前端工程师手册

源码构建

jQuery的代码是分模块书写的,最后通过一系列build的过程,才生产我们日常使用的版本。熟悉它的构建过程,有利于我们了解个各模块,以及组织的方式,便于我们后续自己开发。

前期准备

通过git更新下jquery的最新源码,进入对应的目录,执行npm install,确保本地安装过grunt,如果没有,执行npm install -g grunt-cli

jQuery组织方式

jQuery的源码是按照AMD的模式组织的,在构建的时候,去掉define结构,形成一个单独的文件。

构建步骤

执行grunt,默认会执行一系列任务,我们可以通过终端查看到其中的具体任务,我在这里再分条列一下:

  • Running "build:all:*" (build) task
  • Running "jsonlint:pkg" (jsonlint) task
  • Running "jsonlint:bower" (jsonlint) task
  • Running "jshint:all" (jshint) task
  • Running "jshint:dist" (jshint) task
  • Running "jscs:src" (jscs) task
  • Running "jscs:gruntfile" (jscs) task
  • Running "jscs:test" (jscs) task
  • Running "jscs:release" (jscs) task
  • Running "jscs:tasks" (jscs) task
  • Running "uglify:all" (uglify) task
  • Running "remove_map_comment" task
  • Running "dist:*" (dist) task
  • Running "node_smoke_test" task
  • Running "compare_size:files" (compare_size) task

可以看到,构建任务确实不少。下面我们就依次来分析一下具体的任务负责了什么。具体的任务配置,我们需要查看gruntfile.js文件。

gruntfile.js文件

这是构建工具的入口,我们在这个文件的最后部分可以看到:

// Load grunt tasks from NPM packages
require( "load-grunt-tasks" )( grunt );

// Integrate jQuery specific tasks
grunt.loadTasks( "build/tasks" );

grunt.registerTask( "lint", [ "jsonlint", "jshint", "jscs" ] );

grunt.registerTask( "test_fast", [ "node_smoke_test" ] );

grunt.registerTask( "test", [ "test_fast", "promises-aplus-tests" ] );

// Short list as a high frequency watch task
grunt.registerTask( "dev", [ "build:*:*", "lint", "uglify", "remove_map_comment", "dist:*" ] );

grunt.registerTask( "default", [ "dev", "test_fast", "compare_size" ] );

这里注册了grunt的插件,以及默认的构建任务,比如我们将要看到的grunt其实,就是grunt default,是一系列任务的组合。这里还加载了build/tasks下的构建任务。

Running “build:all:*” (build) task

这个就是构建出开发版本的过程,我们先来看一下默认的build/task/build.js文件。这个文件确切定义了build任务,在文件的尾部,我们可以看到:

// Trace dependencies and concatenate files
requirejs.optimize( config, function( response ) {
    grunt.verbose.writeln( response );
    grunt.log.ok( "File '" + name + "' created." );
    done();
}, function( err ) {
    done( err );
});

这里通过requireJS的压缩,达到build的效果。主要的参数是通过config传入的,查看这个参数,我们会发现一个onBuildWrite选项,这会在构建的时候,帮我们执行去除define的效果,达到合并文件的目的。我们在convert中打印一下参数,可以查看到jQuery到底合并了哪些模块以及其对应的路径,默认情况下是依赖config下定义的src+name文件形成依赖关系:

