webpack配置之代碼優化

来源:https://www.cnblogs.com/xiaohuochai/archive/2018/03/01/8489602.html
-Advertisement-
Play Games

[1]打包公共代碼 [2]動態導入 [3]懶載入 [4]剔除無用代碼 [5]長緩存優化 [6]公用代碼內聯 ...


前面的話

  前面介紹了webpack的基本配置,本文將詳細介紹webpack中關於代碼優化的配置

 

打包公共代碼

  CommonsChunkPlugin 插件,是一個可選的用於建立一個獨立文件(又稱作 chunk)的功能,這個文件包括多個入口 chunk 的公共模塊。通過將公共模塊拆出來,最終合成的文件能夠在最開始的時候載入一次,便存到緩存中供後續使用。這會帶來速度上的提升,因為瀏覽器會迅速將公共的代碼從緩存中取出來,而不是每次訪問一個新頁面時,再去載入一個更大的文件

new webpack.optimize.CommonsChunkPlugin(options)

【配置項】

{
  name: string, // or
  names: string[],
  // common chunk 的名稱
filename: string, // common chunk 的文件名模板。可以包含與 `output.filename` 相同的占位符 minChunks: number|Infinity|function(module, count) -> boolean, // 在傳入公共chunk(commons chunk) 之前所需要包含的最少數量的 chunks 。 // 數量必須大於等於2,或者少於等於 chunks的數量 chunks: string[], // 通過 chunk name 去選擇 chunks 的來源。chunk 必須是 公共chunk 的子模塊。
children: boolean, // 如果設置為 `true`,所有公共chunk 的子模塊都會被選擇 deepChildren: boolean, // If `true` all descendants of the commons chunk are selected async: boolean|string, // 如果設置為 `true`,一個非同步的公共chunk 會作為 `options.name` 的子模塊,和 `options.chunks` 的兄弟模塊被創建。 minSize: number, // 在 公共chunk 被創建立之前,所有公共模塊 (common module) 的最少大小。 }

【提取公共代碼】

new webpack.optimize.CommonsChunkPlugin({
  name: "commons",
  // ( 公共chunk(commnons chunk) 的名稱)

  filename: "commons.js",
  // ( 公共chunk 的文件名)
})

【明確第三方庫chunk】

entry: {
  vendor: ["jquery", "other-lib"],
  app: "./entry"
},
plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: "vendor",
    minChunks: Infinity,
  })
]

【將公共模塊打包進父 chunk】

new webpack.optimize.CommonsChunkPlugin({
  children: true,
})

【額外的非同步公共chunk】

new webpack.optimize.CommonsChunkPlugin({
  name: "app",
  // or
  names: ["app", "subPageA"]
  children: true,
  async: true,
  minChunks: 3,
})

【wepack4】

  webpack 4 將移除 CommonsChunkPlugin, 取而代之的是兩個新的配置項 optimization.splitChunks 和 optimization.runtimeChunk

  通過設置 optimization.splitChunks.chunks: "all" 來啟動預設的代碼分割配置項

  當滿足如下條件時,webpack 會自動打包 chunks:

當前模塊是公共模塊(多處引用)或者模塊來自 node_modules
當前模塊大小大於 30kb
如果此模塊是按需載入,並行請求的最大數量小於等於 5
如果此模塊在初始頁面載入,並行請求的最大數量小於等於 3

  通過設置 optimization.runtimeChunk: true 來為每一個入口預設添加一個只包含 runtime 的 chunk

 

動態導入

  上面介紹的CommonsChunkPlugin可以去重和分離chunk。而本節介紹的動態導入,則是通過模塊的內聯函數調用來分離代碼

  webpack 提供了兩個類似的技術。對於動態導入,第一種,也是優先選擇的方式是,使用符合 ECMAScript 提案 的 import() 語法。第二種,則是使用 webpack 特定的 require.ensure

  下麵來使用import()語法來進行動態導入

  const path = require('path');
  const HTMLWebpackPlugin = require('html-webpack-plugin');

  module.exports = {
    entry: {
      index: './src/index.js'
    },
    plugins: [
      new HTMLWebpackPlugin({
        title: 'Code Splitting'
     })
    ],
    output: {
      filename: '[name].bundle.js',
      chunkFilename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };

  下麵來動態導入loadsh

 function getComponent() { 
 return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => { var element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; }).catch(error => 'An error occurred while loading the component'); } getComponent().then(component => { document.body.appendChild(component); })

  在註釋中使用了 webpackChunkName。這樣做會導致bundle 被命名為 lodash.bundle.js ,而不是 [id].bundle.js

 

