webpack4.0學習筆記(2)

優化配置

1、HMR

HMR:hot module replacement 熱模塊替換
作用:一個模塊發生變化,只會重新打包這一個模塊(而不是打包所有模塊),極大提升構建速度。
樣式文件:可以使用HMR功能,因爲style-loader內部實現了。
JS文件:默認不能使用,需要修改JS代碼,添加支持HMR功能的代碼。
注意:HMR功能對js的處理,只能處理非入口js文件的其他文件。
html文件: 默認不能使用HMR功能.同時會導致問題:html文件不能熱更新了~ (不用做HMR功能)
解決:修改entry入口,將html文件引入

配置hot:true

 devServer: {
    // 項目構建後的路徑
    contentBase: resolve(__dirname, 'build'),
    // 啓動gzip壓縮
    compress: true,
    port: 3000, // 端口號
    open: true, // 自動打開瀏覽器
    hot:true
  }

npx webpack-dev-server啓動。

2、source-map

source-map: 一種 提供源代碼到構建後代碼映射 技術 (如果構建後代碼出錯了,通過映射可以追蹤源代碼錯誤)

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

source-map:外部
  錯誤代碼準確信息 和 源代碼的錯誤位置
inline-source-map:內聯
  只生成一個內聯source-map
  錯誤代碼準確信息 和 源代碼的錯誤位置
hidden-source-map:外部
  錯誤代碼錯誤原因,但是沒有錯誤位置
  不能追蹤源代碼錯誤,只能提示到構建後代碼的錯誤位置
eval-source-map:內聯
  每一個文件都生成對應的source-map,都在eval
  錯誤代碼準確信息 和 源代碼的錯誤位置
nosources-source-map:外部
  錯誤代碼準確信息, 但是沒有任何源代碼信息
cheap-source-map:外部
  錯誤代碼準確信息 和 源代碼的錯誤位置 
  只能精確的行
cheap-module-source-map:外部
  錯誤代碼準確信息 和 源代碼的錯誤位置 
  module會將loader的source map加入

內聯 和 外部的區別:1. 外部生成了文件,內聯沒有 2. 內聯構建速度更快

開發環境:速度快,調試更友好
  速度快(eval>inline>cheap>...)
    eval-cheap-souce-map
    eval-source-map
  調試更友好  
    souce-map
    cheap-module-souce-map
    cheap-souce-map

  --> eval-source-map  / eval-cheap-module-souce-map

生產環境:源代碼要不要隱藏? 調試要不要更友好
  內聯會讓代碼體積變大,所以在生產環境不用內聯
  nosources-source-map 全部隱藏
  hidden-source-map 只隱藏源代碼,會提示構建後代碼錯誤信息
  --> source-map / cheap-module-souce-map
 devServer: {
    // 項目構建後的路徑
    contentBase: resolve(__dirname, 'build'),
    // 啓動gzip壓縮
    compress: true,
    port: 3000, // 端口號
    open: true, // 自動打開瀏覽器
    hot:true
  },
  devtool:'eval-source-map'

3.oneOf

 {
 		// 以下loader只會匹配1個
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader],
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader'],
          }
        ]
      },

4、緩存

babel緩存
  cacheDirectory: true
  --> 讓第二次打包構建速度更快
文件資源緩存
  1、hash: 每次wepack構建時會生成一個唯一的hash值。
    問題: 因爲js和css同時使用一個hash值。
      如果重新打包,會導致所有緩存失效。(可能我卻只改動一個文件)
  2、chunkhash:根據chunk生成的hash值。如果打包來源於同一個chunk,那麼hash值就一樣
    問題: js和css的hash值還是一樣的
      因爲css是在js中被引入的,所以同屬於一個chunk
 3、 contenthash: 根據文件的內容生成hash值。不同文件hash值一定不一樣    
  --> 讓代碼上線運行緩存更好使用

在這裏插入圖片描述

// 服務端設置緩存
const express = require('express');

const app = express();
// express.static向外暴露靜態資源
// maxAge 資源緩存的最大時間,單位ms
app.use(express.static('build', { maxAge: 1000 * 3600 }));

app.listen(3000);

5、tree shaking

tree shaking:去除無用代碼
前提:1. 必須使用ES6模塊化 2. 開啓production環境
作用: 減少代碼體積

在package.json中配置 
  "sideEffects": false 所有代碼都沒有副作用(都可以進行tree shaking)
    問題:可能會把css / @babel/polyfill (副作用)文件幹掉
  "sideEffects": ["*.css", "*.less"]

6、code split

多入口,多個文件輸出

 entry:{
    index:'./src/index.js',
    test:'./src/test.js',
  },
  output: {
    filename: './[name].[contenthash:8].js', // 輸出文件名
    path: resolve(__dirname, 'build'), // 輸出文件路徑
  },

在這裏插入圖片描述
可以將node_modules中代碼單獨打包一個chunk最終輸出。
自動分析多入口chunk中,有沒有公共的文件,如果有會打包成一個單獨的chunk

  optimization:{
    splitChunks:{
      chunks:'all'
    }
  },