====convert: var/arr /Users/leohxj/workspaces/github/jquery/src/var/arr.js
====convert: var/document /Users/leohxj/workspaces/github/jquery/src/var/document.js
====convert: var/slice /Users/leohxj/workspaces/github/jquery/src/var/slice.js
====convert: var/concat /Users/leohxj/workspaces/github/jquery/src/var/concat.js
====convert: var/push /Users/leohxj/workspaces/github/jquery/src/var/push.js
====convert: var/indexOf /Users/leohxj/workspaces/github/jquery/src/var/indexOf.js
====convert: var/class2type /Users/leohxj/workspaces/github/jquery/src/var/class2type.js
====convert: var/toString /Users/leohxj/workspaces/github/jquery/src/var/toString.js
====convert: var/hasOwn /Users/leohxj/workspaces/github/jquery/src/var/hasOwn.js
====convert: var/support /Users/leohxj/workspaces/github/jquery/src/var/support.js
====convert: core /Users/leohxj/workspaces/github/jquery/src/core.js
====convert: sizzle /Users/leohxj/workspaces/github/jquery/external/sizzle/dist/sizzle.js
====convert: selector-sizzle /Users/leohxj/workspaces/github/jquery/src/selector-sizzle.js
====convert: selector /Users/leohxj/workspaces/github/jquery/src/selector.js
====convert: traversing/var/rneedsContext /Users/leohxj/workspaces/github/jquery/src/traversing/var/rneedsContext.js
====convert: core/var/rsingleTag /Users/leohxj/workspaces/github/jquery/src/core/var/rsingleTag.js
====convert: traversing/findFilter /Users/leohxj/workspaces/github/jquery/src/traversing/findFilter.js
====convert: core/init /Users/leohxj/workspaces/github/jquery/src/core/init.js
====convert: traversing /Users/leohxj/workspaces/github/jquery/src/traversing.js
====convert: var/rnotwhite /Users/leohxj/workspaces/github/jquery/src/var/rnotwhite.js
====convert: callbacks /Users/leohxj/workspaces/github/jquery/src/callbacks.js
====convert: deferred /Users/leohxj/workspaces/github/jquery/src/deferred.js
====convert: core/ready /Users/leohxj/workspaces/github/jquery/src/core/ready.js
====convert: core/access /Users/leohxj/workspaces/github/jquery/src/core/access.js
====convert: data/accepts /Users/leohxj/workspaces/github/jquery/src/data/accepts.js
====convert: data/Data /Users/leohxj/workspaces/github/jquery/src/data/Data.js
====convert: data/var/dataPriv /Users/leohxj/workspaces/github/jquery/src/data/var/dataPriv.js
====convert: data/var/dataUser /Users/leohxj/workspaces/github/jquery/src/data/var/dataUser.js
====convert: data /Users/leohxj/workspaces/github/jquery/src/data.js
====convert: queue /Users/leohxj/workspaces/github/jquery/src/queue.js
====convert: var/pnum /Users/leohxj/workspaces/github/jquery/src/var/pnum.js
====convert: var/rcssNum /Users/leohxj/workspaces/github/jquery/src/var/rcssNum.js
====convert: css/var/cssExpand /Users/leohxj/workspaces/github/jquery/src/css/var/cssExpand.js
====convert: css/var/isHidden /Users/leohxj/workspaces/github/jquery/src/css/var/isHidden.js
====convert: css/adjustCSS /Users/leohxj/workspaces/github/jquery/src/css/adjustCSS.js
====convert: manipulation/var/rcheckableType /Users/leohxj/workspaces/github/jquery/src/manipulation/var/rcheckableType.js
====convert: manipulation/support /Users/leohxj/workspaces/github/jquery/src/manipulation/support.js
====convert: event/support /Users/leohxj/workspaces/github/jquery/src/event/support.js
====convert: event /Users/leohxj/workspaces/github/jquery/src/event.js
====convert: manipulation /Users/leohxj/workspaces/github/jquery/src/manipulation.js
====convert: css/defaultDisplay /Users/leohxj/workspaces/github/jquery/src/css/defaultDisplay.js
====convert: css/var/rmargin /Users/leohxj/workspaces/github/jquery/src/css/var/rmargin.js
====convert: css/var/rnumnonpx /Users/leohxj/workspaces/github/jquery/src/css/var/rnumnonpx.js
====convert: css/var/getStyles /Users/leohxj/workspaces/github/jquery/src/css/var/getStyles.js
====convert: var/documentElement /Users/leohxj/workspaces/github/jquery/src/var/documentElement.js
====convert: css/support /Users/leohxj/workspaces/github/jquery/src/css/support.js
====convert: css/curCSS /Users/leohxj/workspaces/github/jquery/src/css/curCSS.js
====convert: css/addGetHookIf /Users/leohxj/workspaces/github/jquery/src/css/addGetHookIf.js
====convert: css/swap /Users/leohxj/workspaces/github/jquery/src/css/swap.js
====convert: css /Users/leohxj/workspaces/github/jquery/src/css.js
====convert: effects/Tween /Users/leohxj/workspaces/github/jquery/src/effects/Tween.js
====convert: effects /Users/leohxj/workspaces/github/jquery/src/effects.js
====convert: queue/delay /Users/leohxj/workspaces/github/jquery/src/queue/delay.js
====convert: attributes/support /Users/leohxj/workspaces/github/jquery/src/attributes/support.js
====convert: attributes/attr /Users/leohxj/workspaces/github/jquery/src/attributes/attr.js
====convert: attributes/prop /Users/leohxj/workspaces/github/jquery/src/attributes/prop.js
====convert: attributes/classes /Users/leohxj/workspaces/github/jquery/src/attributes/classes.js
====convert: attributes/val /Users/leohxj/workspaces/github/jquery/src/attributes/val.js
====convert: attributes /Users/leohxj/workspaces/github/jquery/src/attributes.js
====convert: event/alias /Users/leohxj/workspaces/github/jquery/src/event/alias.js
====convert: ajax/var/location /Users/leohxj/workspaces/github/jquery/src/ajax/var/location.js
====convert: ajax/var/nonce /Users/leohxj/workspaces/github/jquery/src/ajax/var/nonce.js
====convert: ajax/var/rquery /Users/leohxj/workspaces/github/jquery/src/ajax/var/rquery.js
====convert: ajax/parseJSON /Users/leohxj/workspaces/github/jquery/src/ajax/parseJSON.js
====convert: ajax/parseXML /Users/leohxj/workspaces/github/jquery/src/ajax/parseXML.js
====convert: ajax /Users/leohxj/workspaces/github/jquery/src/ajax.js
====convert: manipulation/_evalUrl /Users/leohxj/workspaces/github/jquery/src/manipulation/_evalUrl.js
====convert: wrap /Users/leohxj/workspaces/github/jquery/src/wrap.js
====convert: css/hiddenVisibleSelectors /Users/leohxj/workspaces/github/jquery/src/css/hiddenVisibleSelectors.js
====convert: serialize /Users/leohxj/workspaces/github/jquery/src/serialize.js
====convert: ajax/xhr /Users/leohxj/workspaces/github/jquery/src/ajax/xhr.js
====convert: ajax/script /Users/leohxj/workspaces/github/jquery/src/ajax/script.js
====convert: ajax/jsonp /Users/leohxj/workspaces/github/jquery/src/ajax/jsonp.js
====convert: core/support /Users/leohxj/workspaces/github/jquery/src/core/support.js
====convert: core/parseHTML /Users/leohxj/workspaces/github/jquery/src/core/parseHTML.js
====convert: ajax/load /Users/leohxj/workspaces/github/jquery/src/ajax/load.js
====convert: event/ajax /Users/leohxj/workspaces/github/jquery/src/event/ajax.js
====convert: effects/animatedSelector /Users/leohxj/workspaces/github/jquery/src/effects/animatedSelector.js
====convert: offset /Users/leohxj/workspaces/github/jquery/src/offset.js
====convert: dimensions /Users/leohxj/workspaces/github/jquery/src/dimensions.js
====convert: deprecated /Users/leohxj/workspaces/github/jquery/src/deprecated.js
====convert: exports/amd /Users/leohxj/workspaces/github/jquery/src/exports/amd.js
====convert: jquery /Users/leohxj/workspaces/github/jquery/src/jquery.js

