1. 基础结构搭建
(1) 新建工程并安装webpack
在Terminal中新建工程(详细说明参见webpack实战——(1)安装及命令行)
mkdir webpack-demo
cd webpack-demo
npm init
npm install webpack --save-dev
(2) 工程目录填充
注:以/结尾的都为文件夹。
├─ dist/
├─ node_modules/
├─ src/
│ └── script/
│ └── style/
└─index.html
└─package.json
└─webpack.config.js
- dist: 打包过后的资源
- src: 存放代码源文件,script和style文件夹分别存放脚本文件(js)和样式文件(css或less、sass等)
- index.html: 初始化页面,引入打包后的js,如下:
webpack.config.js: webpack配置文件
<!DOCTYPE HTML> <html> <head> <meta charset="uft-8"> <title>webpack demo</title> </head> <body> <script type="text/javascript" src="bundle.js"></script> </body> </html>
2. webpack配置
(1) API
官网config API:
https://webpack.js.org/configuration
(2) 基本配置
在script文件夹下新建main.js的文件,作为入口。
function hello(){}
编辑webpack.config.js如下:
const path = require('path');
//common.js的模块化输出
module.exports={
entry: './src/script/main.js', //打包入口文件
output:{ //打包后的输出
path: path.resolve(__dirname, 'dist/js'), //输出路径
filename: 'bundle.js' //输出的文件名
}
}
注意!!官方说法如下,output.path必须为绝对路径。所以用了
__dirname
The output directory as an absolute path.
在Termial中运行webpack
,可以看到打包出来的文件了dist->js->bundle.js
(3) 配置文件名称
webpack的配置文件是不是必须要叫webpack.config.js呢?
答案是否定的。webpack的默认配置文件叫webpack.config.js。叫这个名字后,就不需要额外说明,webpack自动识别其为配置文件。
如果配置文件不叫这个名字,可以通过--config
进行指定。如下,指定webpack.dev.config.js为配置文件。
webpack --config webpack.dev.config.js
3. 运行带有参数的webpack
[问题] 在上篇中提到,在命令行中运行webpack可以附加一些参数。那么,在这样的工程下该如何使用呢?
[解答] 配合npm的脚本可以做到。
打开package.json,npm有个叫scripts的属性,如下。可以在其中定义一段脚本。
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.8.1"
}
}
编辑script,增加一个叫webpack的脚本。例如下方代码中定义的参数,可以查看打包过程、打包模块,让打包出来的字是彩色的,以及打包原因。
{
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack --progress --display-modules --colors --display-reasons"
}
}
在Termial中输入如下,便可以执行这个脚本了。
npm run webpack
4. 配置进阶
(1)多个entry
[1] 数组形式
为应对平行的互相依赖的文件,希望打包在一起的情况。
【实战】
在src->script下新建a.js文件。
function a(){}
修改webpack.config.js文件,将entry的值改为一个数组。此时的入口文件为main.js和a.js。
const path = require('path');
module.exports={
entry: ['./src/script/main.js','./src/script/a.js'],
output:{
path: path.resolve(__dirname, 'dist/js'),
filename: 'bundle.js'
}
}
在Terminal中运行npm run webpack
,打包出来了一个文件——bundle.js如下:
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(1);
module.exports = __webpack_require__(2);
/***/ }),
/* 1 */
/***/ (function(module, exports) {
function hello(){}
/***/ }),
/* 2 */
/***/ (function(module, exports) {
function a(){}
/***/ })
/******/ ]);
可以看到0模块就是将两个不相干的入口文件,在生成的文件中require到一起。
[2] 对象形式
key和value的形式,这种方式常见于多页面应用,不同页面有不同的entry。value既可以是一个字符串,也可以是一个数组。
如下,将entry改为一个对象,同时需要修改output.filename。为啥?entry是多个,对应打包出来的文件也是多个。
const path = require('path');
module.exports={
entry: {
main: './src/script/main.js',
a: './src/script/a.js'
},
output:{
path: path.resolve(__dirname, 'dist/js'),
filename: '[name].bundle.js'
}
}
运行npm run webpack
,可以看到在dist->js下打包出来了两个文件,分别是a.bundle.js和main.bundle.js。
(2) output filename
上例中为了实现多entry生成的文件名具有唯一性,使用到了[name]
,在官网中(https://webpack.js.org/configuration/output/#output-filename)还介绍了其他可用的命名。下文中,将对所有的方式进行实践。
[1] entry name
filename: '[name].bundle.js'
同上例,使用入口文件的名称,打包后的文件分别是a.bundle.js
和 main.bundle.js
[2] internal chunk id
filename: '[id].bundle.js'
采用模块id的方式,打包后的文件分别是0.bundle.js
和 1.bundle.js
[3] the unique hash generated for every build
filename: '[name].[hash].bundle.js'
采用入口名称+哈希的方式。打包后的文件分别是a.48a47bbf3cbd6e2e5264.bundle.js
和 main.48a47bbf3cbd6e2e5264.bundle.js
。由下图中可以看到,运行webpack的时候都会生成一个Hash,所以每个文件名中的Hash都是一样的。
[4] hashes based on each chunks’ content
filename: "[name]-[chunkhash].bundle.js"
此处对官网上的例子有所改动,增加了[name]
来知晓是打包的哪个文件。最终得到a-3af0762ff7b4e6ff9f7c.bundle.js
和 main-65ebaccdb6e4a73b7429.bundle.js
。可以看出每个文件的hash是不一样的。这样有什么好处呢?
对main.js进行修改,再重新打包一次。得到的文件为a-3af0762ff7b4e6ff9f7c.bundle.js
和 main-d02880881ec2455f025c.bundle.js
,可以看到没有修改的a.js打包后的hash没有改变,而被修改的main.js打包后的hash改变了。
【小结】使用[chunkhash]
,只有当文件发生改变,Hash才会变化。这有助于对静态资源版本号的管理。比如,在上线时,只用替换被修改过的文件。