APPRTC分析系列0--grunt過程分析0

一、grunt工具分析

apprtc的編譯步驟爲:
npm install
grunt build

網上查閱資料,發現grunt爲一種構建項目的方式,其基本介紹爲
http://www.gruntjs.net/getting-started
通過該介紹可以發現,grunt是通過npm安裝和管理的,而npm又是node.js的包管理器。

在編譯apprtc之前,需要安裝的grunt-cli爲Grunt命令行。執行的npm install -g grunt-cli爲將命令行安裝到全局環境中,其中的-g參數代表global全局的意思,這是npm install的參數。
安裝完grunt-cli後,grunt命令就被加入到系統路徑中了。

二、grunt過程分析

1、npm install
在apprtc目錄下面執行npm install時,npm包管理器讀取apprtc目錄下面的package.json中的內容,並安裝必要的包。
如,apprtc目錄下的package.json內容如下

{
  "name": "apprtc",
  "version": "1.0.0",
  "description": "Project checking for AppRTC repo",
  "license": "BSD-3-Clause",
  "main": "Gruntfile.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/webrtc/apprtc.git"
  },
  "scripts": {
    "test": "grunt --verbose"
  },
  "devDependencies": {
    "grunt": "^0.4.0",
    "grunt-cli": ">=0.1.9",
    "grunt-closurecompiler": ">=0.0.21",
    "grunt-contrib-compress": "^0.13.0",
    "grunt-contrib-csslint": ">=0.3.1",
    "grunt-contrib-jshint": ">=0.10.0",
    "grunt-htmlhint": ">=0.9.12",
    "grunt-jinja": ">=0.3.0",
    "grunt-jscs": ">=0.8.1",
    "grunt-jstestdriver-phantomjs": ">=0.0.7",
    "grunt-shell": "^1.1.1",
    "socket.io-client": "^1.2.0",
    "webrtc-adapter": "^1.0.6"
  }
}

猜測npm install會安裝package.json中的devDependencies對應的值,即各種必要的依賴,包括一些grunt插件。這些插件將會在後面執行grunt命令時使用。

npm install執行完之後,會在apprtc目錄下面生成node_modules目錄,該目錄下面是npm intall安裝的node.js包。查看node_modules目錄下內容,發現和devDependencies值列表相同。證明剛纔的npm install命令是執行安裝package.json中devDependencies的包列表。

也可以通過在apprtc下面,執行npm list命令查看該目錄下安裝的nodejs包的結構。

2、grunt build
apprtc目錄中存在一個Gruntfile.js的文件。裏面涉及到grunt命令時的一系列東東。其介紹也在http://www.gruntjs.net/getting-started中。有興趣的可以自己看一下。我們依據上面鏈接提供的知識來分析一下grunt build到底執行了什麼。

看一下文件內容中的

 grunt.registerTask('default', ['csslint', 'htmlhint', 'jscs', 'jshint',
                                 'runPythonTests', 'shell:genJsEnums', 'jstests']);        
  grunt.registerTask('travis', ['shell:getPythonTestDeps',
                                'shell:installPythonTestDepsOnLinux',
                                'default']);
  grunt.registerTask('runPythonTests', ['shell:buildAppEnginePackageWithTests',
                                        'shell:getPythonTestDeps',
                                        'shell:runPythonTests',
                                        'shell:removePythonTestsFromOutAppEngineDir']);
  grunt.registerTask('jstests', ['shell:genJsEnums', 'closurecompiler:debug', 'grunt-chrome-build', 'jstdPhantom']);
  // buildAppEnginePackage must be done before closurecompiler since buildAppEnginePackage resets out/app_engine.

  grunt.registerTask('build', [`'shell:buildAppEnginePackage', 'shell:genJsEnums', 'closurecompiler:debug', 'grunt-chrome-build'`]);

grunt.registerTask是一個grunt的api,其原型爲grunt.registerTask(taskname,tasklist).其中tasklist必須是一個任務數組。其中的taskname爲一個任務別名。在命令行執行grunt taskname時,會依次執行tasklist中的任務。

實際上grunt build是在執行Gruntfile.js文件中的build任務。而我們找一下,發現build任務是一個任務列表的別名。
按照文件規定,其會依次執行

'shell:buildAppEnginePackage', 
'shell:genJsEnums', 
'closurecompiler:debug', 
'grunt-chrome-build'

這4個任務。
以shell:buildAppEnginePackage任務爲例。
其中的shell爲任務名,而buildAppEnginePackage爲shell任務下的一個目標名。

在文件中尋找一下,發現shell任務屬性如下:

 shell: {
      getPythonTestDeps: {
        command: 'python build/get_python_test_deps.py'
      },
      installPythonTestDepsOnLinux: {
        command: 'python build/install_webtest_on_linux.py webtest-master/'
      },
      runPythonTests: {
        command: ['python', 'build/run_python_tests.py', 'google_appengine/',
                  out_app_engine_dir, 'webtest-master/'].join(' ')
      },
      buildAppEnginePackage: {
        command: ['python', './build/build_app_engine_package.py', 'src',
                  out_app_engine_dir].join(' ')
      },
      buildAppEnginePackageWithTests: {
        command: ['python', './build/build_app_engine_package.py', 'src',
                  out_app_engine_dir, '--include-tests'].join(' ')
      },
      removePythonTestsFromOutAppEngineDir: {
        command: ['python', './build/remove_python_tests.py',
                  out_app_engine_dir].join(' ')
      },
      genJsEnums: {
        command: ['python', './build/gen_js_enums.py', 'src',
                  'src/web_app/js'].join(' ')
      },
    },

