webpack性能優化面面觀

前言

開發中,webpack文件通常分爲3個:css

  1. webpack.base.conf.js (基礎文件)
  2. webpack.dev.conf.js (開發環境使用的webpack,須要與webpack.base.conf.js結合使用)
  3. webpack.prod.conf.js(上線環境使用的webpack,須要與webpack.base.conf.js結合使用)

一.優化構建速度

webpack在啓動後,會根據Entry配置的入口,遞歸解析所依賴的文件。這個過程分爲搜索文件把匹配的文件進行分析、轉化的兩個過程,所以能夠從這兩個角度來進行優化配置。html

1.1 縮小文件的搜索範圍

搜索過程優化方式包括:

1. resolve字段告訴webpack怎麼去搜索文件,因此首先要重視resolve字段的配置:

參考文檔:webpack.docschina.org/configurati…node

resolve用來配置模塊如何解析。例如,當在 ES2015 中調用 import 'lodash'resolve 選項可以對webpack 查找'lodash' 的方式去作修改(查看模塊)。react

// webpack.config.js

module.exports = {
  //...
  resolve: {
    // configuration options
  }
};
複製代碼
module.export = {
  resolve: {
    modules:[path.resolve(__dirname, 'node_modules')]
    extensions: ['.js', '.jsx'],
    mainFiles: ['index', 'child'],
    alias: {
       '@/src': path.resolve(__dirname, `../src`),  // 當看到@/src這個路徑或字符串的時候,實際上指向的是../src目錄
    }
  }
}
複製代碼

(1). resolve.modules參考文檔:www.webpackjs.com/configurati…jquery

resolve.modules告訴webpack解析時應該搜索的目錄webpack

絕對路徑和相對路徑都能使用,可是要知道他們之間有一點差別。經過查看當前目錄以及祖先路徑(即 ./node_modules, ../node_modules 等等),相對路徑將相似於 Node 查找 'node_modules' 的方式進行查找。使用絕對路徑,將只在給定目錄中搜索git

// webpack.config.js

module.exports = {
  //...
  resolve: {
    modules: ['node_modules'] // 相對路徑寫法,會按./node_modules, ../node_modules的方式查找
  }
};
複製代碼

若是你想要添加一個目錄到模塊搜索目錄,此目錄優先於 node_modules/ 搜索:github

// webpack.config.js

module.exports = {
  //...
  resolve: {
    modules: [path.resolve(__dirname, 'src'), 'node_modules'] // 絕對路徑寫法
  }
};
複製代碼

所以:設置resolve.modules:[path.resolve(__dirname, 'node_modules')]避免層層查找。 (2). resolve.mainFields參考文檔: www.webpackjs.com/configurati…web

當從 npm包中導入模塊時(例如,import * as D3 from "d3"),此選項將決定在 package.json 中使用哪一個字段導入模塊。根據 webpack 配置中指定的 target 不一樣,默認值也會有所不一樣。ajax

target 屬性設置爲webworker, web 或者沒有指定,默認值爲:

module.exports = {
  //...
  resolve: {
    mainFields: ['browser', 'module', 'main']
  }
};
複製代碼

對於其餘任意的 target(包括 node),默認值爲:

module.exports = {
  //...
  resolve: {
    mainFields: ['module', 'main']
  }
};
複製代碼

例如,考慮任意一個名爲 upstreamlibrary,其 package.json包含如下字段

{
  "browser": "build/upstream.js",
  "module": "index"
}
複製代碼

在咱們 import * as Upstream from 'upstream' 時,這實際上會從browser 屬性解析文件。在這裏 browser屬性是最優先選擇的,由於它是 mainFields 的第一項。同時,由 webpack 打包的Node.js 應用程序首先會嘗試從 module 字段中解析文件。

(3).resolve.alias參考文檔:www.webpackjs.com/configurati…

建立 importrequire 的別名,來確保模塊引入變得更簡單。例如,一些位於 src/ 文件夾下的經常使用模塊:

alias: {
  Utilities: path.resolve(__dirname, 'src/utilities/'),
  Templates: path.resolve(__dirname, 'src/templates/')
}
複製代碼

如今,替換「在導入時使用相對路徑」這種方式,就像這樣:

import Utility from '../../utilities/utility';
複製代碼

你能夠這樣使用別名:

import Utility from 'Utilities/utility';
複製代碼

也能夠在給定對象的鍵後的末尾添加 $,以表示精準匹配:

