選擇一個(gè)開發(fā)工具:
當(dāng)我們每次要編譯代碼時(shí),手動(dòng)運(yùn)行 npm run build 就會(huì)顯得很麻煩。
webpack 中有幾個(gè)不同的選項(xiàng),可以幫助我們?cè)诖a發(fā)生變化后自動(dòng)編譯代碼:
- webpack's Watch Mode
- webpack-dev-server
- webpack-dev-middleware
這里重點(diǎn)整理一下 webpack-dev-server
使用觀察模式 和 webpack-dev-server
我們可以指示 webpack "watch" 依賴圖中的所有文件以進(jìn)行更改。如果其中一個(gè)文件被更新,代碼將被重新編譯,所以不必手動(dòng)運(yùn)行整個(gè)構(gòu)建
添加用于啟動(dòng) webpack 的觀察模式 和 直接運(yùn)行開發(fā)服務(wù)器(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", //打開實(shí)時(shí)重新加載服務(wù)器
"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"
}
}
命令行運(yùn)行 npm run watch,就可以看到 webpack 編譯代碼,然而卻不會(huì)退出命令行(script 腳本還在觀察文件)。
修改保存文件并檢查終端窗口。應(yīng)該可以看到 webpack 自動(dòng)重新編譯修改后的模塊。
觀察模式唯一的缺點(diǎn)是:為了看到修改后的實(shí)際效果,需要刷新瀏覽器。這個(gè)時(shí)候 webpack-dev-server 恰好可以實(shí)現(xiàn)我們想要的功能。
npm install --save-dev webpack-dev-server
修改配置文件,告訴開發(fā)服務(wù)器(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 下建立服務(wù),將 dist 目錄下的文件,作為可訪問文件。
npm script 腳本在最上面已經(jīng)添加完畢,可以直接運(yùn)行開發(fā)服務(wù)器(dev server)
我們可以在命令行中運(yùn)行 npm start,就會(huì)看到瀏覽器自動(dòng)加載頁面。如果現(xiàn)在修改和保存任意源文件,web 服務(wù)器就會(huì)自動(dòng)重新加載編譯后的代碼。
Tree Shaking
tree shaking 用于描述移除上下文中的未引用代碼(dead-code)。它依賴于 ES2015 模塊系統(tǒng)中的靜態(tài)結(jié)構(gòu)特性,例如 import 和 export。
新的 webpack4 正式版本,拓展了這個(gè)檢測(cè)能力,通過 package.json 的 "sideEffects" 屬性作為標(biāo)記,向 compiler 提供提示,表明項(xiàng)目中的哪些文件是 "pure(純的 ES2015 模塊)",由此可以安全地刪除文件中未使用的部分。
首先在模塊中 export 方法
當(dāng)你從一個(gè)模塊中 import 導(dǎo)入一部分方法,另一部分未導(dǎo)入的方法就是所謂的"未引用代碼(dead code)",我們應(yīng)該刪除未被引用的 export。當(dāng)我們運(yùn)行 npm script npm run build 時(shí),檢查輸出 bundle:
未導(dǎo)入方法上面會(huì)有注釋 unused harmony export square,但是它們?nèi)匀槐话?bundle 中。
將文件標(biāo)記為無副作用(side-effect-free)
在一個(gè)純粹的 ESM 模塊世界中,識(shí)別出哪些文件有副作用很簡(jiǎn)單。然而,我們的項(xiàng)目無法達(dá)到這種純度,所以,此時(shí)有必要向 webpack 的 compiler 提供提示哪些代碼是“純粹部分”。
這種方式是通過 package.json 的 "sideEffects" 屬性來實(shí)現(xiàn)的
{
"name": "your-project",
"sideEffects": false
}
如同上面提到的,如果所有代碼都不包含副作用,我們就可以簡(jiǎn)單地將該屬性標(biāo)記為 false,來告知 webpack,它可以安全地刪除未用到的 export 導(dǎo)出。
「副作用」的定義是,在導(dǎo)入時(shí)會(huì)執(zhí)行特殊行為的代碼,而不是僅僅暴露一個(gè) export 或多個(gè) export。舉例說明,例如 polyfill,它影響全局作用域,并且通常不提供 export。
如果代碼確實(shí)有一些副作用,可以改為提供一個(gè)數(shù)組:
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}
注意,任何導(dǎo)入的文件都會(huì)受到 tree shaking 的影響。這意味著,如果在項(xiàng)目中使用類似 css-loader 并導(dǎo)入 CSS 文件,則需要將其添加到 side effect 列表中,以免在生產(chǎn)模式中無意中將它刪除:
{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js",
"*.css"
]
}
最后,還可以在 module.rules 配置選項(xiàng) 中設(shè)置 "sideEffects"。
壓縮輸出
過如上方式,我們已經(jīng)可以通過 import 和 export 語法,找出那些需要?jiǎng)h除的“未使用代碼(dead code)”,然而,我們不只是要找出,還需要在 bundle 中刪除它們。為此,我們將使用 -p (production) 這個(gè) webpack 編譯標(biāo)記,來啟用 uglifyjs 壓縮插件。
注意,
--optimize-minimize標(biāo)記也會(huì)在 webpack 內(nèi)部調(diào)用UglifyJsPlugin。
從 webpack4開始,也可以通過 "mode" 配置選項(xiàng)輕松切換到壓縮輸出,只需設(shè)置為 "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標(biāo)記,來使用UglifyJSPlugin。
生產(chǎn)環(huán)境配置
不同環(huán)境下可能使用不同的命令,引入不同的配置
配置
開發(fā)環(huán)境(development)和生產(chǎn)環(huán)境(production)的構(gòu)建目標(biāo)差異很大。在開發(fā)環(huán)境中,我們需要具有強(qiáng)大的、具有實(shí)時(shí)重新加載(live reloading)或熱模塊替換(hot module replacement)能力的 source map 和 localhost server。而在生產(chǎn)環(huán)境中,我們的目標(biāo)則轉(zhuǎn)向于關(guān)注更小的 bundle,更輕量的 source map,以及更優(yōu)化的資源,以改善加載時(shí)間。由于要遵循邏輯分離,我們通常建議為每個(gè)環(huán)境編寫彼此獨(dú)立的 webpack 配置。
雖然以上將生產(chǎn)環(huán)境和開發(fā)環(huán)境做了略微區(qū)分,但是應(yīng)該注意的是,還是會(huì)遵循不重復(fù)原則,保留一個(gè)“通用”配置。為了將這些配置合并在一起,要使用一個(gè) webpack-merge 的工具。通過“通用”配置,我們不必在環(huán)境特定的配置中重復(fù)代碼。
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 中設(shè)置了 entry 和 output 配置,并且在其中引入這兩個(gè)環(huán)境公用的全部插件。在 webpack.dev.js 中為此環(huán)境添加了推薦的 devtool (強(qiáng)大的 source map)和簡(jiǎn)單的 devServer 配置。最后在 webpack.prod.js 中引入了之前在 tree shaking 指南中介紹過的 UglifyJSPlugin。
注意,在環(huán)境特定的配置中使用 merge() 很容易地包含 dev 和 prod 中的常見配置。webpack-merge 工具提供了多種合并(merge)的高級(jí)功能,但是用例中無需用到這些。
NPM Script
根據(jù)上面的新配置,可以將 npm start 定義為開發(fā)環(huán)境腳本,并在其中使用 webpack-dev-server,將 npm run build 定義為生產(chǎn)環(huán)境腳本
我們還可以繼續(xù)添加一些生產(chǎn)環(huán)境配置,詳細(xì)請(qǐng)?jiān)L問 環(huán)境構(gòu)建 | webpack