js模块打包的概念已经出现一段时间了,RequireJS在09年首次发声,随后webpack以其优异的特性脱颖而出。
什么是模块打包工具
我们见过的多数编程语言,都可以把代码分别保存在多个文件里,然后我们可以导入这些文件以使用它们的功能。但浏览器本身没有这个功能,因此才有了打包工具帮我们实现它,有两种形式:异步加载模块并在加载完毕后运行,以及把所有必要的文件汇总到一个js文件中通过<script>
标签加载。
传统项目中的依赖问题
在不依赖任何自动化、模块化工具的项目中,通常我们的代码是这样的:
index.html
<html>
<head>
<title>传统项目</title>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
</head>
<body>
<script src="app/index.js"></script>
</body>
</html>
app/index.js
function main() {
$('body').html('hello world!');
}
main();
这样管理依赖有一些问题:
如果依赖项丢失,或者包含在错误的顺序中,应用程序将不会运行。(index.js之前若没有引入jQuery就无法运行)如果包含依赖项但没有使用,那么浏览器必须下载很多不必要的代码。(比如加载了一个jQuery,然而代码中只使用了原生js)。
webpack的实现
而在webpack中相同需求会怎么实现呢,首先
npm install --save jquery // 安装jQuery
改变之后的index.js
var $ = require('jquery');
function main() {
$('body').html('hello world!');
}
main();
显示声明了需要jQuery的依赖,这样就不存在隐式依赖的问题(没有全局污染)。
改变后的index.html
<html>
<head>
<title>webpack项目</title>
</head>
<body>
<script src="dist/bundle.js"></script>
</body>
</html>
把所有依赖和脚本打包在了bundle.js中,这样只需要加载一个文件(解决了浏览器并行加载的限制)。使用webpack最简单的方式,就是不考虑配置文件,直接在命令中运行它。webpack命令至少需要一个输入文件和一个输出文件,webpack会读取输入文件,更新其中的依赖,把所有关联文件打包到一个文件,最后把这个文件输出到你指定的输出路径,
现在运行命令将index.js输出为bundle.js
// webpack A B
webpack app/index.js dist/bundle.js
如果没有全局安装webpack,也可以在package.json中修改scripts
"scripts": {
"build": "webpack app/index.js dist/bundle.js"
}
现在,运行npm run build
, 就会生成一个新的bundle.js文件。
拆分
现在如果我们index.js中的”hello world!”字符串需要放到另外一个hello.js中,然后在index.js中引入使用的话,这就涉及到webpack模块拆分的功能。
app/index.js
var $ = require('jquery');
var str = require('./hello.js');
function main() {
$('body').html(str);
}
main();
app/hello.js
var str = 'hello world';
module.export = str;
当然依赖有所改变,我们应该重新运行一次
webpack app/index.js dist/bundle.js
打包
我们会发现上面的命令不利于我们复杂项目配置的使用,对于更复杂的配置,我们可以利用配置文件webpack.config.js来统一管理。
我们可以在demo文件夹下新建webpack.config.js配置文件:
module.exports = {
entry: './app/index.js',
output: {
filename: 'bundle.js',
path: './dist'
}
}
上方配置中的entry就是我们的入口文件,可以有多个入口文件,而output即为webpack打包的输入对象,filename为输出文件名,path为输出路径。
这里我们是通过配置文件配置,所以要用config命令
webpack --config webpack.config.js
当然你也可以直接运行简化的命令:
webpack
webapck会自动去寻找当前目录下的webpack.config.js文件。
压缩
上一步我们利用webpack命令将多个多件打包到了一个bundle.js的文件中,但是并未进行压缩,你可以打开bundle.js进行查看。
而如果我们需要对打包后的代码进一步压缩处理,我们可以运行命令:
webpack -p
-p的记忆方法是压缩(press).
进一步压缩优化
上方我们通过webpack的压缩命令将文件打包并压缩了,但是对于webpack -p压缩后的文件来说其实还有压缩的余地。如果你使用的是webpack1.0,那么你可以在配置文件webpack.config.js中添加plugins配置项,并且加入如下插件:
var webpack = require('webpack');
module.exports = {
...
plugins:[
// 去除代码块内的告警语句
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
// 优先考虑使用最多的模块,并为它们分配最小的ID
new webpack.optimize.OccurenceOrderPlugin()
]
...
}
而本示例中使用的是webpack2.0版本,在2.0中UglifyJsPlugin的compress选项默认为false,并且OccurrenceOrderPlugin默认启用,所以无需进行配置。
不使用webpack的场景
较大用户量的webapp比如qq空间,所有js文件相当于永久缓存,即没有修改就缓存在客户端。因为这些js文件较大,打包成一个文件之后文件体积太大。而qq空间的访问量大,每次更新都要更改打包文件,用户体验较差,所以qq空间没有使用这样的打包技术