module.exports = {
  //...
  resolve: {
    alias: {
      xyz$: path.resolve(__dirname, 'path/to/file.js')
    }
  }
};
複製代碼

這將產生如下結果:

import Test1 from 'xyz'; // 精確匹配,因此 path/to/file.js 被解析和導入
import Test2 from 'xyz/file.js'; // 非精確匹配,觸發普通解析
複製代碼

PS: 若是你使用了TS,在webpack中使用了resolve.alias,通常須要在tsconfig.json文件中對其進行配置,不然使用alias會致使沒法找到響應目錄而報錯:

// tsconfig.json

"compilerOptions": {
    "paths": {
      "@/src/*": ["./src/*"],
      'Templates': ["./src/templates/"],
    },
}
複製代碼

對龐大的第三方模塊設置resolve.alias, 使webpack直接使用庫的min文件,避免庫內解析

(4). resolve.extensions參考文檔:www.webpackjs.com/configurati…

配置resolve.extensions能夠自動解析肯定的擴展。合理配置resolve.extensions,以減小文件查找

resolve.extensions默認值:extensions:['.wasm', '.mjs', '.js', '.json'],當導入語句沒帶文件後綴時,Webpack會根據extensions定義的後綴列表進行文件查找,因此:

  • 列表值儘可能少
  • 頻率高的文件類型的後綴寫在前面
  • 源碼中的導入語句儘量的寫上文件後綴,如require(./data)要寫成require(./data.json)

經常使用寫法:

extensions: ['.js', '.json', '.ts', '.tsx', '.scss']
複製代碼

2. module.noParse字段告訴Webpack沒必要解析哪些文件,能夠用來排除對非模塊化庫文件的解析

參考文檔:webpack.docschina.org/configurati…

jQuery、ChartJS,另外若是使用resolve.alias配置了react.min.js,則也應該排除解析,由於react.min.js通過構建,已是能夠直接運行在瀏覽器的、非模塊化的文件了。noParse值能夠是RegExp、[RegExp]、function

module:{ noParse:[/jquery|chartjs/, /react\.min\.js$/]}
複製代碼

3. 配置loader時,經過test、exclude、include等縮小搜索範圍

{
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: `/fonts/[name].[hash:8].[ext]`
    }
}
複製代碼

二.提高開發效率

開發過程當中修改代碼後,須要自動構建和刷新瀏覽器,以查看效果。這個過程可使用Webpack實現自動化,Webpack負責監聽文件的變化,DevServer負責刷新瀏覽器。

2.1 使用自動刷新

2.1.1 Webpack監聽文件

Webpack能夠開啓監聽: 啓動webpack時加上--watch參數

webpack.js.org/configurati…

// package.json

"scripts": {
    "dev": "webpack --watch" // --watch監聽打包文件,只要發生變化,就會從新打包。只要有這個參數就生效。
}
複製代碼

但咱們想要更豐富的功能:執行npm run dev就會自動打包,並自動打開瀏覽器,同時能夠模擬一些服務器上的特性,此時就要藉助WebpackDevServer來實現。

devServer:{
    contentBase: './dist' // 服務器起在哪一個文件夾下。WebpackDevServer會幫助咱們在這個文件夾下起一個服務器
}
複製代碼

配置

devServer:{
    port: 8080, // 默認8080
    contentBase: './dist',
    open: true, // 自動打開瀏覽器,並訪問服務器地址。 file協議不行,不能發送ajax請求
    proxy: {
        './api': 'http://localhost:3000' // 用戶訪問 /api 這個路徑會被轉發到 http://localhost:3000,支持跨域代理
    }
}
複製代碼

2.1.2 DevServer刷新瀏覽器

