一個合格的Webpack4配置工程師素養:第三部分
之前有提過webpack根據不同的環境我們會載入不同的配置。我們只需要提取出三部分。
- base: 公共的部分 - dev: 開發環境部分 - prod: 生產環境部分 複製程式碼
npm i -D webpack-merge 複製程式碼
我們這裡現在簡單分層:正式專案最好建立一個config/webpack目錄管理。

下面是原始碼。
"scripts": { "dev": "cross-env NODE_ENV=development npx webpack --progress --config webpack.dev.config.js", "build": "cross-env NODE_ENV=production npx webpack --progress --config webpack.prod.config.js" }, 複製程式碼
// webapck.base.config.js const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') const CleanWebpackplugin = require('clean-webpack-plugin') module.exports = { entry: './src/index.js', module: { rules: [ // 處理字型 { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { // 檔案大小小於limit引數,url-loader將會把檔案轉為DataUR limit: 10000, name: '[name]-[hash:5].[ext]', output: 'fonts/', // publicPath: '', 多用於CDN } }, // 處理檔案 { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [ // 轉base64 { loader: 'url-loader', options: { // 具體配置見外掛官網 limit: 10000, name: '[name]-[hash:5].[ext]', outputPath: 'img/', // outputPath所設定的路徑,是相對於 webpack 的輸出目錄。 // publicPath 選項則被許多webpack的外掛用於在生產模式下更新內嵌到css、html檔案內的 url , 如CDN地址 }, }, { loader: 'image-webpack-loader', options: { mozjpeg: { progressive: true, quality: 65 }, // optipng.enabled: false will disable optipng optipng: { enabled: false, }, pngquant: { quality: '65-90', speed: 4 }, gifsicle: { interlaced: false, }, // the webp option will enable WEBP webp: { quality: 75 } } } ] } ] }, plugins: [ // 打包模板 new HtmlWebpackPlugin({ inject: true, hash: true, cache: true, chunksSortMode: 'none', title: 'Webapck4-demo', // 可以由外面傳入 filename: 'index.html', // 預設index.html template: path.resolve(__dirname, 'index.html'), minify: { collapseWhitespace: true, removeComments: true, removeRedundantAttributes: true, removeScriptTypeAttributes: true, removeStyleLinkTypeAttributes: true } }), // 清理dist目錄 new CleanWebpackplugin(['dist']) ] } 複製程式碼
// webpack.dev.config.js const path = require('path') const merge = require('webpack-merge') const baseWebpackConfig = require('./webpack.base.config.js') module.exports = merge(baseWebpackConfig, { mode: 'development', output: { filename: 'bound.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ // 處理css/scss/sass { test: /\.(sc|sa|c)ss$/, use: [ { loader: 'style-loader', }, { loader: 'css-loader', options: { sourceMap: true } }, { loader: 'postcss-loader', options: { ident: 'postcss', sourceMap: true, plugins: (loader) => [ require('autoprefixer')({ browsers: [ 'last 10 Chrome versions', 'last 5 Firefox versions', 'Safari >= 6', 'ie > 8' ] }) ] } }, { loader: 'sass-loader', options: { sourceMap: true } } ] } ] } }) 複製程式碼
// webapck.prod.config.js const path = require('path') const MiniCssExtractPlugin = require('mini-css-extract-plugin') const OptimizeCSSAssertsPlugin = require('optimize-css-assets-webpack-plugin') const TerserPlugin = require('terser-webpack-plugin') const merge = require('webpack-merge') const baseWebpackConfig = require('./webpack.base.config.js') const devMode = process.env.NODE_ENV !== 'production' module.exports = merge(baseWebpackConfig, { mode: 'production', output: { filename: 'bound.[hash:5].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ // 處理css/scss/sass { test: /\.(sc|sa|c)ss$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader' }, { loader: 'postcss-loader', options: { ident: 'postcss', plugins: (loader) => [ require('autoprefixer')({ browsers: [ 'last 10 Chrome versions', 'last 5 Firefox versions', 'Safari >= 6', 'ie > 8' ] }) ] } }, { loader: 'sass-loader' } ] } ] }, plugins: [ // 提取CSS new MiniCssExtractPlugin({ filename: devMode ? '[name].css' : '[name].[hash:5].css', // 設定輸出的檔名 chunkFilename: devMode ? '[id].css': '[id].[hash:5].css' }) ], optimization: { minimizer: [ // 壓縮JS new TerserPlugin({ cache: true, parallel: true, sourceMap: true, // 等等詳細配置見官網 }), // 壓縮CSS new OptimizeCSSAssertsPlugin({}) ] } }) 複製程式碼
webpack配置js使用sourceMap
在webpack4使用inline-source-map選項就可以啟動錯誤的堆疊跟蹤, 只用於開發環境
devtool: 'inline-source-map' 複製程式碼
監控檔案變化自動編譯
簡單的方法就是啟動watch模式: 如
"dev": "cross-env NODE_ENV=development npx webpack --progress --config webpack.dev.config.js --watch" 複製程式碼
webpack開啟熱更新和代理配置
很明顯上面watch模式效率不高而且很不方便, 編譯完還需要重新整理頁面, webpack可以開啟熱更新模式,大大加速開大效率。
npm i -D webpack-dev-server 複製程式碼
修改script指令碼。
"dev": "cross-env NODE_ENV=development npx webpack-dev-server --progress --config webpack.dev.config.js" 複製程式碼
修改配置檔案
const webpack = require('webpack') plugins: [ new webpack.NamedModulesPlugin(), // 更方便檢視patch的依賴 new webpack.HotModuleReplacementPlugin() // HMR ], devServer: { clientLogLevel: 'warning', // 輸出日誌級別 hot: true, // 啟用熱更新 contentBase: path.resolve(__dirname, 'dist'), // 告訴伺服器從哪裡提供內容 publicPath: '/', // 此路徑下的打包檔案可在瀏覽器下訪問 compress: true, // 啟用gzip壓縮 // publicPath: './', disableHostCheck: true, host: '0.0.0.0', port: 9999, open: true, // 自動開啟瀏覽器 overlay: { // 出現錯誤或者警告時候是否覆蓋頁面線上錯誤資訊 warnings: true, errors: true }, quiet: true, proxy: { // 設定代理 '/dev': { target: 'http://dev.xxxx.com.cn', changeOrigin: true, pathRewrite: { '^/dev': '' } /** * 如果你的配置是 * pathRewrite: { '^/dev': '/order/api' } 即本地請求 /dev/getOrder=>實際上是http://dev.xxxx.com.cn/order/api/getOrder */ }, '/test': { target: 'http://test.xxxx.com.cn', changeOrigin: true, pathRewrite: { '^/test': '' } }, '/prod': { target: 'http://prod.xxxx.com.cn', changeOrigin: true, pathRewrite: { '^/prod': '' } } }, watchOptions: { // 監控檔案相關配置 poll: true, ignored: /node_modules/, // 忽略監控的資料夾, 正則 aggregateTimeout: 300, // 預設值, 當你連續改動時候, webpack可以設定構建延遲時間(防抖) } } 複製程式碼
webpack啟用babel轉碼
npm i -Dbabel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime 複製程式碼
修改配置檔案
// 編譯js { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader?cacheDirectory', // 通過cacheDirectory選項開啟支援快取 options: { presets: ['@babel/preset-env'] } } }, 複製程式碼
增加.babelrc配置檔案
// 僅供參考 { "presets": [ [ "@babel/preset-env" ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": false, "helpers": true, "regenerator": true, "useESModules": false, "absoluteRuntime": "@babel/runtime" } ] ] } 複製程式碼
webpack配置eslint校驗
npm i -D eslint eslint-loader // 校驗規則 npm i -D babel-eslint standard 複製程式碼
修改webpack配置檔案
// 編譯js { test: /\.js$/, exclude: /(node_modules|bower_components)/, use: [ { loader: 'babel-loader?cacheDirectory', // 通過cacheDirectory選項開啟支援快取 options: { presets: ['@babel/preset-env'] } }, { loader: 'eslint-loader', options: { fix: true } } ] }, 複製程式碼
增加.eslintrc.js檔案
/* * ESLint的JSON檔案是允許JavaScript註釋的,但在gist裡顯示效果不好,所以我把.json檔案字尾改為了.js */ /* * ESLint 配置檔案優先順序: * .eslintrc.js(輸出一個配置物件) * .eslintrc.yaml * .eslintrc.yml * .eslintrc.json(ESLint的JSON檔案允許JavaScript風格的註釋) * .eslintrc(可以是JSON也可以是YAML) *package.json(在package.json裡建立一個eslintConfig屬性,在那裡定義你的配置) */ /* * 你可以通過在專案根目錄建立一個.eslintignore檔案告訴ESLint去忽略特定的檔案和目錄 * .eslintignore檔案是一個純文字檔案,其中的每一行都是一個glob模式表明哪些路徑應該忽略檢測 */ module.exports = { //ESLint預設使用Espree作為其解析器 //同時babel-eslint也是用得最多的解析器 //parser解析程式碼時的引數 "parser": "babel-eslint", "parserOptions": { //指定要使用的ECMAScript版本,預設值5 "ecmaVersion": 6 //設定為script(預設)或module(如果你的程式碼是ECMAScript模組) // "sourceType": "script", //這是個物件,表示你想使用的額外的語言特性,所有選項預設都是false // "ecmafeatures": { ////允許在全域性作用域下使用return語句 //"globalReturn": false, ////啟用全域性strict模式(嚴格模式) //"impliedStrict": false, ////啟用JSX //"jsx": false, ////啟用對實驗性的objectRest/spreadProperties的支援 //"experimentalObjectRestSpread": false // } }, //指定環境,每個環境都有自己預定義的全域性變數,可以同時指定多個環境,不矛盾 "env": { //效果同配置項ecmaVersion一樣 "es6": true, "browser": true, "node": true, "commonjs": false, "mocha": true, "jquery": true, //如果你想使用來自某個外掛的環境時,確保在plugins數組裡指定外掛名 //格式為:外掛名/環境名稱(外掛名不帶字首) // "react/node": true }, //指定環境為我們提供了預置的全域性變數 //對於那些我們自定義的全域性變數,可以用globals指定 //設定每個變數等於true允許變數被重寫,或false不允許被重寫 "globals": { "globalVar1": true, "globalVar2": false }, //ESLint支援使用第三方外掛 //在使用外掛之前,你必須使用npm安裝它 //全域性安裝的ESLint只能使用全域性安裝的外掛 //本地安裝的ESLint不僅可以使用本地安裝的外掛還可以使用全域性安裝的外掛 //plugin與extend的區別:extend提供的是eslint現有規則的一系列預設 //而plugin則提供了除預設之外的自定義規則,當你在eslint的規則裡找不到合適的的時候 //就可以借用外掛來實現了 "plugins": [ // "eslint-plugin-airbnb", //外掛名稱可以省略eslint-plugin-字首 // "react" ], //具體規則配置 //off或0--關閉規則 //warn或1--開啟規則,警告級別(不會導致程式退出) //error或2--開啟規則,錯誤級別(當被觸發的時候,程式會退出) "rules": { "eqeqeq": "warn", //你也可以使用對應的數字定義規則嚴重程度 "curly": 2, //如果某條規則有額外的選項,你可以使用陣列字面量指定它們 //選項可以是字串,也可以是物件 "quotes": ["error", "double"], "one-var": ["error", { "var": "always", "let": "never", "const": "never" }], //配置外掛提供的自定義規則的時候,格式為:不帶字首外掛名/規則ID // "react/curly": "error" }, //ESLint支援在配置檔案新增共享設定 //你可以新增settings物件到配置檔案,它將提供給每一個將被執行的規則 //如果你想新增的自定義規則而且使它們可以訪問到相同的資訊,這將會很有用,並且很容易配置 "settings": { "sharedData": "Hello" }, //Eslint檢測配置檔案步驟: //1.在要檢測的檔案同一目錄裡尋找.eslintrc.*和package.json //2.緊接著在父級目錄裡尋找,一直到檔案系統的根目錄 //3.如果在前兩步發現有root:true的配置,停止在父級目錄中尋找.eslintrc //4.如果以上步驟都沒有找到,則回退到使用者主目錄~/.eslintrc中自定義的預設配置 "root": true, //extends屬性值可以是一個字串或字串陣列 //陣列中每個配置項繼承它前面的配置 //可選的配置項如下 //1.字串eslint:recommended,該配置項啟用一系列核心規則,這些規則報告一些常見問題,即在(規則頁面)中打勾的規則 //2.一個可以輸出配置物件的可共享配置包,如eslint-config-standard //可共享配置包是一個匯出配置物件的簡單的npm包,包名稱以eslint-config-開頭,使用前要安裝 //extends屬性值可以省略包名的字首eslint-config- //3.一個輸出配置規則的外掛包,如eslint-plugin-react //一些外掛也可以輸出一個或多個命名的配置 //extends屬性值為,plugin:包名/配置名稱 //4.一個指向配置檔案的相對路徑或絕對路徑 //5.字串eslint:all,啟用當前安裝的ESLint中所有的核心規則 //該配置不推薦在產品中使用,因為它隨著ESLint版本進行更改。使用的話,請自己承擔風險 "extends": [ "standard" ] } 複製程式碼
增加.eslintignore檔案
/dist/ /node_modules/ /*.js 複製程式碼