7、lazy loading

8、pwa

下載插件

npm i workbox-webpack-plugin -D

PWA: 漸進式網絡開發應用程序(離線可訪問)
workbox --> workbox-webpack-plugin

 new WorkboxWebpackPlugin.GenerateSW({
  /*
        1. 幫助serviceworker快速啓動
        2. 刪除舊的 serviceworker

        生成一個 serviceworker 配置文件~
      */
      clientsClaim:true,
      skipWaiting:true
    })

在這裏插入圖片描述

9、多進程打包

下載插件

npm i thread-loader -D
  {
        test:/\.js$/,
        exclude:/node_modules/,
        use:[
           /* 
                開啓多進程打包。 
                進程啓動大概爲600ms,進程通信也有開銷。
                只有工作消耗時間比較長,才需要多進程打包
              */
          {
            loader:'thread-loader',
            options:{
              workers:2
            }
          }
        ]
      },

10、externals

 externals:{
    // 拒絕jQuery被打包進來
    jquery:'jQuery'
  },

11、dll

 // 告訴webpack哪些庫不參與打包,同時使用時的名稱也得變~
    new webpack.DllReferencePlugin({
      manifest:resolve(__dirname,'dll/manifest.json')
    }),

webpack配置

1、entry

entry: 入口起點
1. string --> ‘./src/index.js’
單入口
打包形成一個chunk。 輸出一個bundle文件。
此時chunk的名稱默認是 main
2. array --> [’./src/index.js’, ‘./src/add.js’]
多入口
所有入口文件最終只會形成一個chunk, 輸出出去只有一個bundle文件。
–> 只有在HMR功能中讓html熱更新生效~
3. object
多入口
有幾個入口文件就形成幾個chunk,輸出幾個bundle文件
此時chunk的名稱是 key

  --> 特殊用法
    {
      // 所有入口文件最終只會形成一個chunk, 輸出出去只有一個bundle文件。
      index: ['./src/index.js', './src/count.js'], 
      // 形成一個chunk,輸出一個bundle文件。
      add: './src/add.js'
    }

2、output

output: {
    // 文件名稱(指定名稱+目錄)
    filename: 'js/[name].js',
    // 輸出文件目錄(將來所有資源輸出的公共目錄)
    path: resolve(__dirname, 'build'),
    // 所有資源引入公共路徑前綴 --> 'imgs/a.jpg' --> '/imgs/a.jpg'
    publicPath: '/',
    chunkFilename: 'js/[name]_chunk.js', // 非入口chunk的名稱
    // library: '[name]', // 整個庫向外暴露的變量名
    // libraryTarget: 'window' // 變量名添加到哪個上 browser
    // libraryTarget: 'global' // 變量名添加到哪個上 node
    // libraryTarget: 'commonjs'
  },

3、module

module: {
    rules: [
      // loader的配置
      {
        test: /\.css$/,
        // 多個loader用use
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.js$/,
        // 排除node_modules下的js文件
        exclude: /node_modules/,
        // 只檢查 src 下的js文件
        include: resolve(__dirname, 'src'),
        // 優先執行
        enforce: 'pre',
        // 延後執行
        // enforce: 'post',
        // 單個loader用loader
        loader: 'eslint-loader',
        options: {}
      },
      {
        // 以下配置只會生效一個
        oneOf: []
      }
    ]
  },

4、resolve

// 解析模塊的規則
  resolve: {
    // 配置解析模塊路徑別名: 優點簡寫路徑 缺點路徑沒有提示
    alias: {
      $css: resolve(__dirname, 'src/css')
    },
    // 配置省略文件路徑的後綴名
    extensions: ['.js', '.json', '.jsx', '.css'],
    // 告訴 webpack 解析模塊是去找哪個目錄
    modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
  }

5、dev server