devServer: {
    contentBase: config.build.assetsRoot,
    host: config.dev.host,
    port: config.dev.port,
    open: true,
    inline: true,
    hot: true,
    overlay: {
      warnings: true,
      errors: true
    },
    historyApiFallback: {
      rewrites: [
        { from: /^\/index\//, to: `http://${config.dev.host}:${config.dev.port}/index.html` },
      ]
    },
    noInfo: true,
    disableHostCheck: true,
    proxy: {
      // '/user/message': {
      //   target: `http://go.buy.test.mi.com`,
      //   changeOrigin: true,
      //   secure: false
      // },
    }
  },
複製代碼

DevServer刷新瀏覽器有兩種方式:

  1. 向網頁中注入代理客戶端代碼,經過客戶端發起刷新
  2. 向網頁裝入一個iframe,經過刷新iframe實現刷新效果

默認狀況下,以及 devserver: {inline:true} 都是採用第一種方式刷新頁面。第一種方式DevServer由於不知道網頁依賴哪些Chunk,因此會向每一個chunk中都注入客戶端代碼,當要輸出不少chunk時,會致使構建變慢。而一個頁面只須要一個客戶端,因此關閉inline模式能夠減小構建時間,chunk越多提高越明顯。關閉方式:

  1. 啓動時使用webpack-dev-server --inline false
  2. 配置devserver:{inline:false}

關閉inline後入口網址變爲http://localhost:8080/webpack-dev-server/ 另外devServer.compress參數可配置是否採用Gzip壓縮,默認爲false

2.2 開啓模塊熱替換HMR

模塊熱替換不刷新整個網頁而只從新編譯發生變化的模塊,並用新模塊替換老模塊,因此預覽反應更快,等待時間更少,同時不刷新頁面能保留當前網頁的運行狀態。原理也是向每個chunk中注入代理客戶端來鏈接DevServer和網頁。開啓方式:

webpack-dev-server --hot 使用HotModuleReplacementPlugin,比較麻煩

// package.json
"scripts": {
    "start": "webpack-dev-server" ,
}
複製代碼

webpack-dev-server打包後的dist中的內容放到了內存中,加快訪問速度

const webpack = require('webpack')

module.exports =  {
    devServer:{
        port: 8080, // 默認8080
        contentBase: './dist',
        open: true, 
        hot: true, // 讓webpack-dev-server開啓Hot Module Replacement功能
        hotOnly: true, // 即便HMR功能沒有生效,也不讓瀏覽器自動刷新,
    },
    module: {
        rules: [
        {
            test: /\.css$/,
            use:  [
                 'style-loader',
                 'css-loader',
                 'postcss-loader',
               ]
        },
        ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: 'src/index.html',
      }),
      new CleanWebpackPlugin(['dist']), // 開發環境不須要此配置
      new webpack.HotModuleReplacementPlugin() // 使用webpack插件,可用於開發環境
   ],
}
複製代碼

開啓後若是修改子模塊就能夠實現局部刷新,但若是修改的是根JS文件,會整頁刷新,緣由在於,子模塊更新時,事件一層層向上傳遞,直到某層的文件接收了當前變化的模塊,而後執行回調函數。若是一層層向外拋直到最外層都沒有文件接收,就會刷新整頁。 使用 NamedModulesPlugin 可使控制檯打印出被替換的模塊的名稱而非數字ID,另外同webpack監聽,忽略node_modules目錄的文件能夠提高性能。

3、優化輸出質量-壓縮文件體積

3.1 區分環境--減少生產環境代碼體積

代碼運行環境分爲開發環境生產環境,代碼須要根據不一樣環境作不一樣的操做,許多第三方庫中也有大量的根據開發環境判斷的if else代碼,構建也須要根據不一樣環境輸出不一樣的代碼,因此須要一套機制能夠在源碼中區分環境,區分環境以後可使輸出的生產環境的代碼體積減少。Webpack中使用DefinePlugin插件來定義配置文件適用的環境。

3.2 壓縮代碼-JS、CSS

1. 壓縮JS:Webpack內置UglifyJS插件、ParallelUglifyPlugin

使用terser-webpack-plugin插件壓縮JS代碼: 參考文檔: webpack.js.org/plugins/ter…

optimization: {
 minimizer: [
      new TerserPlugin({
        terserOptions: {
          safari10: true
        }
      })
    ],
}
複製代碼

取代了 UglifyJsPlugin

// 取代 new UglifyJsPlugin(/* ... */)
複製代碼

2. 壓縮CSS

2.1 mini-css-extract-plugin:webpack.js.org/plugins/min… 。該插件將CSS提取到單獨的文件中。它爲每一個包含CSSJS文件建立一個CSS文件。它支持CSSSourceMap的按需加載。它基於新的webpack v4功能(模塊類型)構建,而且須要webpack 4才能正常工做。

2.2 optimize-css-assets-webpack-plugin: www.npmjs.com/package/opt… 。主要是用來壓縮css文件

plugins: [
    new MiniCssExtractPlugin({
      filename: path.join('css/[name].css?[contenthash:8]'),
      chunkFilename: path.join('css/[name].chunk.css?[contenthash:8]')
    }),
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css\?\w*$/
    })
],
複製代碼