懶載入

  懶載入或者按需載入,是一種很好的優化網頁或應用的方式。這種方式實際上是先把你的代碼在一些邏輯斷點處分離開,然後在一些代碼塊中完成某些操作後,立即引用或即將引用另外一些新的代碼塊。這樣加快了應用的初始載入速度,減輕了它的總體體積,因為某些代碼塊可能永遠不會被載入

  上面通過動態導入的loadsh確實會在腳本運行的時候產生一個分離的代碼塊 lodash.bundle.js ,在技術概念上“懶載入”它。問題是載入這個包並不需要用戶的交互 -- 意思是每次載入頁面的時候都會請求它

  下麵來增加一個交互,當用戶點擊按鈕的時候用 console 列印一些文字。但是會等到第一次交互的時候再載入那個代碼塊(print.js

//print.js
console.log('The print.js module has loaded! See the network tab in dev tools...');
export default () => {
  console.log('Button Clicked: Here\'s "some text"!');
}
//index.js
 import _ from 'lodash';
 function component() {
   var element = document.createElement('div');
   var button = document.createElement('button');
   var br = document.createElement('br');
   button.innerHTML = 'Click me and look at the console!';
   element.innerHTML = _.join(['Hello', 'webpack'], ' ');
   element.appendChild(br);
   element.appendChild(button);
   button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
     var print = module.default;
     print();
   });
    return element;
  }
 document.body.appendChild(component());

 

剔除無用代碼

  tree shaking 是一個術語,通常用於描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴於 ES2015 模塊系統中的靜態結構特性,例如 import 和 export。這個術語和概念實際上是興起於 ES2015 模塊打包工具 rollup

【JS】

  JS的tree shaking主要通過uglifyjs插件來完成

npm install --save-dev uglifyjs-webpack-plugin
const path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
 },
  plugins: [
   new UglifyJSPlugin()
  ]
};

【CSS】

  CSS的tree shaking主要通過purify CSS來實現的

npm i -D purifycss-webpack purify-css
const path = require('path');
const glob = require('glob');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PurifyCSSPlugin = require('purifycss-webpack');

module.exports = {
  entry: {...},
  output: {...},
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallbackLoader: 'style-loader',
          loader: 'css-loader'
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('[name].[contenthash].css'),
    // Make sure this is after ExtractTextPlugin!
    new PurifyCSSPlugin({
      // Give paths to parse for rules. These should be absolute!
      paths: glob.sync(path.join(__dirname, 'app/*.html')),
    })
  ]
};

  如果要設置多路徑,則需要將glob換成glob-all

const glob = require('glob-all');
paths: glob.sync([
  path.join(__dirname, '.php'),
  path.join(__dirname, 'partials/.php')
])

 

模塊熱更新

  模塊熱更新,又稱為模塊熱替換,HMR(Hot Module Replacement)。在應用程式運行過程中替換、添加或刪除模塊,無需重新載入頁面,極大地加速了開發時間

  啟用此功能實際上相當簡單。而我們要做的,就是更新 webpack-dev-server 的配置,和使用 webpack 內置的 HMR 插件。此外,還添加了NamedModulesPlugin,以便更容易查看要修補(patch)的依賴

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  entry: {
     app: './src/index.js'
  },
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './dist',
    hot: true
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Hot Module Replacement'
    }),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

 

長緩存優化

【使用chunkhash】

  將hash替換為chunkhash,這樣當chunk不變時,緩存依然有效

const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Caching'
    })
  ],
  output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'dist')
  }
};

【提取模板】

  CommonsChunkPlugin 可以用於將模塊分離到單獨的文件中。還能夠在每次修改後的構建結果中,將 webpack 的樣板(boilerplate)和 manifest 提取出來。通過指定 entry 配置中未用到的名稱,此插件會自動將我們需要的內容提取到單獨的包中

const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Caching'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'
    })
  ],
  output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'dist')
  }
};

  將第三方庫(library)(例如 lodash 或 react)提取到單獨的 vendor chunk 文件中,是比較推薦的做法,這是因為,它們很少像本地的源代碼那樣頻繁修改。因此通過實現以上步驟,利用客戶端的長效緩存機制,可以通過命中緩存來消除請求,並減少向伺服器獲取資源,同時還能保證客戶端代碼和伺服器端代碼版本一致。這可以通過使用新的 entry(入口) 起點,以及再額外配置一個 CommonsChunkPlugin 實例的組合方式來實現