devServer: {
    // 運行代碼的目錄
    contentBase: resolve(__dirname, 'build'),
    // 監視 contentBase 目錄下的所有文件,一旦文件變化就會 reload
    watchContentBase: true,
    watchOptions: {
      // 忽略文件
      ignored: /node_modules/
    },
    // 啓動gzip壓縮
    compress: true,
    // 端口號
    port: 5000,
    // 域名
    host: 'localhost',
    // 自動打開瀏覽器
    open: true,
    // 開啓HMR功能
    hot: true,
    // 不要顯示啓動服務器日誌信息
    clientLogLevel: 'none',
    // 除了一些基本啓動信息以外,其他內容都不要顯示
    quiet: true,
    // 如果出錯了,不要全屏提示~
    overlay: false,
    // 服務器代理 --> 解決開發環境跨域問題
    proxy: {
      // 一旦devServer(5000)服務器接受到 /api/xxx 的請求,就會把請求轉發到另外一個服務器(3000)
      '/api': {
        target: 'http://localhost:3000',
        // 發送請求時,請求路徑重寫:將 /api/xxx --> /xxx (去掉/api)
        pathRewrite: {
          '^/api': ''
        }
      }
    }

6、optimization

 optimization: {
    splitChunks: {
      chunks: 'all'
      // 默認值,可以不寫~
      /* minSize: 30 * 1024, // 分割的chunk最小爲30kb
      maxSiza: 0, // 最大沒有限制
      minChunks: 1, // 要提取的chunk最少被引用1次
      maxAsyncRequests: 5, // 按需加載時並行加載的文件的最大數量
      maxInitialRequests: 3, // 入口js文件最大並行請求數量
      automaticNameDelimiter: '~', // 名稱連接符
      name: true, // 可以使用命名規則
      cacheGroups: {
        // 分割chunk的組
        // node_modules文件會被打包到 vendors 組的chunk中。--> vendors~xxx.js
        // 滿足上面的公共規則,如:大小超過30kb,至少被引用一次。
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          // 優先級
          priority: -10
        },
        default: {
          // 要提取的chunk最少被引用2次
          minChunks: 2,
          // 優先級
          priority: -20,
          // 如果當前要打包的模塊,和之前已經被提取的模塊是同一個,就會複用,而不是重新打包模塊
          reuseExistingChunk: true
        } 
      }*/
    },
    // 將當前模塊的記錄其他模塊的hash單獨打包爲一個文件 runtime
    // 解決:修改a文件導致b文件的contenthash變化
    runtimeChunk: {
      name: entrypoint => `runtime-${entrypoint.name}`
    },
    minimizer: [
      // 配置生產環境的壓縮方案:js和css
      new TerserWebpackPlugin({
        // 開啓緩存
        cache: true,
        // 開啓多進程打包
        parallel: true,
        // 啓動source-map
        sourceMap: true
      })
    ]
  }

webpack5

此版本重點關注以下內容:

  • 通過持久緩存提高構建性能.
  • 使用更好的算法和默認值來改善長期緩存.
  • 通過更好的樹搖和代碼生成來改善捆綁包大小.
  • 清除處於怪異狀態的內部結構,同時在 v4 中實現功能而不引入任何重大更改.
  • 通過引入重大更改來爲將來的功能做準備,以使我們能夠儘可能長時間地使用 v5.

下載

  • npm i webpack@next webpack-cli -D

自動刪除 Node.js Polyfills

早期,webpack 的目標是允許在瀏覽器中運行大多數 node.js 模塊,但是模塊格局發生了變化,許多模塊用途現在主要是爲前端目的而編寫的。webpack <= 4 附帶了許多 node.js 核心模塊的 polyfill,一旦模塊使用任何核心模塊(即 crypto 模塊),這些模塊就會自動應用。

儘管這使使用爲 node.js 編寫的模塊變得容易,但它會將這些巨大的 polyfill 添加到包中。在許多情況下,這些 polyfill 是不必要的。

webpack 5 會自動停止填充這些核心模塊,並專注於與前端兼容的模塊。

遷移:

  • 儘可能嘗試使用與前端兼容的模塊。
  • 可以爲 node.js 核心模塊手動添加一個 polyfill。錯誤消息將提示如何實現該目標。

Chunk 和模塊 ID

添加了用於長期緩存的新算法。在生產模式下默認情況下啓用這些功能。

chunkIds: "deterministic", moduleIds: "deterministic"

Chunk ID

你可以不用使用 import(/* webpackChunkName: "name" */ "module") 在開發環境來爲 chunk 命名,生產環境還是有必要的

webpack 內部有 chunk 命名規則,不再是以 id(0, 1, 2)命名了

Tree Shaking

  1. webpack 現在能夠處理對嵌套模塊的 tree shaking
// inner.js
export const a = 1;
export const b = 2;

// module.js
import * as inner from './inner';
export { inner };

// user.js
import * as module from './module';
console.log(module.inner.a);

在生產環境中, inner 模塊暴露的 b 會被刪除

  1. webpack 現在能夠多個模塊之前的關係
import { something } from './something';

function usingSomething() {
  return something;
}

export function test() {
  return usingSomething();
}

當設置了"sideEffects": false時,一旦發現test方法沒有使用,不但刪除test,還會刪除"./something"

  1. webpack 現在能處理對 Commonjs 的 tree shaking

Output

webpack 4 默認只能輸出 ES5 代碼

webpack 5 開始新增一個屬性 output.ecmaVersion, 可以生成 ES5 和 ES6 / ES2015 代碼.

如:output.ecmaVersion: 2015

SplitChunk

// webpack4
minSize: 30000;
// webpack5
minSize: {
  javascript: 30000,
  style: 50000,
}

Caching

// 配置緩存
cache: {
  // 磁盤存儲
  type: "filesystem",
  buildDependencies: {
    // 當配置修改時,緩存失效
    config: [__filename]
  }
}

緩存將存儲到 node_modules/.cache/webpack

監視輸出文件

之前 webpack 總是在第一次構建時輸出全部文件,但是監視重新構建時會只更新修改的文件。

此次更新在第一次構建時會找到輸出文件看是否有變化,從而決定要不要輸出全部文件。

默認值

  • entry: "./src/index.js
  • output.path: path.resolve(__dirname, "dist")
  • output.filename: "[name].js"

更多內容

more webpack5

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章