2.3 cssnano基於PostCSS,不只是刪掉空格,還能理解代碼含義,例如把color:#ff0000 轉換成 color:redcss-loader內置了cssnano,只須要使用 css-loader?minimize 就能夠開啓cssnano壓縮。 另一種壓縮CSS的方式是使用PurifyCSSPlugin,須要配合 extract-text-webpack-plugin 使用,它主要的做用是能夠去除沒有用到的CSS代碼,相似JSTree Shaking

3.3 使用Tree Shaking剔除JS死代碼

參考文檔:webpack.docschina.org/guides/tree…

Tree Shaking能夠剔除用不上的死代碼,它依賴ES6import、export的模塊化語法,最早在Rollup中出現,Webpack 2.0將其引入。適合用於Lodash、utils.js等工具類較分散的文件。它正常工做的前提是代碼必須採用ES6的模塊化語法,由於ES6模塊化語法是靜態的(在導入、導出語句中的路徑必須是靜態字符串,且不能放入其餘代碼塊中)。若是採用了ES5中的模塊化,例如module.export = {...}、require( x+y )、if (x) { require( './util' ) },則Webpack沒法分析出能夠剔除哪些代碼。

tree shaking 是一個術語,一般用於描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴於 ES2015模塊語法的 靜態結構 特性,例如importexport。這個術語和概念其實是由 ES2015 模塊打包工具 rollup 普及起來的。

webpack 4正式版本擴展了此檢測能力,經過package.json"sideEffects" 屬性做爲標記,向 compiler 提供提示,代表項目中的哪些文件是 "pure(純的 ES2015 模塊)",由此能夠安全地刪除文件中未使用的部分。

參考文檔:webpack.docschina.org/guides/tree…

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

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

參考文檔:webpack.docschina.org/guides/tree…

經過 importexport語法,咱們已經找出須要刪除的「未引用代碼(dead code)」,然而,不只僅是要找出,還要在 bundle 中刪除它們。爲此,咱們須要將 mode配置選項設置爲 production

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
- mode: 'development',
- optimization: {
-   usedExports: true
- }
+ mode: 'production'
};
複製代碼
注意,也能夠在命令行接口中使用 --optimize-minimize 標記,來啓用 TerserPlugin。
複製代碼

準備就緒後,而後運行另外一個 npm script npm run build,就會看到輸出結果發生了改變。

dist/bundle.js 中,如今整個 bundle 都已經被 minify(壓縮) 和 mangle(混淆破壞),可是若是仔細觀察,則不會看到引入 square 函數,但能看到 cube函數的混淆破壞版本(function r(e){return e*e*e}n.a=r)。如今,隨着 minification(代碼壓縮) 和tree shaking,咱們的bundle 減少幾個字節!雖然,在這個特定示例中,可能看起來沒有減小不少,可是,在有着複雜依賴樹的大型應用程序上運行 tree shaking時,會對 bundle 產生顯著的體積優化。

運行 tree shaking 須要 ModuleConcatenationPlugin。經過 mode: "production" 能夠添加此插件。若是你沒有使用 mode 設置,記得手動添加 ModuleConcatenationPlugin。
複製代碼

參考文檔:webpack.docschina.org/guides/tree…

結論: 咱們已經知道,想要使用 tree shaking 必須注意如下幾點:

  • 使用 ES2015模塊語法(即 importexport)。
  • 確保沒有 compilerES2015 模塊語法轉換爲 CommonJS模塊(這也是流行的 Babel preset@babel/preset-env 的默認行爲 - 更多詳細信息請查看 文檔)。
  • 在項目package.json 文件中,添加一個"sideEffects" 屬性。
  • 經過將 mode選項設置爲 production,啓用 minification(代碼壓縮) 和tree shaking

你能夠將應用程序想象成一棵樹。綠色表示實際用到的 source code(源碼)library(庫),是樹上活的樹葉。灰色表示未引用代碼,是秋天樹上枯萎的樹葉。爲了除去死去的樹葉,你必須搖動這棵樹,使它們落下。

4、優化輸出質量--加速網絡請求

4.1 使用CDN加速靜態資源加載

1. CND加速的原理

CDN經過將資源部署到世界各地,使得用戶能夠就近訪問資源,加快訪問速度。要接入CDN,須要把網頁的靜態資源上傳到CDN服務上,在訪問這些資源時,使用CDN服務提供的URL

