Webpack入門以及打包優化

十月梔發表於2020-02-29

WEBPACK

原文連結及程式碼檢視請進入github 如果喜歡,請動動您可愛的小手點亮star--- ^.^

一、從0搭建自己的webpack開發環境

1.什麼是Webpack
  • 靜態模組打包器
  • 功能:
    • 程式碼轉換;
    • 檔案優化;在生產環境不會壓縮JS、CSS....
    • 程式碼分割;提取多個頁面的公共程式碼,提取首屏不需要執行部分讓其非同步載入
    • 模組合併;模組化的專案裡會有多個模組和檔案,需要構建功能把模組分類合併成一個檔案
    • 自動重新整理;監聽本地更改並重新整理頁面
    • 程式碼校驗;提交到git倉庫前校驗程式碼
    • 自動釋出;自動構建線上釋出程式碼並傳輸給釋出系統
  • webpack命令:
    • 檢視版本號:npx webpack -v
    • 安裝指定版本:webpack@3.12.0 webpack-cli
    • 開啟檔案監聽模式:webpack --watch (消耗效能,如果想提升開發速度,完全可以使用webpack-dev-server)
2.初始化專案
  • npm init -y // 生成package.json檔案
  • npm install webpack webpack-cli --save-dev // 生成node_modules資料夾
  • webpack-cli --mode 可以解析傳遞引數
3.Webpack快速上手
  • 打包:
    • webpack webpack-cli // 預設讀取根目錄下的src資料夾
    • npx webpack
  • 開發環境development && 生產環境 production;可以在package.json中進行指令碼配置
  • 打包入口和出口的個性化配置,webpack.config.js
  • 配置拆分:通過引數判斷當前環境,載入指定配置檔案;
    • 合併配置檔案:npm install webpack-merge
  • 生產環境預設打包配置

小記

  • hash命名檔案在webpack中的幾個區別:
    • hash:每次打包都會更改檔名,
    • chunkhash:每個入口對應chunk,會根據入口檔案中的更改內容決定獨立打包某個入口所對應的檔案;
    • contenthash:根據檔案內容是否變化來決定是否打包該檔案;
  • mode取值,會將process.evn.NODE_ENV的值設定為production || development [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-r3w4L8pB-1582959864761)(./static/process.env.png)]
4.Webpack-dev-server

啟動本地服務,使用webpack-dev-server,npm install webpack-dev-server在記憶體中打包,不會產生實體檔案; devServer配置;

5.打包html外掛

使用html-webpack-plugin自動生成html檔案並且引入打包後的js內容;

6.清空打包結果

使用clean-webpack-plugin ,在每次打包之前都清除dist檔案下的目錄;

