webpack單詞

qq_35647460發表於2020-12-31
字母解釋讀音
const常量kɒnst
path道路,路徑pɑːθ
require需要rɪˈkwaɪər
module模組;元件;模數ˈmɒdjuːl
exports出口商品eksport
entry入口ˈentri
mode模式məʊd
development
production
output輸出ˈaʊtpʊt
resolve決定 ,分解rɪˈzɒlv
__dirname目錄名
build構建bɪld
filename檔名ˈfaɪlneɪm
plugins外掛
config配置kən’fɪɡ
rules規則ruːlz
test: /.txt$/測試
template模板ˈtempleɪt
options選擇ˈɒpʃnz
limit限制ˈlɪmɪt
esModule: false,關閉url-loader的es6模組化,使用commonjs解析
name: ‘[hash:10].[ext]’[hash:10]取圖片的hash的前10位 [ext]取檔案原來副檔名
exclude排除ɪkˈskluːd
devServer啟動devServer指令為:npx webpack-dev-server
contentBase基於內容kɑntent beɪs
compress壓縮kəmˈpres
portpɔːt
outputPath: ‘imgs’輸出路徑
browserslist瀏覽器列表
collapseWhitespace移除空格kəˈlæps 倒塌 Whitespace空白
removeComments移除註釋rɪˈmuːv移動 kmens評論
minify壓縮html程式碼mɪnɪfaɪ
enforce: ‘pre’,優先執行ɪnˈfɔːs
hot: true開啟HMR功能
source-map一種 提供原始碼到構建後程式碼對映 技術 (如果構建後程式碼出錯了,通過對映可以追蹤原始碼錯誤)
oneOf:注意:不能有兩個配置處理同一種型別檔案
cacheDirectory: true開啟babel快取 第二次構建時,會讀取之前的快取
.then然後ðen
catch抓住kætʃ
reduce減少;降低;使處於;把…分解rɪˈdjuːs
externals拒絕jQuery被打包進來ɪkˈstɜːrnlz
html-webpack-plugin功能:預設會建立一個空的HTML,自動引入打包輸出的所有資源(JS/CSS) 需求:需要有結構的HTML檔案
webpack用於訪問內建外掛
mini-css-extract-plugin對輸出的css檔案進行重新命名 filename: ‘css/built.css’
MiniCssExtractPlugin.loader,這個loader取代style-loader。作用:提取js中的css成單獨檔案
optimize-css-assets-webpack-plugin壓縮css
process.env.NODE_ENV = ‘development’;設定nodejs環境變數
[name]:取檔名
    filename: 'js/[name].[contenthash:10].js',

24

document.getElementById('btn').onclick = function() {
  // 懶載入~:當檔案需要使用時才載入~
  // 預載入 prefetch:會在使用之前,提前載入js檔案 
  // 正常載入可以認為是並行載入(同一時間載入多個檔案)  
  // 預載入 prefetch:等其他資源載入完畢,瀏覽器空閒了,再偷偷載入資源
  import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
    console.log(mul(4, 5));
  });

25

const WorkboxWebpackPlugin = require('workbox-webpack-plugin');

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

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

        生成一個 serviceworker 配置檔案~
      */
      clientsClaim: true,
      skipWaiting: true
    })
test: /.less$/,
style-loader
css-loader
less-loader
test: /.(jpgpng
loader: ‘url-loader’,問題:預設處理不了html中img圖片 處理圖片資源
test: /.html$/,
loader: ‘html-loader’處理html檔案的img圖片(負責引入img,從而能被url-loader進行處理)
exclude: /.(css、js、html、less)$/, loader: ‘file-loader’, options: { name: ‘[hash:10].[ext]’// 排除css/js/html資源 // 打包其他資源(除了html/js/css資源以外的資源)
loader: ‘eslint-loader’,語法檢查12
loader: ‘babel-loader’,js相容性處理:babel-loader @babel/core

啟動devServer

// 開發伺服器 devServer:用來自動化(自動編譯,自動開啟瀏覽器,自動重新整理瀏覽器~~)
  // 特點:只會在記憶體中編譯打包,不會有任何輸出
  // 啟動devServer指令為:npx webpack-dev-server
  devServer: {
    // 專案構建後路徑
    contentBase: resolve(__dirname, 'build'),
    // 啟動gzip壓縮
    compress: true,
    // 埠號
    port: 3000,
    // 自動開啟瀏覽器
    open: true
css相容性處理:postcss --> postcss-loader postcss-preset-env

            幫postcss找到package.json中browserslist裡面的配置,通過配置載入指定的css相容性樣式

            "browserslist": {
              // 開發環境 --> 設定node環境變數:process.env.NODE_ENV = development
              "development": [
                "last 1 chrome version",
                "last 1 firefox version",
                "last 1 safari version"
              ],
              // 生產環境:預設是看生產環境
              "production": [
                ">0.2%",
                "not dead",
                "not op_mini all"
              ]
            }
          */
          // 使用loader的預設配置
          // 'postcss-loader',
          // 修改loader的配置
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                // postcss的外掛
                require('postcss-preset-env')()
              ]
            }

語法檢查

module: {
    rules: [
      /*
        語法檢查: eslint-loader  eslint
          注意:只檢查自己寫的原始碼,第三方的庫是不用檢查的
          設定檢查規則:
            package.json中eslintConfig中設定~
              "eslintConfig": {
                "extends": "airbnb-base"
              }
            airbnb --> eslint-config-airbnb-base  eslint-plugin-import eslint
      */
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          // 自動修復eslint的錯誤
          fix: true
        }
      }
    ]
  },