因爲CDN會爲資源開啓長時間的緩存,例如用戶從CDN上獲取了index.html,即便以後替換了CDN上的index.html,用戶那邊仍會在使用以前的版本直到緩存時間過時。業界作法:

  • HTML文件:放在本身的服務器上且關閉緩存,不接入CDN
  • 靜態的JS、CSS、圖片等資源:開啓CDN和緩存,同時文件名帶上由內容計算出的Hash值,這樣只要內容變化hash就會變化,文件名就會變化,就會被從新下載而不論緩存時間多長。

另外,HTTP1.x版本的協議下,瀏覽器會對於向同一域名並行發起的請求數限制在4~8個。那麼把全部靜態資源放在同一域名下的CDN服務上就會遇到這種限制,因此能夠把他們分散放在不一樣的CDN服務上,例如JS文件放在js.cdn.com下,將CSS文件放在css.cdn.com下等。這樣又會帶來一個新的問題:增長了域名解析時間,這個能夠經過dns-prefetch來解決 <link rel='dns-prefetch' href='//js.cdn.com'> 來縮減域名解析的時間。形如**//xx.com 這樣的URL省略了協議**,這樣作的好處是,瀏覽器在訪問資源時會自動根據當前URL採用的模式來決定使用HTTP仍是HTTPS協議。

當瀏覽器從第三方服務跨域請求資源的時候,在瀏覽器發起請求以前,這個第三方的跨域域名須要被解析爲一個IP地址,這個過程就是DNS解析,DNS緩存能夠用來減小這個過程的耗時,DNS解析可能會增長請求的延遲,對於那些須要請求許多第三方的資源的網站而言,DNS解析的耗時延遲可能會大大下降網頁加載性能。

參考文章: developer.mozilla.org/zh-CN/docs/…

2. 總之,構建須要知足如下幾點:

  • 靜態資源導入的URL要變成指向CDN服務的絕對路徑的URL
  • 靜態資源的文件名須要帶上根據內容計算出的Hash
  • 不一樣類型資源放在不一樣域名的CDN

3. 最終配置:

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const {WebPlugin} = require('web-webpack-plugin');
//...
output:{
 filename: '[name]_[chunkhash:8].js',
 path: path.resolve(__dirname, 'dist'),
 publicPatch: '//js.cdn.com/id/', //指定存放JS文件的CDN地址
},
module:{
 rules:[{
     test: /\.css/,
     use: ExtractTextPlugin.extract({
         use: ['css-loader?minimize'],
         publicPatch: '//img.cdn.com/id/', //指定css文件中導入的圖片等資源存放的cdn地址
     }),
 },{
    test: /\.png/,
    use: ['file-loader?name=[name]_[hash:8].[ext]'], //爲輸出的PNG文件名加上Hash值 
 }]
},
plugins:[
  new WebPlugin({
     template: './template.html',
     filename: 'index.html',
     stylePublicPath: '//css.cdn.com/id/', //指定存放CSS文件的CDN地址
  }),
 new ExtractTextPlugin({
     filename:`[name]_[contenthash:8].css`, //爲輸出的CSS文件加上Hash
 })
]

複製代碼

4.2 多頁面應用提取頁面間公共代碼,以利用緩存

  1. 原理

大型網站一般由多個頁面組成,每一個頁面都是一個獨立的單頁應用,多個頁面間確定會依賴一樣的樣式文件、技術棧等。若是不把這些公共文件提取出來,那麼每一個單頁打包出來的chunk中都會包含公共代碼,至關於要傳輸n份重複代碼。若是把公共文件提取出一個文件,那麼當用戶訪問了一個網頁,加載了這個公共文件,再訪問其餘依賴公共文件的網頁時,就直接使用文件在瀏覽器的緩存,這樣公共文件就只用被傳輸一次。

  1. 應用方法

把多個頁面依賴的公共代碼提取到common.js中,此時common.js包含基礎庫的代碼

把多個頁面依賴的公共代碼提取到common.js中,此時common.js包含基礎庫的代碼
複製代碼

找出依賴的基礎庫,寫一個base.js文件,再與common.js提取公共代碼到base中,common.js就剔除了基礎庫代碼,而base.js保持不變

//base.js
import 'react';
import 'react-dom';
import './base.css';
//webpack.config.json
entry:{
    base: './base.js'
},
plugins:[
    new CommonsChunkPlugin({
        chunks:['base','common'],
        name:'base',
        //minChunks:2, 表示文件要被提取出來須要在指定的chunks中出現的最小次數,防止common.js中沒有代碼的狀況
    })        
]
複製代碼
  1. 獲得基礎庫代碼base.js,不含基礎庫的公共代碼common.js,和頁面各自的代碼文件xx.js