二、 Webpack中必須要掌握的配置

  1. 前言:webpack預設配置(零配置),非常弱,靈活性差,所以需要掌握一些配置;
  2. 開發相關:
    •  sourceMap:原始碼與打包後的程式碼的對映關係,通過sourceMap定位到原始碼;在dev模式中,預設開啟,[devtool](https://webpack.js.org/configuration/devtool/),線上不推薦開啟;
      複製程式碼
    • WebpackDevServer:
      • 作用:提升開發效率的利器,每次改完程式碼都需要重新打包一次,開啟瀏覽器,重新整理一次,很麻煩。我們可以安裝webpack-dev-server;
      • 原理:啟動服務後,會發現dist目錄沒有了,這是因為devServer把打包後的模組不會放在dist目錄下,而是放在記憶體中
      • 配置:通過devServer選項指定埠號(port)、內容存放目錄(contentBase)、本地代理配置(proxy)等等...
  3. 解析CSS :需要強調一下loader的執行順序,預設是從下往上執行,從右邊向左邊
    • css-loader:解析css語法
    • style-loader:將解析的css變成style標籤,插入到頁面中
  4. css前處理器 .scss node-sass sass-loader .less less-loader ...
    • 安裝:npm install node-sass sass-loader;
    • 配置:rules
// 注意在a.css檔案中再通過@import引入a.sass檔案的配置方式
use: ['style-loader', {
    loader: 'css-loader',
    options: { // 給loader傳遞引數
        importLoader: 1 // 代表後面引數: sass-loader
    }
}, 'sass-loader']
複製程式碼
  1. css樣式相容自動填充字首 附:檢視css樣式相容性的網址

    • postcss-loader ,查詢有相容性要求的css屬性
    • autoprefixer,自動填充ms-|| webpack-...字首
    • 配置:
    {
        test: /\.css$/,
        use: [
            'style-loader'',
            'css-loader',
            'sass-loader',
            {
                loader: 'postcss-loader',
                options: { // 給loader傳遞引數
                    plugins: () => [
                        require('autoprefixer')({
                            overrideBrowserslist: ["last 2 versions", ">1%"]
                        })
                    ]
                }
            }
        ]
    }
    複製程式碼
    • mini-css-extract-plugin, 抽離css樣式檔案,抽離的好處是 css檔案可以和js並行載入
  2. 解析圖片+icon

    • file-loader,配置圖片格式匹配
    {
        test: /\.(jpe?g|png|gif)$/,
        use:'file-loader'
    }
    複製程式碼
  3. js相關

    • @babel/core @babel/preset-env babel-loader,

      • 用法:babel-loader是webpack與babel通訊的橋樑(不會把es6轉es5) @bebel-preset-env負責es6->es5,
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
          loader: 'babel-loader',
          options: {
              presets: ["@babel/preset-env"]
          }
      }
      複製程式碼
      • @babel/polyfill的使用: 在入口檔案index.js中import
      import "@babel/polyfill"
      複製程式碼

      但是會導致bundle.js非常龐大,所以我們希望按需引入,useBuiltIns選項是babel7的新功能,告訴babel如何配置@babel/polyfill,具體配置見/root/.babelrc 小記 當我們開發元件庫時、工具庫時,polyfill就不適合了,因為polyfill是注入到全域性變數window下,會汙染全域性環境;開發元件庫時,推薦閉包方式:@babel/plugin-transform-runtime

      • 避免js程式碼 重用:@babel/plugin-transform-runtime
      • ts配置:@babel-preset-typescript
      type State = Readonly<typeof initState> // 把initState中的屬性拿出來變成只讀的
      複製程式碼
    • terser-webpack-plugin,壓縮js檔案

  4. react+vue...

  5. 多入口配置 實踐:入口配置為物件,出口配置多個HTMLWebpackPlugin,通過 chunks 屬性定義好對應的入口檔案

三、 Webpack打包優化(打包大小、打包速度、模組拆分)

1、壓縮+刪除無用程式碼;
2、Tree-shaking(webpack自帶) && Scope-hoistiong
  • Tree-shaking
    • 作用:去除掉js無用程式碼;
    • 適用範圍:預設只支援 es6語法,靜態匯入,只在生產環境使用;
    • 配置:
    optimization: {
        usedExports: true
    }
    複製程式碼
    • 需要注意的是:通過import引入的可執行檔案程式碼,但是並未真實使用,需要在package.json中配置:"sideEffects": true, l(注意該種辦法的副作用:如果引入css檔案:import 'a.css',也會被去除),可以根據需要指定檔案型別:
      "sideEffects": [
        "**/*.css" // glob語法
      ]
    複製程式碼
  • Scope-hoistiong(自帶)
    • 作用:由於webpack打包的每個模組都會生成一個函式,會導致記憶體過大,所以,引入scope-hoistiong,作用域提升,減少作用域
3、DllPlugin && DllReferencePlugin
  • DllPlugin 動態連結庫 某種方法實現了拆分 bundles,同時還大大提升了構建的速度(對專案執行優化沒有幫助)
    • 打包第三方庫
    • 配置:/root/build/webpack.dll.js 注:可以通過指定libraryTarget 來決定匯出方式(匯出方式即圖中所示) [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-YHjWWGjk-1582959864764)(./static/library_result.png)]
  • DllReferencePlugin 在專案中可以找到 上一步打包好的dll中的指定檔案;
        new DllReferencePlugin({
        manifest: path.resolve(__dirname, '../dll/mainfest.json')
        })
    複製程式碼
