webpack4.x常用配置

  • 2020 年 1 月 13 日
  • 筆記

配套程式碼demo:https://github.com/FinGet/webpack4_demo。部落格原文:[https://finget.github.io/2019/07/24/webpack4-0/](https://finget.github.io/2019/07/24/webpack4-0/)

打包多頁面在git倉庫里,並沒有單獨寫出來。

初始化:

yarn init -y yarn add webpack webpack-cli -D

webpack-cli的作用就是讓我們能在命令行中使用webpacknpx webpakck 這些指令。

webpack基礎配置

// webpack 是node寫出來,所以要按node的寫法  const path = require('path');    module.exports = {  	mode: 'development', // 模式 默認值:production [development]  	entry: './src/index.js',  // 打包入口文件  	output: {  		filename: 'bundle.[hash:8].js', // 打包後的文件名  		path: path.resolve(__dirname, 'dist') // 這個路徑必須是一個絕對路徑,所以需要用path來解析一下  	}  }
// src/index.js  console.log('hello webpack4.0');

npx webpack 命令直接打包(npm5.2之後支援的語法)。會打包出一個main.js文件

默認支援js模組化:

// commonjs  // src/a.js  module.exports = 'FinGet'  // src/index.js  let name = require('./a.js');  console.log(name); // 'FinGet'
// ES6 module  // src/a.js  export default = 'FinGet'  // src/index.js  import name from './a.js'  console.log(name); // 'FinGet'

手動配置webpack

  • 默認配置文件的名字: webpack.config.js。為啥叫這個名字呢?
// node_modules/webpack-cli/bin/config/config-yargs.js  ...    module.exports = function(yargs) {    yargs  	.help("help")  	.alias("help", "h")  	.version()  	.alias("version", "v")  	.options({  	  config: {  		type: "string",  		describe: "Path to the config file",  		group: CONFIG_GROUP,  		defaultDescription: "webpack.config.js or webpackfile.js", // 默認名字有兩種  		requiresArg: true  	  },  ...
  • 可以通過–config指定配置文件: npx webpack –config xxxx.js
  • 也可以在package.json中配置腳本
"script": {    "build": "webpack --config webpack.config.my.js"  },

運行 npm run build

  • 如果在package.json中不設置config文件
"script": {    "build": "webpack"  },

運行 npm run build -- --config webpack.config.my.js -- 不能少!

  • 簡化的webpack打包出來的文件:
(function(modules) { // webpackBootstrap    // The module cache 先定義一個快取    var installedModules = {};    // The require function 配置了一個require方法    function __webpack_require__(moduleId) {        // Check if module is in cache 檢查這個模組是否在快取中      if (installedModules[moduleId]) {          return installedModules[moduleId].exports;      }      // Create a new module (and put it into the cache) 創建一個新的模組,並存入快取      var module = installedModules[moduleId] = {          i: moduleId,          l: false,          exports: {}      };        // Execute the module function      modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);        // Flag the module as loaded      module.l = true;        // Return the exports of the module      return module.exports;    }    // Load entry module and return exports 載入入口模組    return __webpack_require__(__webpack_require__.s = "./src/index.js");  })({  		// key-value  key -> 模組路徑 | value -> 函數      "./src/a.js": (function(module, exports) {          eval("module.exports="FinGet";nn//# sourceURL=webpack:///./src/a.js?");      }),      "./src/index.js": (function(module, exports, __webpack_require__) {          eval("let name = __webpack_require__(/*! ./a.js */ "./src/a.js");nconsole.log('hello webpack4.0');nconsole.log(name);nn//# sourceURL=webpack:///./src/index.js?");      })    });

webpack-dev-server

yarn add webpack-dev-server -D

它會在記憶體中生成打包文件。

官方文檔: https://webpack.docschina.org/configuration/dev-server/

本地服務

// webpack.config.js  // 開發伺服器的配置 官方文檔: https://webpack.docschina.org/configuration/dev-server/  devServer: {  	contentBase: './dist', // 告訴伺服器從哪個目錄中提供內容。只有在你想要提供靜態文件時才需要。  	publicPath: './dist', // 將用於確定應該從哪裡提供 bundle,並且此選項優先。 此路徑下的打包文件可在瀏覽器中訪問。  	port: 3000, // 埠  	progress: true, // 打包過程  	open: true, // 自動打開瀏覽器  	compress: true, // 一切服務都啟用 gzip 壓縮  	// host: '' , // 指定使用一個 host  	hot: true, // 啟用 webpack 的 模組熱替換 功能 依賴於HotModuleReplacementPlugin  }    plugins: [    // 開啟webpack全局熱更新    new webpack.HotModuleReplacementPlugin()  ]

做代理

devServer : {    	proxy: { // 代理        '/api': {            target: 'http://localhost:3000',            pathRewrite: {'^/api' : ''}        }      }  }

mock數據

devServer: {    // 前端mock數據 不存在跨域    before(app) {      app.get('/api/goods', (req, res) => {   	  res.json({   		code: 0,   		list: [   		  {id:1,name:'蘋果'},   		  {id:2,name:'香蕉'}   	   ]   	  })   	})    }  }

html-webpack-plugin

yarn add html-webpack-plugin -D

plugins: [    new HtmlWebpackPlugin({  	template: path.resolve(__dirname,'./public/index.html'), // 模版路徑  	filename: 'index.html', // 打包後的文件名  	title: 'webpack4.0', // 顧名思義,設置生成的 html 文件的標題  	/**  		注入選項。有四個選項值 true, body, head, false    		true 默認值,script標籤位於html文件的  		body 底部body 同 true  		head script 標籤位於 head 標籤內  		false 不插入生成的 js 文件,只是單純的生成一個 html 文件  	*/  	inject: true,  	// favicon: 'xxx.ico' // 給生成的 html 文件生成一個 favicon  	minify: { // 壓縮  		removeAttributeQuotes: true, // 去掉屬性的雙引號  		collapseWhitespace: true // 程式碼壓縮成一行  	},  	hash: true, // hash選項的作用是 給生成的 js 文件一個獨特的 hash 值,該 hash 值是該次 webpack 編譯的 hash 值  	cahe: true, // 默認值是 true。表示只有在內容變化時才生成一個新的文件  	showErrors: true, // 如果 webpack 編譯出現錯誤,webpack會將錯誤資訊包裹在一個 pre 標籤內,屬性的默認值為 true    	/**  		chunks 選項的作用主要是針對多入口(entry)文件。當你有多個入口文件的時候,對應就會生成多個編譯後的 js 文件。那麼 chunks 選項就可以決定是否都使用這些生成的 js 文件。  		chunks 默認會在生成的 html 文件中引用所有的 js 文件,當然你也可以指定引入哪些特定的文件。  	**/  	// chunks: ['index','index2'],    })  ]

css樣式

yarn add css-loader style-loader less less-loader -D

在index.js中引入css|less模組

// src/index.js  let name = require('./a.js');  require('./assets/css/index.css');  require('./assets/css/commom.less');  console.log('hello webpack4.0');  console.log(name);
module: { // 模組    rules: [  	// loader的順序 默認是從右往左,從上到下      // css-loader 解析 @import 這種語法的      // style-loader 將css引入html的head中 style標籤  	// {test: /.css$/, use: ['style-loader','css-loader']}  	{test: /.(css|less)$/,  	  use: [  		{  		  loader: 'style-loader',  		  options: {  			insertAt: 'top' // 插入頂部 這樣就會被後面的樣式覆蓋  		  }  		},  		'css-loader',  		'less-loader'  	  ]  	}    ]  },

mini-css-extract-plugin

yarn add mini-css-extract-plugin -D

上面打包css會把css文件以style標籤的形式寫入index.html,現在我們就來把它們單獨打包成文件。

module: { // 模組  	rules: [  		{test: /.(css|less)$/,  			use: [  				MiniCssExtractPlugin.loader,  				'css-loader',  				'less-loader'  			]  		}  	]  },    plugins: [    	new MiniCssExtractPlugin({  		filename: 'assets/css/index.css' // 打包到dist/assets/css/index.css  	})  ]

css3 自動添加各種瀏覽器前綴:

yarn add postcss-loader autoprefixer -D

// postcss.config.js  module.exports = {  	plugins: [require('autoprefixer')({'browsers': ['> 1%', 'last 2 versions']})]  }    // webpack.config.js  module: { // 模組  	rules: [  		{test: /.(css|less)$/,  			use: [  				MiniCssExtractPlugin.loader,  				'css-loader',  				'postcss-loader',  				'less-loader'  			]  		}  	]  },

推薦用法是在package.json中設置:

Replace Autoprefixer browsers option to Browserslist config. Use browserslist key in package.json or .browserslistrc file.

// postcss.config.js  module.exports = {  	plugins: [require('autoprefixer')]  }
"browserslist": [     "> 1%",     "last 2 versions",     "not ie <= 8"   ]

壓縮css:

⚠️壓縮css也要壓縮js,不如js不會壓縮。

yarn add optimize-css-assets-webpack-plugin terser-webpack-plugin -D

// webpack.config.js  mode:'production', // * development不會壓縮  optimization: {      minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],    },

處理js

yarn add babel-loader @babel/babel-core @babel/preset-env -D

⚠️@babel/babel-core@babel/preset-envbabel-corebabel-preset-env 不一樣

// webpack.config.js  module: {    rules: [      {        test: /.js$/,        exclude: '/node_modules',        include: 'src',        use: {      	loader: 'babel-loader',      	options: {      	    // 配置預設      		presets: [      			'@babel/preset-env'      		]      	}        }      }    ]  }

或者:

// .babelrc  {    "presets": ["@babel/preset-env"]  }

處理高級版本js

babel-runtime 是供編譯模組復用工具函數,是錦上添花。 babel-polyfil是雪中送炭,是轉譯沒有的api。

詳細講解

// 示例  class Person{  	constructor(name, age) {      this.name = name;      this.age = age;    }  }    let person = new Person('FinGet',24);  console.log(person.name);    // 高級api  console.log('FinGet'.includes('Get'));
yarn add @babel/plugin-transform-runtime -D  // @babel/runtime as a production dependency (since it's for the "runtime").  yarn add @babel/runtime

使用:

// .babelrc  "plugins": ["@babel/plugin-transform-runtime"]

@babel/runtime 會在打包的js中,注入一些腳本,所以要安裝production依賴

yarn add @babel/polyfill

使用:

require("@babel/polyfill");  // or  import "@babel/polyfill";  // or  // webpack.config.js  module.exports = {    entry: ["@babel/polyfill", "./app/js"],  };

這樣引入會導致打包出來的js很大

按需引入:

// .babelrd  {    "presets": [["@babel/preset-env", {      "useBuiltIns": "usage"    }]],  }

關鍵點是useBuiltIns這一配置項,它的值有三種:

  • false: 不對polyfills做任何操作
  • entry: 根據target中瀏覽器版本的支援,將polyfills拆分引入,僅引入有瀏覽器不支援的polyfill
  • usage(新):檢測程式碼中ES6/7/8等的使用情況,僅僅載入程式碼中用到的polyfills

ESlint 檢測語法

yarn add eslint eslint-loader -D

https://cn.eslint.org/demo/

在根目錄下生成一個.eslint.json來配置規則。

{      "parserOptions": {          "ecmaVersion": 5,          "sourceType": "script",          "ecmaFeatures": {}      },      "rules": {          // 允許console          "no-console": "off",          // 允許空語句塊          "no-empty": ["error", { "allowEmptyCatch": true }],          // 強制關鍵字周圍空格的一致性 (keyword-spacing)          "keyword-spacing": "error",          // 把 var 語句看作是在塊級作用域範圍之內          "block-scoped-var": "error",          // 要求遵循大括弧約定          "curly": "error",          // switch 要有default分支          "default-case": "error",          // no-eq-null 禁止與null進行比較          "no-eq-null": "error",          // 禁止使用多個空格          "no-multi-spaces": ["error", {"exceptions": { "Property": true }}],          // 禁止多行字元串          "no-multi-str": "error",          // 禁止使用 new 以避免產生副作用          "no-new": "error",          // 數組中的空格          "array-bracket-spacing": ["error", "never"],          // 禁止或強制在程式碼塊中開括弧前和閉括弧後有空格          "block-spacing": "error",          // 大括弧風格要求          "brace-style": ["error",  "1tbs", { "allowSingleLine": true }],          // 逗號前後使用一致的空格          "comma-spacing": ["error", { "before": false, "after": true }],          // 逗號風格          "comma-style": ["error", "last"],          // 計算屬性不使用空格          "computed-property-spacing": ["error", "never"],          // 函數標識符和其調用之間禁止空格          "func-call-spacing": ["error", "never"],          // 箭頭函數函數體的位置          "implicit-arrow-linebreak": ["error", "beside"],          // tab縮進          "indent": ["error", "tab", { "SwitchCase": 1 }],          // 對象key-value空格          "key-spacing": ["error", { "beforeColon": false }],          // 行注釋位置          "line-comment-position": ["error", { "position": "above" }],          // 類成員之間需要空行          "lines-between-class-members": ["error", "always"],          // 要求構造函數首字母大寫          "new-cap": "error",          // 調用無參構造函數時帶括弧          "new-parens": "error",          // 禁止使用 Array 構造函數          "no-array-constructor": "error",          // 禁止使用內聯注釋          "no-inline-comments": "error",          // 禁止連續賦值          "no-multi-assign": "error",          // 不允許多個空行          "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1 }],          // 禁止使用 Object 構造函數          "no-new-object": "error",          // 禁用行尾空白          "no-trailing-spaces": "error",          // 禁止屬性前有空白          "no-whitespace-before-property": "error",          // 強制在花括弧內使用一致的換行符          "object-curly-newline": ["error", { "ImportDeclaration": "always", "ExportDeclaration": "always" }],          // 花括弧中使用一致的空格          "object-curly-spacing": ["error", "never"],          // 要求在變數聲明周圍換行          "one-var-declaration-per-line": ["error", "always"],          // 禁止塊內填充          "padded-blocks": ["error", "never"],          // 語句間填充空行          "padding-line-between-statements": [              "error",              { "blankLine": "always", "prev": ["const", "let", "var"], "next": "*"},              { "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]},              { "blankLine": "always", "prev": "directive", "next": "*" },              { "blankLine": "any", "prev": "directive", "next": "directive" }          ],          // 強制使用一致的反勾號、雙引號或單引號          "quotes": ["error", "single", { "allowTemplateLiterals": true }],          // 對象字面量屬性名稱使用引號          "quote-props": ["error", "as-needed"],          // 行尾分號          "semi": ["error", "always"],          // 分號前後空格          "semi-spacing": ["error", {"before": false, "after": true}],          // 分號位置          "semi-style": ["error", "last"],          // 語句塊之前的空格          "space-before-blocks": "error",          // function空格          "space-before-function-paren": ["error", {              "anonymous": "always",              "named": "never",              "asyncArrow": "always"          }],          // 禁止圓括弧內的空格          "space-in-parens": "error",          // 要求中綴操作符周圍有空格          "space-infix-ops": "error",          // 要求或禁止在一元操作符之前或之後存在空格          "space-unary-ops": ["error", {"words": true, "nonwords": false}],          // 要求或禁止在注釋前有空白          "spaced-comment": ["error", "always"],          // 強制在 switch 的冒號左右有空格          "switch-colon-spacing": "error",          // 要求正則表達式被包裹起來          "wrap-regex": "error",            // ES6          // 要求箭頭函數體使用大括弧          "arrow-body-style": "error",          // 要求箭頭函數的箭頭之前或之後有空格          "arrow-spacing": "error",          // 禁止重複導入      },      "env": {}  }
{    test: /.js$/,    loader: ['babel-loader', 'eslint-loader'],  }  // or  {    test: /.js$/,    use: {      loader: 'eslint-loader',      options: {        enforce: 'pre' // 先執行      }    }  }

打包圖片

  • js中創建圖片引入
import jpg from './assets/snail.jpg'  let img = new Image();  img.src = jpg    document.body.appendChild(img);
  • css背景圖引入
body{  	background-image: url(../logo.svg);  }
  • html img標籤引入
<img src="../src/assets/snail.jpg" alt="">

file-loader

yarn add file-loader -D

file-loader 會默認在內部生成生成一張圖片,到dist目錄下,把生成圖片的名字返回回來

{    test: /.(png|jpe?g|gif|svg)(?.*)?$/,    use: 'file-loader'  }

html-withimg-loader

html中直接使用img標籤src載入圖片的話,因為沒有被依賴,圖片將不會被打包。

yarn add html-withimg-loader

使用:

{    test: /.(htm|html)$/i,    loader: 'html-withimg-loader'  }

url-loader

如果圖片較多,會發很多http請求,會降低頁面性能。這個問題可以通過url-loader解決。url-loader會將引入的圖片編碼,生成dataURl。相當於把圖片數據翻譯成一串字元。再把這串字元打包到文件中,最終只需要引入這個文件就能訪問圖片了。當然,如果圖片較大,編碼會消耗性能。因此url-loader提供了一個limit參數,小於limit位元組的文件會被轉為DataURl,大於limit的還會使用file-loader進行copy。


url-loader和file-loader是什麼關係呢?簡答地說,url-loader封裝了file-loader。url-loader不依賴於file-loader,即使用url-loader時,只需要安裝url-loader即可,不需要安裝file-loader,因為url-loader內置了file-loader。

yarn add url-loader -D
{    test: /.(png|jpe?g|gif|svg)(?.*)?$/,    use: {    	loader: 'url-loader',    	options: {    	    name: '[name].[ext]', // 保持名稱不變    		limit: 20*1024, // 小於20k的圖片 打包成base64    		outputPath: 'assets/' // 打包後的存放路徑 dist/assets    	}    }  },

output.publicPath

此選項指定在瀏覽器中所引用的「此輸出目錄對應的公開 URL」。相對 URL(relative URL) 會被相對於 HTML 頁面(或 標籤)解析。相對於服務的 URL(Server-relative URL),相對於協議的 URL(protocol-relative URL) 或絕對 URL(absolute URL) 也可是可能用到的,或者有時必須用到,例如:當將資源託管到 CDN 時。

module.exports = {    //...    output: {      path: path.resolve(__dirname, 'dist'),      publicPath: 'https://cdn.example.com/assets/'    }  };

⚠️也可以單獨給圖片的options下配一個publicPath

source-map

生產模式會壓縮程式碼成一行,就沒法調試了。

...  ️mode:'developmen', //production 不會生成map文件  entry: './src/index.js',  devtool: "source-map", // 增加映射文件  ...

webpack 高級配置

watch

...  entry: entry: './src/index.js',  // build 監控,變化自動打包  watch: true,  watchOptions: { // 監控選項    poll: 1000, // 每秒 watch 1000次    aggregateTimeout: 500, // 防抖    ignored: '/node_modules/' //不需要監控的文件  },  ...

clean-webpack-plugin

每次打包之前,都刪除dist目錄下的文件。

yarn add clean-webpack-plugin -D

clean-webpack-plugin: ^3.00

const {CleanWebpackPlugin} = require('clean-webpack-plugin');    plugins: [      new CleanWebpackPlugin()  ]
export { CleanWebpackPlugin };//3.0.0導出方式    export default CleanWebpackPlugin;//2.0.2導出方式  所以在2.0.2版本我們可以直接require拿到CleanWebpackPlugin  const CleanWebpackPlugin = require('clean-webpack-plugin')    module.exports = CleanWebpackPlugin;//1.0.1導出方式

他會默認清空我們output裡面設置的所有文件夾

https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional    By default, this plugin will remove all files inside webpack's output.path directory, as well as all unused webpack assets after every successful rebuild.

copy-webpack-plugin

拷貝文件

yarn add copy-webpack-plugin -D
const CopyPlugin = require('copy-webpack-plugin');    plugins: [    new CopyPlugin([      { from: 'src/assets', to: 'assets' }    ]),  ]

BannerPlugin

版權聲明

plugins:[    new webpack.BannerPlugin('CopyRight by FinGet!')  ]  // 會在打包文件頭部加上 /*! CopyRight by FinGet! */
// 配置選項  {    banner: string | function, // 其值為字元串或函數,將作為注釋存在    raw: boolean, // 如果值為 true,將直出,不會被作為注釋    entryOnly: boolean, // 如果值為 true,將只在入口 chunks 文件中添加    test: string | RegExp | Array,    include: string | RegExp | Array,    exclude: string | RegExp | Array,  }

resolve

module.exports = {    resolve: { // 解析第三方包      alias: { // 創建 import 或 require 的別名,來確保模組引入變得更簡單。        '@': path.resolve(__dirname, 'src')      },      extensions: ['.js','.css','.json'], // 自動解析確定的擴展 就是沒有後綴名時,按這個順序匹配      modules: [path.resolve('node_modules')] //告訴 webpack 解析模組時應該搜索的目錄    },  }

點這裡查看更多配置項。

DefinePlugin

定義一些全局變數。

module.exports = {    plugins: [      new webpack.DefinePlugin({        PRODUCTION: JSON.stringify(true),        VERSION: JSON.stringify('5fa3b9'),        BROWSER_SUPPORTS_HTML5: true,        TWO: '1+1',        'typeof window': JSON.stringify('object'),        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)      });    ]  }

注意,因為這個插件直接執行文本替換,給定的值必須包含字元串本身內的實際引號。通常,有兩種方式來達到這個效果,使用 『「production」『, 或者使用 JSON.stringify(『production』)。

webpack-merge

分別配置不同的環境打包文件。

yarn add webpack-merge -D
// build/webpack.base.conf.js  const webpack = require('webpack');  const path = require('path');  const HtmlWebpackPlugin = require('html-webpack-plugin');  const MiniCssExtractPlugin = require('mini-css-extract-plugin');  const { CleanWebpackPlugin } = require('clean-webpack-plugin');    module.exports = {    entry: path.resolve(__dirname,'../src/index.js'), // 打包入口文件    output: {      filename: 'bundle.[hash:8].js', // 打包後的文件名      path: path.resolve(__dirname, '../dist') // 這個路徑必須是一個絕對路徑,所以需要用path來解析一下    },    module: { // 模組      rules: [        {          test: /.(css|less)$/,          use: [            MiniCssExtractPlugin.loader,            'css-loader',            'postcss-loader',            'less-loader'          ]        },        {          test: /.js$/,          loader: 'babel-loader',        },        {          test: /.(png|jpe?g|gif|svg)(?.*)?$/,          use: {            loader: 'url-loader',            options: {              limit: 1,              outputPath: 'assets/images' // 打包後的存放路徑            }          }        },        {          test: /.(htm|html)$/i,          loader: 'html-withimg-loader'        }      ]    },      // 配置插件      plugins: [      new CleanWebpackPlugin(),      new HtmlWebpackPlugin({        template: path.resolve(__dirname, '../public/index.html'), // 模版路徑        filename: 'index.html', // 打包後的文件名        title: 'webpack4.0', // 顧名思義,設置生成的 html 文件的標題        inject: true,        hash: true, // hash選項的作用是 給生成的 js 文件一個獨特的 hash 值,該 hash 值是該次 webpack 編譯的 hash 值        cahe: true, // 默認值是 true。表示只有在內容變化時才生成一個新的文件        showErrors: true, // 如果 webpack 編譯出現錯誤,webpack會將錯誤資訊包裹在一個 pre 標籤內,屬性的默認值為 true      }),      new MiniCssExtractPlugin({        filename: 'assets/css/index.css'      })    ]  }
// build/webpack.pro.cong.js  const merge = require('webpack-merge');  const base = require('./webpack.base.conf');  const TerserJSPlugin = require('terser-webpack-plugin');  const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');    mmodule.exports = merge(base, {  	mode: 'production',  	optimization: {        minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],      },      plugins: [    	  // 文件頭部注入        new webpack.BannerPlugin('CopyRight by FinGet!')      ]  })
// build/webpack.dev.cong.js  const merge = require('webpack-merge');  const webpack = require('webpack');  const base = require('./webpack.base.conf');    mmodule.exports = merge(base, {    mode: 'development',    // 開發伺服器的配置 官方文檔: https://webpack.docschina.org/configuration/dev-server/    devServer: {      contentBase: path.resolve(__dirname, "../dist"), // 告訴伺服器從哪個目錄中提供內容。只有在你想要提供靜態文件時才需要。      // publicPath: './dist', // 將用於確定應該從哪裡提供 bundle,並且此選項優先。 此路徑下的打包文件可在瀏覽器中訪問。      port: 3000, // 埠      progress: true, // 打包過程      open: true, // 自動打開瀏覽器    },    devtool: 'source-map',    plugins: [      new webpack.DefinePlugin({        'process.env': {          'NODE_ENV': JSON.stringify(process.env.NODE_ENV)        }      })    ],  })
yarn run dev -- --config build/webpack.dev.conf.js      yarn run build -- --config build/webpack.pro.conf.js

webpack 優化

noParse

防止 webpack 解析那些任何與給定正則表達式相匹配的文件。

module.exports = {    //...    module: {      noParse: /jquery|lodash/,    }  };

happyPack 多執行緒打包

js、css、img都可以多執行緒打包,提高打包速度。

yarn add happypack -D
module.exports = {   module:{     {       test: /.js$/,       use: 'Happypack/loader?id=js'     }   }   plugins:[     new Happypack({       id: 'js', // id與上面對應       use: [{         loader: 'babel-loader',         options: {           presets:['@babel/preset-env']         }       }]     })   ]  }

tree-shaking

(webpack 自帶)把沒用的程式碼刪除掉。

import 在生產環境下 會自動去掉沒用的程式碼。es6 模組會把結果放到default上。

// test.js  let sum = (a,b) => {    return a+b;  }  let minus = (a,b) => {    return a-b;  }  export default {sum,minus}
import calc from './test.js';  console.log(calc.add(1,2));    let calc = require('./test');  console.log(calc.default.sum(1,2));

這裡沒用minus方法,在import方式打包中會tree-shaking,require則不會。

scope hosting

let a = 1;  let b = 2;  let c = 3;  let d = a + b + c;  console.log(d);

這個程式碼很啰嗦,在打包之後,webpack會自動分析,省略程式碼。

// 打包後  console.log(6);

抽離公共程式碼

多入口項目,多個入口,引用同一個js/css,則可以抽離公共程式碼。

module.exports = {    optimization: {      splitChunks: { // 分割程式碼塊        cacheGroups: { // 快取組          common: { // 公共模組            chunks: 'initial',            minSize: 0,            minChunks: 2,          }        }      }    },  }
// 把第三方模組單獨打包 比如jquery、lodash  module.exports = {    optimization: {      splitChunks: { // 分割程式碼塊        cacheGroups: { // 快取組          common: { // 公共模組            chunks: 'initial',            minSize: 0,            minChunks: 2,          },            // 單獨打包第三方模組          vendor: {            priority: 1, // 優先順序別            test: /[\/]node_modules[\/]/,            chunks: 'initial',            name(module, chunks, cacheGroupKey) {              const moduleFileName = module.identifier().split('/').reduceRight(item => item);              return `${moduleFileName}`;            },            minSize: 0,            minChunks: 2          }        }      }    },  }

optimization參數介紹:

optimization: {      splitChunks: {        chunks: "initial",         // 程式碼塊類型 必須三選一: "initial"(初始化) | "all"(默認就是all) | "async"(動態載入)        minSize: 0,                // 最小尺寸,默認0        minChunks: 1,              // 最小 chunk ,默認1        maxAsyncRequests: 1,       // 最大非同步請求數, 默認1        maxInitialRequests: 1,     // 最大初始化請求書,默認1        name: () => {},            // 名稱,此選項課接收 function        cacheGroups: {                // 快取組會繼承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用於配置快取組。          priority: "0",              // 快取組優先順序 false | object |          vendor: {                   // key 為entry中定義的 入口名稱            chunks: "initial",        // 必須三選一: "initial"(初始化) | "all" | "async"(默認就是非同步)            test: /react|lodash/,     // 正則規則驗證,如果符合就提取 chunk            name: "vendor",           // 要快取的 分隔出來的 chunk 名稱            minSize: 0,            minChunks: 1,            enforce: true,            reuseExistingChunk: true   // 可設置是否重用已用chunk 不再創建新的chunk          }        }      }    }

點擊這裡查看更多配置。

懶載入

在用戶觸發一個點擊操作才載入需要的文件。

// lazy.js  export default '懶載入';
// test.js  function handleClick() {    import('./lazy.js').then(module => {      console.log(module.default);    })  }