var path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: [
      'lodash'
    ]
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Caching'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'
    })
  ],
  output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'dist')
  }
};

  [註意]CommonsChunkPlugin 的 'vendor' 實例,必須在 'manifest' 實例之前引入

【使用Name而不是id】

  每個 module.id 會基於預設的解析順序(resolve order)進行增量。也就是說,當解析順序發生變化,ID 也會隨之改變

  下麵來使用兩個插件解決這個問題。第一個插件是 NamedModulesPlugin,將使用模塊的路徑,而不是數字標識符。雖然此插件有助於在開發過程中輸出結果的可讀性,然而執行時間會長一些。第二個選擇是使用 HashedModuleIdsPlugin,推薦用於生產環境構建

const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: [
      'lodash'
    ]
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Caching'
    }),
    new webpack.HashedModuleIdsPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'
    })
  ],
  output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'dist')
  }
};

 

公用代碼內聯

  使用html-webpack-inline-chunk-plugin插件將mainfest.js內聯到html文件中

$ npm install html-webpack-inline-chunk-plugin --save-dev
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineChunkWebpackPlugin = require('html-webpack-inline-chunk-plugin');

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: [
      'lodash'
    ]
  },
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      title: 'Caching',
      inlineSource: '.(js|css)$'
    }),
    new webpack.HashedModuleIdsPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'
    }),
    new InlineChunkWebpackPlugin({
        inlineChunks: ['manifest']
    })
  ],
  output: {
    filename: '[name].[chunkhash].js',
    path: path.resolve(__dirname, 'dist')
  }
};

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 2018年3月1日 農曆正月十四 星期四 不知怎麼地,一大早上班就想寫博客; Xcode代碼塊 開發中,都不想寫過多代碼,然後就會用這種方法,去簡化代碼,包括MVVM框架,它也體現出來了去簡化C裡面的那些垃圾代碼;其實在編寫時,Xcode本身也為我們提供了,提高編寫效率的捷徑-代碼塊,就是下麵 ...
  • 一、字體屬性 1.預設字體系列 chrome/opera:"宋體" firefox:"微軟雅黑" safari/IE:Times,"宋體" 2.字體屬性 字體類型 font-family 初始化時定義字體類型,如宋體 字體大小 font-size 應用於: 所有元素 繼承性: 有 百分數: 相對於父 ...
  • 1:閉包 1>概念:閉包就是能夠讀取其他函數內部變數的函數。在JS中,只有函數內部的子函數才能讀取局部變數,因此可以把閉包簡單理解為”定義在一個函數內部的函數”。 2>閉包的特點 1)可以讀取函數內部的變數。 2)讓這些變數的值始終保存在記憶體中。 3>閉包的原理 理解閉包,首先必須理解JS變數的作用 ...
  • 前面的話 使用Facebook官方推出的create-react-app腳手架,我們基本可以零配置搭建基於webpack的React開發環境。但是,如果需要個性化定製,則還需要基於create-react-app進行再配置 環境變數 在根目錄下新建.env.local文件,可以用於本地環境變數覆蓋 ...
  • 一、何為cookie 由於http協議是無狀態的,所以沒法知道當前訪問的客戶端是誰,所以有了cookie這個東西,通過cookie來讓服務端知道當前是誰訪問我,可以看做是一個身份牌 二、cookie的工作流程 (1) 第一次用戶登錄的時候,輸入用戶名和密碼信息,服務端接收後進行用戶認證。 (2)服務 ...
  • 一、水平居中: (1). 行內元素的水平居中? 如果被設置元素為文本、圖片等行內元素時,在父元素中設置text-align:center實現行內元素水平居中,將子元素的display設置為inline-block,使子元素變成行內元素 (2)塊狀元素的水平居中(定寬) 當被設置元素為定寬塊級元素時用 ...
  • 前言: 考慮自己網站的圖片展示,而且要支持移動端和PC端。自己寫的代碼也不盡如意,要寫好的話也需要時間,於是就想到了使用相關插件。 準備: PhotoSwipe 官網地址:http://photoswipe.com/ 英語還可以的同學可以看官方文檔學習:http://photoswipe.com/d ...
  • 數據流向 數據的改變發生通常是通過用戶交互行為或者瀏覽器行為(如路由跳轉等)觸發的,當此類行為會改變數據的時候可以通過 dispatch 發起一個 action,如果是同步行為會直接通過 Reducers 改變 State ,如果是非同步行為(副作用)會先觸發 Effects 然後流向 Reducer ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...