webpack 之 開發(fā)

選擇一個(gè)開發(fā)工具:
當(dāng)我們每次要編譯代碼時(shí),手動(dòng)運(yùn)行 npm run build 就會(huì)顯得很麻煩。

webpack 中有幾個(gè)不同的選項(xiàng),可以幫助我們?cè)诖a發(fā)生變化后自動(dòng)編譯代碼:

  1. webpack's Watch Mode
  2. webpack-dev-server
  3. 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)特性,例如 importexport

新的 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)可以通過 importexport 語法,找出那些需要?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è)置了 entryoutput 配置,并且在其中引入這兩個(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() 很容易地包含 devprod 中的常見配置。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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容