我们也可以指定构建模块,比如使用grunt build:*:core:selector,来确定构建coreselector模块:

====convert: jquery /Users/leohxj/workspaces/github/jquery/src/jquery.js
====convert: var/arr /Users/leohxj/workspaces/github/jquery/src/var/arr.js
====convert: var/document /Users/leohxj/workspaces/github/jquery/src/var/document.js
====convert: var/slice /Users/leohxj/workspaces/github/jquery/src/var/slice.js
====convert: var/concat /Users/leohxj/workspaces/github/jquery/src/var/concat.js
====convert: var/push /Users/leohxj/workspaces/github/jquery/src/var/push.js
====convert: var/indexOf /Users/leohxj/workspaces/github/jquery/src/var/indexOf.js
====convert: var/class2type /Users/leohxj/workspaces/github/jquery/src/var/class2type.js
====convert: var/toString /Users/leohxj/workspaces/github/jquery/src/var/toString.js
====convert: var/hasOwn /Users/leohxj/workspaces/github/jquery/src/var/hasOwn.js
====convert: var/support /Users/leohxj/workspaces/github/jquery/src/var/support.js
====convert: core /Users/leohxj/workspaces/github/jquery/src/core.js
====convert: sizzle /Users/leohxj/workspaces/github/jquery/external/sizzle/dist/sizzle.js
====convert: selector-sizzle /Users/leohxj/workspaces/github/jquery/src/selector-sizzle.js
====convert: selector /Users/leohxj/workspaces/github/jquery/src/selector.js

参考资料