js相容性處理

module: {
    rules: [
      /*
        js相容性處理:babel-loader @babel/core 
          1. 基本js相容性處理 --> @babel/preset-env
            問題:只能轉換基本語法,如promise高階語法不能轉換
          2. 全部js相容性處理 --> @babel/polyfill  
            問題:我只要解決部分相容性問題,但是將所有相容性程式碼全部引入,體積太大了~
          3. 需要做相容性處理的就做:按需載入  --> core-js
      */  
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          // 預設:指示babel做怎麼樣的相容性處理
          presets: [
            [
              '@babel/preset-env',
              {
                // 按需載入
                useBuiltIns: 'usage',
                // 指定core-js版本
                corejs: {
                  version: 3
                },
                // 指定相容性做到哪個版本瀏覽器
                targets: {
                  chrome: '60',
                  firefox: '60',
                  ie: '9',
                  safari: '10',
                  edge: '17'
                }
              }
            ]
          ]
        }
      }
    ]
  },

壓縮html程式碼15

 plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      // 壓縮html程式碼
      minify: {
        // 移除空格
        collapseWhitespace: true,
        // 移除註釋
        removeComments: true
      }
    })
  ],

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

啟動伺服器指令

/*
  伺服器程式碼
  啟動伺服器指令:
    npm i nodemon -g
    nodemon server.js

    node server.js
  訪問伺服器地址:
    http://localhost:3000

*/
const express = require('express');

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

app.listen(3000);


const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

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

// 定義nodejs環境變數:決定使用browserslist的哪個環境
process.env.NODE_ENV = 'production';

// 複用loader
const commonCssLoader = [
  MiniCssExtractPlugin.loader,
  'css-loader',
  {
    // 還需要在package.json中定義browserslist
    loader: 'postcss-loader',
    options: {
      ident: 'postcss',
      plugins: () => [require('postcss-preset-env')()]
    }
  }
];

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.[contenthash:10].js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        // 在package.json中eslintConfig --> airbnb
        test: /\.js$/,
        exclude: /node_modules/,
        // 優先執行
        enforce: 'pre',
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      },
      {
        // 以下loader只會匹配一個
        // 注意:不能有兩個配置處理同一種型別檔案
        oneOf: [
          {
            test: /\.css$/,
            use: [...commonCssLoader]
          },
          {
            test: /\.less$/,
            use: [...commonCssLoader, 'less-loader']
          },
          /*
            正常來講,一個檔案只能被一個loader處理。
            當一個檔案要被多個loader處理,那麼一定要指定loader執行的先後順序:
              先執行eslint 在執行babel
          */
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            options: {
              presets: [
                [
                  '@babel/preset-env',
                  {
                    useBuiltIns: 'usage',
                    corejs: { version: 3 },
                    targets: {
                      chrome: '60',
                      firefox: '50'
                    }
                  }
                ]
              ],
              // 開啟babel快取
              // 第二次構建時,會讀取之前的快取
              cacheDirectory: true
            }
          },
          {
            test: /\.(jpg|png|gif)/,
            loader: 'url-loader',
            options: {
              limit: 8 * 1024,
              name: '[hash:10].[ext]',
              outputPath: 'imgs',
              esModule: false
            }
          },
          {
            test: /\.html$/,
            loader: 'html-loader'
          },
          {
            exclude: /\.(js|css|less|html|jpg|png|gif)/,
            loader: 'file-loader',
            options: {
              outputPath: 'media'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/built.[contenthash:10].css'
    }),
    new OptimizeCssAssetsWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  mode: 'production',
  devtool: 'source-map'
};

tree shaking:去除無用程式碼

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

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

多入口23-1

entry: {
    // 多入口:有一個入口,最終輸出就有一個bundle
    index: './src/js/index.js',
    test: './src/js/test.js'
  },

自動分析多入口chunk中23-2


    1. 可以將node_modules中程式碼單獨打包一個chunk最終輸出
    2. 自動分析多入口chunk中,有沒有公共的檔案。如果有會打包成單獨一個chunk
  */
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },

26多執行緒

1. eslint不認識 window、navigator全域性變數
    解決:需要修改package.json中eslintConfig配置
      "env": {
        "browser": true // 支援瀏覽器端全域性變數
      }
   2. sw程式碼必須執行在伺服器上
      --> nodejs
      -->
        npm i serve -g
        serve -s build 啟動伺服器,將build目錄下所有資源作為靜態資源暴露出去
*/
// 註冊serviceWorker
// 處理相容性問題
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker
      .register('/service-worker.js')
      .then(() => {
        console.log('sw註冊成功了~');
      })
      .catch(() => {
        console.log('sw註冊失敗了~');
      });
  });
 externals: {
    // 拒絕jQuery被打包進來
    jquery: 'jQuery'
  }

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'
        }



entry: {
    index: ['./src/index.js', './src/count.js'], 
    add: './src/add.js'
  },

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'
  },

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: []
      }
    ]
  },

resolve配置解析模組路徑別名

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

devServer執行程式碼的目錄

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': ''
        }
      }
    }
  }
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
      })
    ]
  }