從以上內容可以看到,buildAppEnginePackage的實質是執行

'python', './build/build_app_engine_package.py', 'src',
                  out_app_engine_dir

其中的out_app_engine_dir在文件開頭定義,內容如下:

/* globals module */
var out_app_engine_dir = 'out/app_engine';

所以,buildAppEnginePackage應該是要執行

'python', './build/build_app_engine_package.py', 'src','out/app_engine'

更具體的含義就需要查看對應的python文件了。

類似的
‘shell:genJsEnums’,對應

'python', './build/gen_js_enums.py', 'src','src/web_app/js'

‘closurecompiler:debug’對應:

closurecompiler: {
      debug: {
        files: {               文件對象格式,一個目標可以多個src-dest對。
          // Destination: [source files]
          'out/app_engine/js/apprtc.debug.js': [       //其中out/app_engine/js/apprtc.debug.js爲dest文件,屬性名;[]爲src文件
            'node_modules/webrtc-adapter/out/adapter.js',
            'src/web_app/js/analytics.js',
            'src/web_app/js/enums.js',
            'src/web_app/js/adapter.js',
            'src/web_app/js/appcontroller.js',
            'src/web_app/js/call.js',
            'src/web_app/js/constants.js',
            'src/web_app/js/infobox.js',
            'src/web_app/js/peerconnectionclient.js',
            'src/web_app/js/remotewebsocket.js',
            'src/web_app/js/roomselection.js',
            'src/web_app/js/sdputils.js',
            'src/web_app/js/signalingchannel.js',
            'src/web_app/js/stats.js',
            'src/web_app/js/storage.js',
            'src/web_app/js/util.js',
            'src/web_app/js/windowport.js',
          ]
        },
        options: {
          'compilation_level': 'WHITESPACE_ONLY',
          'language_in': 'ECMASCRIPT5',
          'formatting': 'PRETTY_PRINT'
        },
      },

分析一下:
closurecompiler:debug的會從如下一堆文件

'node_modules/webrtc-adapter/out/adapter.js',
            'src/web_app/js/analytics.js',
            'src/web_app/js/enums.js',
            'src/web_app/js/adapter.js',
            'src/web_app/js/appcontroller.js',
            'src/web_app/js/call.js',
            'src/web_app/js/constants.js',
            'src/web_app/js/infobox.js',
            'src/web_app/js/peerconnectionclient.js',
            'src/web_app/js/remotewebsocket.js',
            'src/web_app/js/roomselection.js',
            'src/web_app/js/sdputils.js',
            'src/web_app/js/signalingchannel.js',
            'src/web_app/js/stats.js',
            'src/web_app/js/storage.js',
            'src/web_app/js/util.js',
            'src/web_app/js/windowport.js',

生成out/app_engine/js/apprtc.debug.js文件
生成過程中,採用options中的屬性,其中的具體含義沒有找到確切的答案。

‘grunt-chrome-build’對應

'grunt-chrome-build' : {
      apprtc: {
        options: {
          buildDir: 'out/chrome_app',
          zipFile: 'out/chrome_app/apprtc.zip',
          // If values for chromeBinary and keyFile are not provided, the packaging
          // step will be skipped.
          // chromeBinary should be set to the Chrome executable on your system.
          chromeBinary: null,
          // keyFile should be set to the key you want to use to create the crx package
          keyFile: null,
          appwindowHtmlSrc: 'src/web_app/html/index_template.html',
          appwindowHtmlDest: 'out/chrome_app/appwindow.html'
        },
        files: [       //文件數組格式,多個src-dest文件映像,同時支持每個src-dest有各自的屬性 files:[]爲文件數組格式,files:{}爲文件對象格式,區別在於是否允許不同的src-dest有不同的屬性
          {
            expand: true,                      //處理大量的單一文件時,用來動態的構建文件列表。expand 爲true時
            cwd: 'src/web_app/chrome_app',     //爲之後src文件匹配時,都是相對此處的路徑
            src: [
              'manifest.json'                  //應該src文件就是src/web_app/chrome_app/manifest.json
            ],
            dest: 'out/chrome_app/'            //目標文件路徑前綴
          },
          {
          //expand屬性爲true時,後面的src/dest的路徑都是相對cwd路徑而言的
            expand: true, 
            cwd: out_app_engine_dir,
            src: [
            //通配符篩選文件,**可以表示文件路徑,*表示任意數目字符,但不能代替‘/’
              '**/*.js',
              '**/*.css',
              '**/images/apprtc*.png',
              '!**/*.pem'
            ],
            dest: 'out/chrome_app/'
          },
          {
            expand: true,
            cwd: 'src/web_app',
            src: [                   //文件操作中的簡潔模式,一個src-dest對。源文件爲src值,目標文件爲dest值,都是相對cwd值的路徑,即src第一個文件爲src/web_app/js/background.js
              'js/background.js',
              'js/appwindow.js',
              '!**/*.pem'
            ],
            dest: 'out/chrome_app/'
          }
        ],
      }
    },

具體執行應該是執行這4個任務。這4個任務的更具體的含義,之後有時間來分析一下。

本人也是邊學習新知識邊分析apprtc.歡迎指正!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章