webpack經常使用配置

1. 模塊熱替換

參考地址-官網javascript

1.1 啓用 HMR

啓用此功能須要更新 webpack-dev-server 的配置,和使用 webpack 內置的 HMR 插件。css

webpack.config.jshtml

module.exports = {
    // ...
    devServer: {
        // ...
        hot: true
    }
};
複製代碼

worker.js前端

if (module.hot) {
  	module.hot.accept('./print.js', function() {
        console.log('Accepting the updated printMe module!');
        printMe();
  	})
}
複製代碼

注意點vue

1.2 HMR 修改樣式表

CSS 的模塊熱更新,藉助於 style-loaderjava

2. Tree shaking

參考1-官網參考2-博客node

2.1 sideEffects

  • false ,全部文件代碼都沒有反作用
  • 數組,指定文件代碼是有反作用

「反作用」的定義是,在導入時會執行特殊行爲的代碼,而不是僅僅暴露一個 export 或多個 export。舉例說明,例如 polyfill,它影響全局做用域,而且一般不提供 export。有反作用的不能tree sharking!webpack

注意,任何導入的文件都會受到 tree shaking 的影響。這意味着,若是在項目中使用相似 css-loader 並導入 CSS 文件,則須要將其添加到 side effect 列表中,以避免在生產模式中無心中將它刪除。git

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}
複製代碼

還能夠在 module.rules 配置選項 中設置 "sideEffects"es6

2.2 壓縮輸出

從 webpack 4 開始,也能夠經過 "mode" 配置選項輕鬆切換到壓縮輸出,只需設置爲 "production"

webpack.config.js

module.exports = {
  // ...
  mode: "production"
};
複製代碼

2.3 tree sharking 條件

  • 使用 ES2015 模塊語法(即 importexport
  • 在項目 package.json 文件中,添加一個 sideEffects入口
  • 引入一個可以刪除未引用代碼(dead code)的壓縮工具(minifier)(例如 UglifyJSPlugin, webpack4 開始能夠設置 mode: "production"來代替)

3. devtool

參考-官網

生產環境,在使用 uglifyjs-webpack-plugin 時,你必須提供 sourceMap:true 選項來啓用 source map 支持。

鼓勵你在生產環境中啓用 source map,由於它們對調試源碼(debug)和運行基準測試(benchmark tests)頗有幫助。

3.1 對於開發環境

  • eval - 映射到轉換後的代碼
  • eval-source-map - 行數可以正確映射,會映射到原始代碼中。
  • cheap-eval-source-map - 相似 eval-source-map,每一個模塊使用 eval() 執行。這是 "cheap(低開銷)" 的 source map,由於它沒有生成列映射(column mapping),只是**映射行數。它會忽略源自 loader 的 source map,**而且僅顯示轉譯後的代碼,就像 eval devtool。
  • cheap-module-eval-source-map - 相似 cheap-eval-source-map,而且,在這種狀況下,源自 loader 的 source map 會獲得更好的處理結果。然而,loader source map 會被簡化爲每行一個映射(mapping)。

3.2 對於生產環境

這些選項一般用於生產環境中:

  • (none)(省略 devtool 選項) - 不生成 source map。這是一個不錯的選擇。

  • source-map - 整個 source map 做爲一個單獨的文件生成。它爲 bundle 添加了一個引用註釋,以便開發工具知道在哪裏能夠找到它。

    你應該將你的服務器配置爲,不容許普通用戶訪問 source map 文件!

  • hidden-source-map - 與 source-map 相同,但不會爲 bundle 添加引用註釋。若是你只想 source map 映射那些源自錯誤報告的錯誤堆棧跟蹤信息,但不想爲瀏覽器開發工具暴露你的 source map,這個選項會頗有用。

    你不該將 source map 文件部署到 web 服務器。而是隻將其用於錯誤報告工具。

  • nosources-source-map - 建立的 source map 不包含 sourcesContent(源代碼內容)。它能夠用來映射客戶端上的堆棧跟蹤,而無須暴露全部的源代碼。你能夠將 source map 文件部署到 web 服務器。

    這仍然會暴露反編譯後的文件名和結構,但它不會暴露原始代碼。

3.3 特定場景

如下選項對於開發環境和生產環境並不理想。他們是一些特定場景下須要的,例如,針對一些第三方工具。

  • inline-source-map - source map 轉換爲 DataUrl 後添加到 bundle 中。
  • cheap-source-map - 沒有列映射(column mapping)的 source map,忽略 loader source map。
  • inline-cheap-source-map - 相似 cheap-source-map,可是 source map 轉換爲 DataUrl 後添加到 bundle 中。
  • cheap-module-source-map - 沒有列映射(column mapping)的 source map,將 loader source map 簡化爲每行一個映射(mapping)。
  • inline-cheap-module-source-map - 相似 cheap-module-source-map,可是 source mapp 轉換爲 DataUrl 添加到 bundle 中。

4. 指定環境變量

參考-官網

4.1 基本使用

許多 library 將經過與 process.env.NODE_ENV 環境變量關聯,以決定 library 中應該引用哪些內容。例如,當不處於生產環境中時,某些 library 爲了使調試變得容易,可能會添加額外的日誌記錄(log)和測試(test)。其實,**當使用 process.env.NODE_ENV === 'production' 時,一些 library 可能針對具體用戶的環境進行代碼優化,從而刪除或添加一些重要代碼。**咱們可使用 webpack 內置的 DefinePlugin 爲全部的依賴定義這個變量

NODE_ENV 屬性

  1. 這個變量並非 pocess.env 直接就有的,而是經過設置獲得的。
  2. 能夠經過判斷這個變量區分開發環境或生產環境。

webpack.prod.js

const webpack = require('webpack');
  const merge = require('webpack-merge');
  const common = require('./webpack.common.js');

  module.exports = merge(common, {
    plugins: [
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify('production')
      })
    ]
  });
