在webpack中這樣分離環境和程式碼就好啦
前面的文章中,webpack.config.js 中包含本地除錯和線上釋出的所有配置,編譯後的 bundle.js 包含所有的程式碼。
當專案變大、程式碼量變多、配置增加的時候,檔案的可維護性會越來越差,是時候對他們進行分離啦~
環境分離
環境分離主要是區分本地和生產兩種環境,本地除錯需要能實時看到程式碼變化,而生產環境需要編譯成指定的檔案。
可以採用兩種方式
- 開發環境和生產環境分別定義配置檔案,在 package.json 中定義對應的指令
- 開發環境和生產環境共用配置檔案,通過引數來區分環境
配置檔案分離
分別定義用於開發環境的配置檔案 webpack.dev.js 和用於生產編譯的 webpack.prod.js,再分別通過 npm run serve
npm run build
來開啟 devServer 和 編譯操作
// package.json
"scripts": {
"serve": "webpack serve --config ./config/webpack.dev.js",
"build": "webpack --config ./config/webpack.prod.js",
},
引數區分
開發環境和生產環境都使用 webpack.common.js 檔案,通過 package.json 中設定指令增加 --env 引數來區分
"scripts": { "serve2": "webpack serve --config ./config/webpack.common.js --env development", "build2": "webpack --config ./config/webpack.common.js --env production" },
在 webpack.common.js 中 module.exports 定義為函式,就可以接收 env 傳遞的引數
將開發環境和生產環境都需要用到配置抽離出來放到一個物件中,分別使用的配置分抽離到單獨檔案,再通過 webpack-merge
工具來對配置程式碼進行合併。
// webpack.config.js const { merge } = require('webpack-merge'); const devConfig = require('./webpack.dev'); const prodConfig = require('./webpack.prod'); const commonConfig = { ... // 公共要用的配置 } module.exports = function (env) { // 賦值後可在 babel.config.js 中獲取當前環境 process.env.NODE_ENV = env.production ? 'production' : 'development'; const config = env.production ? prodConfig : devConfig; return merge(commonConfig, config); };
這樣公共配置部分就可以統一管理
程式碼分離
所有原始碼都編譯到一個檔案中,會造成編譯檔案過大,一次性載入所有資源,載入速度慢,從效能的角度來思考,希望提升請求速度,以及當資源需要的時候再載入,那這個時候可以根據功能將原始碼編譯成多個檔案。
程式碼分離有三種方式
- 多入口:通過 entry 配置多個入口,手動分離程式碼
- 防止重複:使用 Entry Dependencies 或 splitChunksPlugin 去重和分離
- 動態匯入:通過 import 函式來分離
多入口
// webpack.config.js
// 獲取啟動目錄
const dirname = process.cwd();
const resolveApp = (folder) => path.resolve(dirname, folder);
module.exports = {
entry: {
index: './src/index.js',
main: './src/main.js',
},
output: {
filename: 'js/[name].js',
path: resolveApp('./dist'),
},
// ...
}
這樣編譯後就會根據入口生成兩個js檔案
防止重複
當存在公共的庫時,多處引用可能會造成重複載入的問題。
Entry Dependencies
一種方式是定義 entry ,將重複的依賴抽離單獨編譯成一個檔案
splitChunksPlugin
另外就是可以使用 splitChunksPlugin, 它已經預設整合在 webpack 當中,通過 splitChunks 來設定屬性,chunks 屬性有三個值,用於定義分離的場景。
- async,預設情況,只有當代碼進行非同步操作時才會分離
- initial,同步程式碼會分離
- all,非同步同步都會分離
optimization: {
chunkIds: 'named', // 規定檔案的命名方式
splitChunks: {
chunks: 'all',
},
},
定義了 splitChunks 中分離程式碼方式之後,在 index.js 中使用到的 moment 和 lodash 都編譯到 vendors 這個檔案中
splitChunks 中還有其它的屬性,用於規定編譯的檔案大小、檔名
- minSize,預設2萬字節,規定拆分出來的包最小值
- maxSize,規定大於 maxSize 尺寸的包,拆分成不小於 minSize 的包
- minChunks,表示引用的包至少被匯入的次數
- cacheGroup,快取組,配置具體的編譯規則
這些即使不設定,也都是有預設值的,上面將依賴打包的非常長的檔名 vendors 就是按照預設的設定生成的,在 webpack 的官方文件 中有介紹
也可以自己再進行定義,比如更改 打包依賴的檔名
動態匯入
另外一種分離的方式就是動態匯入了,當使用資源時,才會下載並解析。
以下程式碼在 index.js 中引入 foo.js 和 baz.js
import('./foo');
import('./baz');
通過 import 函式動態匯入的 js 被編譯成兩個單獨的檔案。
動態匯入還可以通過魔法註釋做一些配置
- webpackChunkName 自定義編譯後文件名
- webpackPrefetch 在瀏覽器空閒時提前下載資源
- webpackPreload 和父 chunk 一起提前下載資源
在 import 函式中定義魔法註釋
import(
/* webpackChunkName: 'foo' */ /* webpackPreload: true */ './foo.js'
).then((result) => {
console.log('foo載入了', result, result.default);
});
可以在看到 foo.js 第一次是在瀏覽器空閒時下載資源,第二次是從快取中獲取資源
使用 prefetch 預獲取的方式可以提前下載好資源,當使用的時候速度會相對快一點,但這樣會給入口檔案渲染增加壓力,所以還得視實際使用場景而定。
總結
-
webpack.config.js 中使用 module.exports 匯出函式,通過引數來區分編譯環境,從而使用不同的 loader、plugin 和配置來處理開發、生產環境的資源。
-
拆分程式碼可以通過多入口 entry 、防止重複 splitChunksPlugin 和動態匯入 lazy 函式的方式來操作,其中動態匯入非同步檔案可以設定預載入或者預獲取提前下載資源。
以上就是 webpack 環境和程式碼分離的相關介紹, 更多有關webpack的內容可以參考我其它的博文,持續更新中~