这篇文章是「模块化」系列的最后一篇文章,聊一聊前端模块加载器。上一篇文章《模块化(二)》中提到的实现 AMD 规范的 RequireJS 就是一种比较常用的模块加载器,除此之外比较常用的有 Browserify 和 Webpack,接下来逐一介绍。
Browserify
npm 的模块非常丰富,但是其模块符合 CommonJS 规范,对浏览器不友好。Browserify 就是为了解决这个问题而生,递归分析应用中 require()
的调用顺序,将所有依赖的模块打包成一个 js 文件,浏览器通过一个 标签即可加载。
接下来再以 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文件
Input Number:
Webpack
Webpack 是一种功能强大的模块加载器,与 Browserify 相比,可以灵活按配置将 js 打成多个包按需加载,提高首次访问页面的速读,同时也支持 css 、图片等静态文件的管理。
同样,以 webpack 实现 incrememnt 功能。
前提:node 和 npm 环境准备就绪。
安装 webpack
npm install webpack -g
示例中还演示了加载 css 的功能,需要在 www 目录安装 css-loader
和 style-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 之旅 - 模块化(三) |