选择一个开发工具:
当我们每次要编译代码时,手动运行 npm run build
就会显得很麻烦。
webpack 中有几个不同的选项,可以帮助我们在代码发生变化后自动编译代码:
- webpack's Watch Mode
- webpack-dev-server
- webpack-dev-middleware
这里重点整理一下 webpack-dev-server
使用观察模式 和 webpack-dev-server
我们可以指示 webpack "watch" 依赖图中的所有文件以进行更改。如果其中一个文件被更新,代码将被重新编译,所以不必手动运行整个构建
添加用于启动 webpack 的观察模式 和 直接运行开发服务器(dev server) 的 npm script 脚本
package.json
{
"name": "development",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch", // 添加观察命令
"start": "webpack-dev-server --open", //打开实时重新加载服务器
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"xml-loader": "^1.2.1"
}
}
命令行运行 npm run watch
,就可以看到 webpack 编译代码,然而却不会退出命令行(script 脚本还在观察文件)。
修改保存文件并检查终端窗口。应该可以看到 webpack 自动重新编译修改后的模块。
观察模式唯一的缺点是:为了看到修改后的实际效果,需要刷新浏览器。这个时候 webpack-dev-server
恰好可以实现我们想要的功能。
npm install --save-dev webpack-dev-server
修改配置文件,告诉开发服务器(dev server)在哪里查找文件
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'inline-source-map',
devServer: { // 添加
contentBase: './dist'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
以上配置告知 webpack-dev-server
,在 localhost:8080
下建立服务,将 dist
目录下的文件,作为可访问文件。
npm script 脚本在最上面已经添加完毕,可以直接运行开发服务器(dev server)
我们可以在命令行中运行 npm start
,就会看到浏览器自动加载页面。如果现在修改和保存任意源文件,web 服务器就会自动重新加载编译后的代码。
Tree Shaking
tree shaking 用于描述移除上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import
和 export
。
新的 webpack4 正式版本,拓展了这个检测能力,通过 package.json
的 "sideEffects"
属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯的 ES2015 模块)",由此可以安全地删除文件中未使用的部分。
首先在模块中 export
方法
当你从一个模块中 import
导入一部分方法,另一部分未导入的方法就是所谓的"未引用代码(dead code)",我们应该删除未被引用的 export
。当我们运行 npm script npm run build
时,检查输出 bundle:
未导入方法上面会有注释 unused harmony export square
,但是它们仍然被包含在 bundle 中。
将文件标记为无副作用(side-effect-free)
在一个纯粹的 ESM 模块世界中,识别出哪些文件有副作用很简单。然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。
这种方式是通过 package.json 的 "sideEffects"
属性来实现的
{
"name": "your-project",
"sideEffects": false
}
如同上面提到的,如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack,它可以安全地删除未用到的 export 导出。
「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
如果代码确实有一些副作用,可以改为提供一个数组:
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}
注意,任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js",
"*.css"
]
}
最后,还可以在 module.rules 配置选项 中设置 "sideEffects"
。
压缩输出
过如上方式,我们已经可以通过 import
和 export
语法,找出那些需要删除的“未使用代码(dead code)”,然而,我们不只是要找出,还需要在 bundle 中删除它们。为此,我们将使用 -p
(production) 这个 webpack 编译标记,来启用 uglifyjs 压缩插件。
注意,
--optimize-minimize
标记也会在 webpack 内部调用UglifyJsPlugin
。
从 webpack4开始,也可以通过 "mode"
配置选项轻松切换到压缩输出,只需设置为 "production"
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: "production"
};
注意,也可以在命令行接口中使用
--optimize-minimize
标记,来使用UglifyJSPlugin
。
生产环境配置
不同环境下可能使用不同的命令,引入不同的配置
配置
开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。
虽然以上将生产环境和开发环境做了略微区分,但是应该注意的是,还是会遵循不重复原则,保留一个“通用”配置。为了将这些配置合并在一起,要使用一个 webpack-merge
的工具。通过“通用”配置,我们不必在环境特定的配置中重复代码。
npm install --save-dev webpack-merge
project
webpack-demo
|——package.json
|——webpack.common.js
|——webpack.dev.js
|——webpack.prod.js
|——/dist
|——/src
|——index.js
|——print.js
|——/node_modules
webpack.common.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
}
});
webpack.prod.js
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
plugins: [
new UglifyJSPlugin()
]
});
在 webpack.common.js
中设置了 entry
和 output
配置,并且在其中引入这两个环境公用的全部插件。在 webpack.dev.js
中为此环境添加了推荐的 devtool
(强大的 source map)和简单的 devServer
配置。最后在 webpack.prod.js
中引入了之前在 tree shaking 指南中介绍过的 UglifyJSPlugin
。
注意,在环境特定的配置中使用 merge()
很容易地包含 dev
和 prod
中的常见配置。webpack-merge
工具提供了多种合并(merge)的高级功能,但是用例中无需用到这些。
NPM Script
根据上面的新配置,可以将 npm start
定义为开发环境脚本,并在其中使用 webpack-dev-server
,将 npm run build
定义为生产环境脚本
我们还可以继续添加一些生产环境配置,详细请访问 环境构建 | webpack
网友评论