複製代碼

技術上講,NODE_ENV 是一個由 Node.js 暴露給執行腳本的系統環境變量。一般用於決定在開發環境與生產環境(dev-vs-prod)下,服務器工具、構建腳本和客戶端 library 的行爲。然而,與預期不一樣的是,沒法在構建腳本 webpack.config.js 中,將 process.env.NODE_ENV 設置爲 "production",請查看 #2537

例如 process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js' 這樣的條件語句,在 webpack 配置文件中,沒法按照預期運行。

任何位於 /src 的本地代碼均可以關聯到 process.env.NODE_ENV 環境變量,因此如下檢查也是有效的:

src/worker.js

import { cube } from './math.js';

  if (process.env.NODE_ENV !== 'production') {
    console.log('Looks like we are in development mode!');
  }
複製代碼

4.2疑問?

爲何 webpack官網 裏面說:

process.env.NODE_ENV === 'production' ? '[name].[hash].bundle.js' : '[name].bundle.js'`這樣的條件語句,在 webpack 配置文件中,沒法按照預期運行。

可是 MiniCssExtractPlugin 官網 裏面能夠以下使用:

const devMode = process.env.NODE_ENV !== 'production'
複製代碼

4.3 解惑

參考-網友博客

  1. 在初始狀態下 " 配置文件 " 和 " src 下面的文件 " 輸出的process.env.NODE_ENV值都是 undefined
  2. webpack config文件中定義的變量是爲了你將要打包的文件中用的。配置以下:
// 方式一
new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify('production')
})

// 方式二
{
    mode: 'production'
}
複製代碼

只設置 NODE_ENV,則會自動設置 mode

  1. 如何在webpack配置文件裏獲取NODE_ENV的值呢,這樣就能夠根據不一樣的值定義相關的參數了,如上所述,答案是:corss-env,在package.json裏增長以下配置:
"scripts": {
    "build-cross-env":"cross-env NODE_ENV=production webpack"
}
複製代碼

經過cross-env NODE_ENV=production,信息傳遞給了webpack的配置文件, src文件下面不能訪問。

5. 代碼分離

參考-官網

5.1 概述

把代碼分離到不一樣的 bundle 中,而後能夠按需加載或並行加載這些文件。代碼分離能夠用於獲取更小的 bundle,以及控制資源加載優先級,若是使用合理,會極大影響加載時間。

有三種經常使用的代碼分離方法:

  • 入口起點:使用 entry 配置手動地分離代碼。
  • 防止重複:使用 CommonsChunkPlugin 去重和分離 chunk。
  • 動態導入:經過模塊的內聯函數調用來分離代碼。

5.2 動態導入(dynamic imports)

當涉及到動態代碼拆分時,webpack 提供了兩個相似的技術。對於動態導入,第一種,也是優先選擇的方式是,使用符合 ECMAScript 提案import() 語法。第二種,則是使用 webpack 特定的 require.ensure。讓咱們先嚐試使用第一種……

import() 調用會在內部用到 promises。若是在舊有版本瀏覽器中使用 import(),記得使用 一個 polyfill 庫(例如 es6-promise promise-polyfill),來 shim Promise

worker.js

// 方式一
const _ = await import(/* webpackChunkName: "lodash" */ 'lodash');

// 方式二
import(/* webpackChunkName: "print" */ './print').then(module => {
      var print = module.default;
      print();
});
複製代碼

注意當調用 ES6 模塊的 import() 方法(引入模塊)時,必須指向模塊的 .default 值,由於**它纔是 promise 被處理後返回的實際的 module 對象*。*

webpack.config.js

output: {
    filename: '[name].bundle.js',
    chunkFilename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
}
複製代碼

5.3 bundle 分析

參考——官網

6. 緩存

6.1 hash、chunkhash和contenthash三者的區別

參考-網友博客

hash

跟整個webpack構建項目相關的,每次項目構建hash對應的值都是不一樣的,即便項目文件沒有作**「任何修改」**。

實際上是有修改的,由於每次webpack打包編譯都會注入webpack的運行時代碼,致使整個項目有變化,因此每次hash值都會變化的。

chunkhash

**根據不一樣的入口文件(Entry)進行依賴文件解析、構建對應的chunk,生成對應的hash值。**在生產環境裏把一些公共庫和程序入口文件區分開,單獨打包構建,採用chunkhash的方式生成hash值,那麼只要不改動公共庫的代碼,就能夠保證其hash值不會受影響。

對css使用了chunkhash以後,它與依賴它的chunk共用chunkhash,測試後會發現,css與js文件名的chunkhash值是同樣的JSCSS 相互影響。

css文件最好使用contenthash

contenthash

contenthash表示由文件內容產生的hash值,內容不一樣產生的contenthash值也不同。

6.2 實現圖片/字體的緩存

對於圖片、字體等靜態資源,生成對應的文件hash值是由對應的file-loader來計算的。

那麼這些靜態文件的hash值使用的是什麼hash值呢?

其實就是hash屬性值。此hash非webpack每次項目構建的hash,它是***由file-loader根據文件內容計算出來的,不是webpack構建的hash***。

7. 多種webpack配置類型(configuration types)

參考-官網

7.1 導出爲一個函數

module.exports = function(env, argv) {
   return {
     mode: env.production ? 'production' : 'development',
     devtool: env.production ? 'source-maps' : 'eval',
     plugins: [
       new webpack.optimize.UglifyJsPlugin({
         compress: argv['optimize-minimize'] // 只有傳入 -p 或 --optimize-minimize
       })
     ]
   };
};
複製代碼

當 webpack 配置對象導出爲一個函數時,能夠向起傳入一個"環境對象(environment)"。也能夠經過 [指定環境變量](#4. 指定環境變量) 中的 cross-env NODE_ENV=production webpack" 配置

webpack --env.NODE_ENV=local --env.production --progress
複製代碼

若是設置 env 變量,卻沒有賦值,--env.production 默認將 --env.production 設置爲 true。還有其餘可使用的語法。有關詳細信息,請查看 webpack CLI 文檔。

7.2 導出一個 Promise

webpack 將運行由配置文件導出的函數,而且等待 Promise 返回。便於須要異步地加載所需的配置變量。

module.exports = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        entry: './app.js',
        /* ... */
      })
    }, 5000)
  })
}
複製代碼

7.3 導出一個配置對象

7.4 導出數組,多個配置對象

8. webpack-dev-server的刷新模式inline和iframe詳解

參考-博客

iframe

  1. 在網頁中嵌入了一個iframe,將咱們本身的應用注入到這個iframe當中去。
  2. 在頁面頭部有一個提示框,用於顯示構建過程的狀態信息。
  3. 加載了live.bundle.js文件,其不但建立了iframe標籤,同時包含socket.ioclient代碼,以和webpack-dev-server進行websocket通信,從而完成自動編譯打包、頁面自動刷新的功能。

inline

  1. 構建消息在瀏覽器控制檯顯示。
  2. socket.ioclient代碼被打包進了你的包(bundle)中,以此來與webpack-dev-server進行websocket通信,從而完成自動編譯打包、頁面自動刷新的功能。
  3. 可是,每個入口文件都會被插入上述的一段腳本,使得打包後的bundle文件很臃腫。

總結

  1. Iframe modeInline mode最後達到的效果都是同樣的,都是監聽文件的變化,而後再將編譯後的文件推送到前端,完成頁面的reload的。
  2. 經過設置devServer.inline切換兩種模式,默認爲inline模式。
  3. 當使用HMR功能時,推薦使用inline mode

9. 模式

參考-官網

記住,只設置 NODE_ENV,則不會自動設置 mode

9.1 用法

只在配置中提供 mode 選項:

module.exports = {
  mode: 'production'
};
複製代碼

或者從 CLI 參數中傳遞:

webpack --mode=production
複製代碼

9.2 production

會將 process.env.NODE_ENV 的值設爲 production。啓用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin.

mode: production

// webpack.production.config.js
module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    new webpack.NoEmitOnErrorsPlugin()
-  ]
}
複製代碼

9.3 development

會將 process.env.NODE_ENV 的值設爲 development。啓用 NamedChunksPluginNamedModulesPlugin

mode: development

// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
複製代碼

10. output

10.1 output.library

對於用途普遍的 library,咱們但願它可以兼容不一樣的環境,例如 CommonJS,AMD,Node.js 或者做爲一個全局變量。爲了讓你的 library 可以在各類用戶環境(consumption)中可用,須要在 output 中添加 library 屬性。

爲了讓 library 和其餘環境兼容,還須要在配置文件中添加 libraryTarget 屬性。這是能夠控制 library 如何以不一樣方式暴露的選項,output.libraryTarget 的默認選項是 var

output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'webpack-numbers.js',
      library: 'webpackNumbers'
      library: 'webpackNumbers',
      libraryTarget: 'umd'
    },
複製代碼

10.2 output.publicPath 和 devServer.publicPath

output.publicPath 和 devServer.publicPath 的區別

devServer.publicPath 的意義就是決定外部能以怎樣的路徑經過 devServer來訪問構建在內存中的文件,這個字段未顯式設定時,則會去沿用 output.publicPath 字段的顯式值(若是output.publicPath有值的話,不然就用本身的 default 值)。output.publicPath 的意義是用來爲構建的文件生成知足特定需求的前綴,並將這個前綴提供給須要的 resolver、plugin 或者其餘的配置字段

HtmlWebpackPlugin 中的filename 也會依賴於public.publicPath

參考博客-你必定能看懂的關於 devServer.publicPath、output.publicPath 和 output.path 的意義的闡述

10.3 output.path

這個字段只在 production 配置下有效,若是你去試一下的話,你會發如今 development 配置下,不管你給把它配置成什麼值(前提必須是一個合規的絕對地址),它都不會對你訪問開發時構建在內存中的文件產生影響,因此 development 配置下,直接忽略就行了。另外,它的 default 值是 `path.resolve(__dirname, './dist')