頁面引用順序以下:base.js--> common.js--> xx.js

4.3 分割代碼以按需加載

  1. 原理

單頁應用的一個問題在於使用一個頁面承載複雜的功能,要加載的文件體積很大,不進行優化的話會致使首屏加載時間過長,影響用戶體驗。作按需加載能夠解決這個問題。具體方法以下:

  • 將網站功能按照相關程度劃分紅幾類
  • 每一類合併成一個Chunk,按需加載對應的Chunk
  • 例如,只把首屏相關的功能放入執行入口所在的Chunk,這樣首次加載少許的代碼,其餘代碼要用到的時候再去加載。最好提早預估用戶接下來的操做,提早加載對應代碼,讓用戶感知不到網絡加載
  1. 作法

一個最簡單的例子:網頁首次只加載main.js,網頁展現一個按鈕,點擊按鈕時加載分割出去的show.js,加載成功後執行show.js裏的函數

//main.js
document.getElementById('btn').addEventListener('click',function(){
    import(/* webpackChunkName:"show" */ './show').then((show)=>{
        show('Webpack');
    })
})
//show.js
module.exports = function (content) {
    window.alert('Hello ' + content);
}

複製代碼

import(/* webpackChunkName:show */ './show').then() 是實現按需加載的關鍵Webpack內置對import( *)語句的支持,Webpack會以./show.js爲入口從新生成一個Chunk。代碼在瀏覽器上運行時只有點擊了按鈕纔會開始加載show.js,且import語句會返回一個Promise,加載成功後能夠在then方法中獲取加載的內容。這要求瀏覽器支持Promise API,對於不支持的瀏覽器,須要注入Promise polyfill/* webpackChunkName:show */ 是定義動態生成的Chunk的名稱,默認名稱是[id].js,定義名稱方便調試代碼。爲了正確輸出這個配置的ChunkName,還須要配置Webpack

//...
output:{
    filename:'[name].js',
    chunkFilename:'[name].js', // 指定動態生成的Chunk在輸出時的文件名稱
}
複製代碼

5、優化輸出質量--提高代碼運行時的效率

5.1 使用Prepack提早求值

  1. 原理:

Prepack是一個部分求值器,編譯代碼時提早將計算結果放到編譯後的代碼中,而不是在代碼運行時纔去求值。經過在便一階段預先執行源碼來獲得執行結果,再直接將運行結果輸出以提高性能。可是如今Prepack還不夠成熟,用於線上環境還爲時過早。

參考文檔:github.com/facebook/pr…

  1. 使用方法
const PrepackWebpackPlugin = require('prepack-webpack-plugin').default;
module.exports = {
    plugins:[
        new PrepackWebpackPlugin()
    ]
}
複製代碼

5.2 使用Scope Hoisting

  1. 原理

譯做「做用域提高」,是在Webpack3中推出的功能,它分析模塊間的依賴關係,儘量將被打散的模塊合併到一個函數中,但不能形成代碼冗餘,因此只有被引用一次的模塊才能被合併。因爲須要分析模塊間的依賴關係,因此源碼必須是採用了ES6模塊化的,不然Webpack會降級處理不採用Scope Hoisting

  1. 使用方法
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
//...
plugins:[
    new ModuleConcatenationPlugin();
],
resolve:{
	mainFields:['jsnext:main','browser','main']
}
複製代碼

webpack --display-optimization-bailout 輸出日誌中會提示哪一個文件致使了降級處理

6、使用輸出分析工具

啓動Webpack時帶上這兩個參數能夠生成一個json文件,輸出分析工具大多依賴該文件進行分析: webpack --profile --json > stats.json 其中 --profile 記錄構建過程當中的耗時信息,--jsonJSON的格式輸出構建結果,>stats.jsonUNIX / Linux系統中的管道命令,含義是將內容經過管道輸出到stats.json文件中。

  1. 官方工具Webpack Analyse

打開該工具的官網http://webpack.github.io/analyse/上傳stats.json,就能夠獲得分析結果

  1. webpack-bundle-analyzer

可視化分析工具,比Webapck Analyse更直觀。使用也很簡單:

npm i -g webpack-bundle-analyzer安裝到全局 按照上面方法生成stats.json文件 在項目根目錄執行webpack-bundle-analyzer,瀏覽器會自動打開結果分析頁面。

相關文章
相關標籤/搜索