1. 程式人生 > 其它 >在webpack中這樣分離環境和程式碼就好啦

在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的內容可以參考我其它的博文,持續更新中~