×

后端程序员的 JavaScript 之旅 - 模块化(三)

96
李少鹏
2016.02.20 11:04* 字数 783
模块化

这篇文章是「模块化」系列的最后一篇文章,聊一聊前端模块加载器。上一篇文章《模块化(二)》中提到的实现 AMD 规范的 RequireJS 就是一种比较常用的模块加载器,除此之外比较常用的有 Browserify 和 Webpack,接下来逐一介绍。

Browserify

npm 的模块非常丰富,但是其模块符合 CommonJS 规范,对浏览器不友好。Browserify 就是为了解决这个问题而生,递归分析应用中 require() 的调用顺序,将所有依赖的模块打包成一个 js 文件,浏览器通过一个 <script> 标签即可加载。
接下来再以 browserify 实现前两篇文章中的示例。

前提:node 和 npm 环境准备就绪,jQuery 已安装。

安装 browserify

npm install -g browserify

www/scripts 目录

math.js

exports.add = function(x, y) {
    return x + y;
};

increment.js

var math = require('./math');
exports.increment = function(val) {
    return math.add(val, 1);
}

mian.js

var $ = require('jquery');
var inc = require('./increment').increment;

$(function() {
    $(':button').click(function() {
        var val = parseInt($('#val').val());
        var res = inc(isNaN(val) ? 0 : val);
        $('#val').val(res);     
    })
});

browserify 打包

在 www 目录下,使用 browserify 打包

browserify ./scripts/main.js -o bundle.js

index.html

www目录下的index.html文件

<!doctype html>
<html>
    <head>
    </head>
    <body>
        <div>
        Input Number: <input type="text" id="val">
        <input type="button" value="Plus One">
        </div>
        <script src="./bundle.js"></script>
    </body>
</html>

Webpack

Webpack 是一种功能强大的模块加载器,与 Browserify 相比,可以灵活按配置将 js 打成多个包按需加载,提高首次访问页面的速读,同时也支持 css 、图片等静态文件的管理。

同样,以 webpack 实现 incrememnt 功能。

前提:node 和 npm 环境准备就绪。

安装 webpack

npm install webpack -g

示例中还演示了加载 css 的功能,需要在 www 目录安装 css-loaderstyle-loader,不带 -g 参数。

npm install css-loader style-loader

www/styles 目录

style.css

body {
    background: #98887B;
}

www/scripts 目录

math.js 和 increment.js 同 Browserify,lib子目录有 jquery-2.2.0.js 文件。
main.js 文件略微不同,还加载了 css 文件。

require('../styles/style.css');

var $ = require('./lib/jquery-2.2.0');
var inc = require('./increment').increment;

$(function() {
    $(':button').click(function() {
        var val = parseInt($('#val').val());
        var res = inc(isNaN(val) ? 0 : val);
        $('#val').val(res); 
    })
});

www 目录

www 目录增加 webpack 配置文件 webpack.config.js

module.exports = {
    entry: "./scripts/main.js",
    output: {
        path: __dirname,
        filename: "bundle.js"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" }
        ]
    }
};

webpack 打包

在 www 目录下,使用 webpack 打包,由于存在配置文件,直接运行命令 webpack 即可

webpack

index.html

www 目录下的 index.html 同 Browserify 中的例子,由于加载了 css 底色会有不同。

模块加载器比较

这个表格是 Webpack 官网上所列的 RequireJS、Browserify、Webpack 支持特性的比较:

Feature webpack/webpack jrburke/requirejs substack/node-browserify
CommonJs require yes only wrapping in define yes
CommonJs require.resolve yes no no
CommonJs exports yes only wrapping in define yes
AMD define yes yes deamdify
AMD require yes yes no
AMD require loads on demand yes with manual configuration no
ES2015 import/export no no no
Generate a single bundle yes yes♦ yes
Load each file separate no yes no
Multiple bundles yes with manual configuration with manual configuration
Additional chunks are loaded on demand yes yes no
Multi pages build with common bundle with manual configuration yes
Concat in require require("./fi" + "le") yes no♦ no
Indirect require var r = require; r("./file") yes no♦ no
Expressions in require (guided) require("./templates/" + template) yes (all files matching included) no♦ no
Expressions in require (free) require(moduleName) with manual configuration no♦ no
Requirable files file system web file system
Plugins yes yes yes
Preprocessing loaders, transforms loaders transforms
Watch mode yes not required yes
Debugging support SourceUrl, SourceMaps not required SourceMaps
Node.js built-in libs require("path") yes no yes
Other Node.js stuff process, __dir/filename, global - process, __dir/filename, global
Replacement for browser web_modules, .web.js, package.json field, alias config option alias option package.json field, alias option
Minimizing uglify uglify, closure compiler uglifyify
Mangle path names yes no partial
Runtime overhead 243B + 20B per module + 4B per dependency 14.7kB + 0B per module + (3B + X) per dependency 415B + 25B per module + (6B + 2X) per dependency
Dependencies 19MB / 127 packages 11MB / 118 packages 1.2MB / 1 package

♦ in production mode (opposite in development mode)
X is the length of the path string

HACKHAT 也有一个第三方的模块加载器的对比文章 Module loader comparision: Webpack vs Require.js vs Browserify 可供参考。

结论

「后端程序员的 JavaScript 之旅 - 模块化」系列文章介绍了:模块模式,解决在天生模块化缺失的情况下如何根据 JS 自身的语言特性构建模块化的基本方法;
流行的模块化规范 CommonJS 、AMD 和 ES 6 模块标准等,了解到模块化规范对生态圈的重要性;介绍了生态圈中常用的三种常用的模块加载器及其特点。

后端程序员的 JavaScript 之旅 - 模块化系列文章:
后端程序员的 JavaScript 之旅 - 模块化(一) | 简书
后端程序员的 JavaScript 之旅 - 模块化(二) | 简书
后端程序员的 JavaScript 之旅 - 模块化(三) | 简书

李少鹏的网络日志
Web note ad 1