4、程式碼分割
  • 程式碼分割:即第三方庫抽離,不同於dll這個是做快取:生產環境下,自動將第三方庫進行抽離:optimization.splitchunks
  • 配置:/root/util/webpack.base.js -> optimization.splitChunks,可以通過引數指定什麼情況下自動分割程式碼,

DllPlugin與Optimization.splitChunks的區別

區別比較 是否優化頁面載入速度? 執行時機 建議使用場景
DllPlugin 構建之前抽離 開發環境提升打包速度
Optimization.splitChunks 編譯過程中抽離 生產環境分割第三方程式碼
5、動態載入;
  • 草案語法:import()
    • 使用:動態匯入,可以實現程式碼分割,應用在類比、路由懶載入...;
    • 原理:JSONP;
    • 語法:返回值為Promise物件;
  • 為動態載入的檔案更改檔名的配置:chunkFilename + 魔術字串
6、熱更新(模組熱替換Hot Module Replacement);
  • 定義:模組熱替換是Webpack提供的最有用的功能之一,它允許在執行時替換、新增、刪除各種模組,而無需進行完全重新整理重新載入整個頁面;瞭解更多點選進入官網
  • 實現:
    • 保留在完全重新載入頁面時丟失的應用程式的狀態;
    • 只更新改變內容,節省開發時間;
    • 調整樣式更加快速,幾乎等同於在瀏覽器偵錯程式中更改樣式;
  • 配置:
    devServer: {
        hot: true
    }
    new webpack.NamedModulesPlugin()
    複製程式碼
  • 讓js支援熱更新:
    import sum from './sum'
    console.log(sum(1, 2))
    if (module.hot) { // 判斷是否支援熱更新
        module.hot.accept() // 當入口檔案變化後重新執行當前入口檔案,原理是監聽到變化後,刪除dom再重新將新的新增到文件中;
    }
    複製程式碼
    如果在專案中使用,不用單獨配置,配置框架loader即可,
7、happypack;

happypack多執行緒打包,將不同的邏輯交給不同的執行緒來處理

8、CDN載入檔案;
  • 意義:webpack打包出來的都會放到bundle.js(出口檔案)中,bundle.js會非常龐大,所以我們引入CDN,拆分bundle.js
  • 使用:bootcnd,找到外掛,複製script標籤,貼上進模板檔案中,但是當檔案較多時,不能都在index.html中引入,所以可以使用 add-asset-html-cdn-webpack-plugin 外掛
    plugins: [
        new AddCdnPlugin(true, {
            'jquery': 'https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js'
        })
    ]
    複製程式碼
  • 配置:宣告外部檔案
    externals: {
        'jquery': '$' // 引入外部變數,在使用$時,是從外部引入的jq,不去打包程式碼中的jquery
    }
    複製程式碼
9、IgnorePlugin;

忽略import和require語法

10、noParse;

module.noParse,對類似jq這類依賴庫,內部不會引用其他庫,我們在打包的時候沒有必要去解析,這樣能夠增加打包速率

noParse: /jquery/
複製程式碼
11、resolve;
resolve: {
    extensions: [".js", ".jsx", ".json", ".css"],
    alias: {},
    modules: ['node_modules']
}
複製程式碼
12、include/exclude;

在使用loader 時,可以指定哪些檔案不通過loader,或者指定哪些檔案通過loader

13、打包檔案分析工具

四、原理

  1. 簡單實現一個檔案匯入,程式碼轉換:見/root/util/bundle.js
  2. 簡單實現一個loader 官網描述
  3. 簡單編寫一個plugins 官網描述 外掛是可以作用在webpack打包的整個生命週期中,所以需要了解compiler鉤子compilation鉤子

相關文章