11. webpack.optimize.ModuleConcatenationPlugin

Webpack 3 的新功能:Scope Hoisting

過去 webpack 打包時的一個取捨是將 bundle 中各個模塊單獨***打包成閉包***。這些打包函數使你的 JavaScript 在瀏覽器中***處理的更慢***。相比之下,一些工具像 Closure Compiler 和 RollupJS 能夠提高(hoist)或者***預編譯全部模塊到一個閉包中***,提高你的代碼在瀏覽器中的執行速度。這個插件會在 webpack 中實現以上的預編譯功能。

12. devServer

devServer 構建的文件是在內存裏的,而非你電腦的磁盤上,可是若是內存中找不到想要的文件時,devServer 會根據文件的路徑嘗試去電腦的磁盤上找,若是這樣還找不到纔會 404

開發時在內存和 contentBase 下真實的磁盤路徑中存在着一樣文件名的文件,那麼 devServer 返回的是內存的那個

12.1 devServer.historyApiFallback

historyApiFallback: {
     rewrites: [
         { from: /.*/, to: path.posix.join(devConfig.assetsPublicPath, 'index.html') },
     ],
 },
複製代碼

當使用 HTML5 History API 時,任意的 404 響應均可能須要被替代爲 index.html。經過傳入如下啓用:

historyApiFallback: true
複製代碼

經過傳入一個對象,好比使用 rewrites 這個選項,此行爲可進一步地控制:

historyApiFallback: {
  rewrites: [
    { from: /^\/$/, to: '/views/landing.html' },
    { from: /^\/subpage/, to: '/views/subpage.html' },
    { from: /./, to: '/views/404.html' }
  ]
}
複製代碼

12.2 devServer.publicPath

決定外部可以以什麼樣的路徑訪問到構建的文件。

與 output.publicPath 的關係 [查看](#10.2 output.publicPath 和 devServer.publicPath)

13. VUE-CLI 中常見配置

參考-博客

13.1 .babelrc文件

這個文件放在根目錄下面設置轉碼規則的。例如要想在代碼中使用es6,就要在這個文件中配置"presets": ["es2015"]。在項目代碼中要使用jsx語法除了安裝babel-plugin-transform-vue-jsx插件以外,還要配置"plugins": ["transform-runtime", "transform-vue-jsx"]

13.2 .editorconfig文件

這個文件配置編輯器的編碼風格

EditorConfig 介紹-博客

13.3 .eslintrc

參考-博客

配置 ESLint

能夠經過如下三種方式配置 ESLint:

  • 使用 .eslintrc 文件(支持 JSON 和 YAML 兩種語法);
  • 在 package.json 中添加 eslintConfig 配置塊;
  • 直接在代碼文件中定義。

.eslintrc 文件示例:

{
  "env": {
    "browser": true,
  },
  "globals": {
    "angular": true,
  },
  "rules": {
    "camelcase": 2,
    "curly": 2,
    "brace-style": [2, "1tbs"],
    "quotes": [2, "single"],
    "semi": [2, "always"],
    "space-in-brackets": [2, "never"],
    "space-infix-ops": 2,
  }
}
複製代碼

放在項目根目錄,則會應用到整個項目;若是子目錄中也包含 .eslintrc 文件,則子目錄會忽略根目錄的配置文件,應用該目錄中的配置文件。這樣能夠方便地對不一樣環境的代碼應用不一樣的規則。

13.4 .eslintignore文件

想要引入三方js庫,可是這些庫不符合eslint規範,能夠在這個文件裏忽略掉,例如:

build/*.js
config/*.js
static
複製代碼

13.5 .gitignore文件

這個文件用於配置不須要加入版本管理的文件,例如:

.DS_Store
node_modules/
npm-debug.log
test/unit/coverage
test/e2e/reports
selenium-debug.log
.idea
/clear
/src/modules/cache.js
複製代碼

13.6 .browserslist

參考-博客

npm地址-官網

在不一樣前端工具之間共享目標瀏覽器和Node.js版本的配置。

使用方法

(1) package.json (推薦)

{
  "browserslist": [
    "last 1 version",
    "> 1%",
    "maintained node versions",
    "not dead"
  ]
}
複製代碼

(2) .browserslistrc

# Browsers that we support

last 1 version
> 1%
maintained node versions
not dead
複製代碼

Browserslist 的數據都是來自Can I Use的。若是你想知道配置語句的查詢結果可使用online demo

13.7 .postcssrc.js

參考-官網

只是多種配置方式的一種

module.exports = {
  "plugins": {
    "postcss-import": {},
    "postcss-url": {},
    // to edit target browsers: use "browserslist" field in package.json
    "autoprefixer": {}
  }
}
複製代碼

14. eslint

參考-中文官網

15. watch 和 watchOption

參考-webpack

webpack-dev-server 和 webpack-dev-middleware 裏 Watch 模式默認開啓。

16. SplitChunksPlugin

參考1-webpack-英文

參考2-博客-中文

默認配置便是咱們推薦的web最佳實踐,可是你項目的最佳策略根據項目類型可能會有所不一樣

默認將全部來源於node_modules的模塊分配到叫作venders的緩存組,全部引用超過兩次的模塊分配到default緩存組.

相關文章
相關標籤/搜索