【前端必知】Webpack性能優化

Webpack是現在主流的功能強大的模塊化打包工具,在使用Webpack時,如果不注意性能優化,有非常大的可能會產生性能問題,性能問題主要分為開發時打包構建速度慢、開發調試時的重復性工作、以及輸出文件質量不高等,因此性能優化也主要從這些方面來分析。

  • 優化構建速度
    • 縮小文件的搜索范圍
    • 使用DllPlugin減少基礎模塊編譯次數
    • 使用HappyPack開啟多進程Loader轉換
    • 使用ParallelUglifyPlugin開啟多進程壓縮JS文件
  • 優化開發體驗
    • 使用自動刷新
      • Webpack監聽文件
      • DevServer刷新瀏覽器
    • 開啟模塊熱替換
  • 優化輸出質量-壓縮文件體積
    • 區分環境--減小生產環境代碼體積
    • 壓縮代碼-JS、ES、CSS
      • 壓縮JS:Webpack內置UglifyJS插件、ParallelUglifyPlugin
      • 壓縮ES6:第三方UglifyJS插件
      • 壓縮CSS:css-loader?minimize、PurifyCSSPlugin
    • 使用Tree Shaking剔除JS死代碼
  • 優化輸出質量--加速網絡請求
    • 使用CDN加速靜態資源加載
    • 多頁面應用提取頁面間公共代碼,以利用緩存
    • 分割代碼以按需加載]
  • 優化輸出質量--提升代碼運行時的效率
    • 使用Prepack提前求值
    • 使用Scope Hoisting
  • 使用輸出分析工具
  • 其他Tips

優化構建速度

Webpack在啟動后會根據Entry配置的入口出發,遞歸地解析所依賴的文件。這個過程分為搜索文件和把匹配的文件進行分析、轉化的兩個過程,因此可以從這兩個角度來進行優化配置。

縮小文件的搜索范圍

搜索過程優化方式包括:

  1. resolve字段告訴webpack怎么去搜索文件,所以首先要重視resolve字段的配置
  • 設置 resolve.modules:[path.resolve(__dirname, 'node_modules')]
    避免層層查找。

resolve.modules告訴webpack去哪些目錄下尋找第三方模塊,默認值為['node_modules'],會依次查找./node_modules、../node_modules、../../node_modules。

  • 設置 resolve.mainFields:['main'],設置盡量少的值可以減少入口文件的搜索步驟

第三方模塊為了適應不同的使用環境,會定義多個入口文件,mainFields定義使用第三方模塊的哪個入口文件,由于大多數第三方模塊都使用main字段描述入口文件的位置,所以可以設置單獨一個main值,減少搜索

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

如對于react:

resolve.alias:{
    'react':patch.resolve(__dirname, './node_modules/react/dist/react.min.js')
}

這樣會影響Tree-Shaking,適合對整體性比較強的庫使用,如果是像lodash這類工具類的比較分散的庫,比較適合Tree-Shaking,避免使用這種方式。

  • 合理配置resolve.extensions,減少文件查找

默認值:extensions:['.js', '.json'],

當導入語句沒帶文件后綴時,Webpack會根據extensions定義的后綴列表進行文件查找,所以:

a. 列表值盡量少

b. 頻率高的文件類型的后綴寫在前面

c. 源碼中的導入語句盡可能的寫上文件后綴,如require(./data)要寫成require(./data.json)

  1. module.noParse字段告訴Webpack不必解析哪些文件,可以用來排除對非模塊化庫文件的解析
    如jQuery、ChartJS,另外如果使用resolve.alias配置了react.min.js,則也應該排除解析,因為react.min.js經過構建,已經是可以直接運行在瀏覽器的、非模塊化的文件了。

noParse值可以是RegExp、[RegExp]、function

module:{ noParse:[/jquery|chartjs/, /react\.min\.js$/] }
  1. 配置loader時,通過test、exclude、include縮小搜索范圍

使用DllPlugin減少基礎模塊編譯次數

DllPlugin動態鏈接庫插件,其原理是把網頁依賴的基礎模塊抽離出來打包到dll文件中,當需要導入的模塊存在于某個dll中時,這個模塊不再被打包,而是去dll中獲取。為什么會提升構建速度呢?原因在于dll中大多包含的是常用的第三方模塊,如react、react-dom,所以只要這些模塊版本不升級,就只需被編譯一次。我認為這樣做和配置resolve.alias和module.noParse的效果有異曲同工的效果。

使用方法:

使用DllPlugin配置一個webpack_dll.config.js來構建dll文件:

// webpack_dll.config.js
const path = require('path');
const DllPlugin = require('webpack/lib/DllPlugin');
module.exports = {
 entry:{
     react:['react','react-dom'],
     polyfill:['core-js/fn/promise','whatwg-fetch']
 },
 output:{
     filename:'[name].dll.js',
     path:path.resolve(__dirname, 'dist'),
     library:'_dll_[name]',  //dll的全局變量名
 },
 plugins:[
     new DllPlugin({
         name:'_dll_[name]',  //dll的全局變量名
         path:path.join(__dirname,'dist','[name].manifest.json'),//描述生成的manifest文件
     })
 ]
}

需要注意DllPlugin的參數中name值必須和output.library值保持一致,并且生成的manifest文件中會引用output.library值。

最終構建出的文件:

 |-- polyfill.dll.js
 |-- polyfill.manifest.json
 |-- react.dll.js
 └── react.manifest.json

其中xx.dll.js包含打包的n多模塊,這些模塊存在一個數組里,并以數組索引作為ID,通過一個變量假設為_xx_dll暴露在全局中,可以通過window._xx_dll訪問這些模塊。xx.manifest.json文件描述dll文件包含哪些模塊、每個模塊的路徑和ID。然后再在項目的主config文件里使用DllReferencePlugin插件引入xx.manifest.json文件。

在主config文件里使用DllReferencePlugin插件引入xx.manifest.json文件:

//webpack.config.json
const path = require('path');
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module.exports = {
    entry:{ main:'./main.js' },
    //... 省略output、loader等的配置
    plugins:[
        new DllReferencePlugin({
            manifest:require('./dist/react.manifest.json')
        }),
        new DllReferenctPlugin({
            manifest:require('./dist/polyfill.manifest.json')
        })
    ]
}

最終構建生成main.js

使用HappyPack開啟多進程Loader轉換

在整個構建流程中,最耗時的就是Loader對文件的轉換操作了,而運行在Node.js之上的Webpack是單線程模型的,也就是只能一個一個文件進行處理,不能并行處理。HappyPack可以將任務分解給多個子進程,最后將結果發給主進程。JS是單線程模型,只能通過這種多進程的方式提高性能。

HappyPack使用如下:

npm i -D happypack
// webpack.config.json
const path = require('path');
const HappyPack = require('happypack');

module.exports = {
    //...
    module:{
        rules:[{
                test:/\.js$/,
                use:['happypack/loader?id=babel']
                exclude:path.resolve(__dirname, 'node_modules')
            },{
                test:/\.css/,
                use:['happypack/loader?id=css']
            }],
        plugins:[
            new HappyPack({
                id:'babel',
                loaders:['babel-loader?cacheDirectory']
            }),
            new HappyPack({
                id:'css',
                loaders:['css-loader']
            })
        ]
    }
}

除了id和loaders,HappyPack還支持這三個參數:threads、verbose、threadpool,threadpool代表共享進程池,即多個HappyPack實例都用同個進程池中的子進程處理任務,以防資源占用過多。

使用ParallelUglifyPlugin開啟多進程壓縮JS文件

使用UglifyJS插件壓縮JS代碼時,需要先將代碼解析成Object表示的AST(抽象語法樹),再去應用各種規則去分析和處理AST,所以這個過程計算量大耗時較多。ParallelUglifyPlugin可以開啟多個子進程,每個子進程使用UglifyJS壓縮代碼,可以并行執行,能顯著縮短壓縮時間。

使用也很簡單,把原來的UglifyJS插件換成本插件即可,使用如下:

npm i -D webpack-parallel-uglify-plugin

// webpack.config.json
const ParallelUglifyPlugin = require('wbepack-parallel-uglify-plugin');
//...
plugins: [
    new ParallelUglifyPlugin({
        uglifyJS:{
            //...這里放uglifyJS的參數
        },
        //...其他ParallelUglifyPlugin的參數,設置cacheDir可以開啟緩存,加快構建速度
    })
]

優化開發體驗

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

使用自動刷新

Webpack監聽文件

Webpack可以使用兩種方式開啟監聽:

  1. 啟動webpack時加上--watch參數;
  2. 在配置文件中設置watch:true。此外還有如下配置參數。合理設置watchOptions可以優化監聽體驗。
module.exports = {
    watch: true,
    watchOptions: {
        ignored: /node_modules/,
        aggregateTimeout: 300,  //文件變動后多久發起構建,越大越好
        poll: 1000,  //每秒詢問次數,越小越好
    }
}

ignored:設置不監聽的目錄,排除node_modules后可以顯著減少Webpack消耗的內存

aggregateTimeout:文件變動后多久發起構建,避免文件更新太快而造成的頻繁編譯以至卡死,越大越好

poll:通過向系統輪詢文件是否變化來判斷文件是否改變,poll為每秒詢問次數,越小越好

DevServer刷新瀏覽器

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

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

默認情況下,以及 devserver: {inline:true} 都是采用第一種方式刷新頁面。第一種方式DevServer因為不知道網頁依賴哪些Chunk,所以會向每個chunk中都注入客戶端代碼,當要輸出很多chunk時,會導致構建變慢。而一個頁面只需要一個客戶端,所以關閉inline模式可以減少構建時間,chunk越多提升越明顯。關閉方式:

  • 啟動時使用webpack-dev-server --inline false
  • 配置 devserver:{inline:false}

關閉inline后入口網址變為http://localhost:8080/webpack-dev-server/

另外devServer.compress參數可配置是否采用Gzip壓縮,默認為false

開啟模塊熱替換HMR

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

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

開啟后如果修改子模塊就可以實現局部刷新,但如果修改的是根JS文件,會整頁刷新,原因在于,子模塊更新時,事件一層層向上傳遞,直到某層的文件接收了當前變化的模塊,然后執行回調函數。如果一層層向外拋直到最外層都沒有文件接收,就會刷新整頁。

使用 NamedModulesPlugin 可以使控制臺打印出被替換的模塊的名稱而非數字ID,另外同webpack監聽,忽略node_modules目錄的文件可以提升性能。

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

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

代碼運行環境分為開發環境和生產環境,代碼需要根據不同環境做不同的操作,許多第三方庫中也有大量的根據開發環境判斷的if else代碼,構建也需要根據不同環境輸出不同的代碼,所以需要一套機制可以在源碼中區分環境,區分環境之后可以使輸出的生產環境的代碼體積減小。Webpack中使用DefinePlugin插件來定義配置文件適用的環境。

const DefinePlugin = require('webpack/lib/DefinePlugin');
//...
plugins:[
    new DefinePlugin({
        'process.env': {
            NODE_ENV: JSON.stringify('production')
        }
    })
]

注意,JSON.stringify('production') 的原因是,環境變量值需要一個雙引號包裹的字符串,而stringify后的值是'"production"'

然后就可以在源碼中使用定義的環境:

if(process.env.NODE_ENV === 'production'){
    console.log('你在生產環境')
    doSth();
}else{
    console.log('你在開發環境')
    doSthElse();
}

當代碼中使用了process時,Webpack會自動打包進process模塊的代碼以支持非Node.js的運行環境,這個模塊的作用是模擬Node.js中的process,以支持process.env.NODE_ENV === 'production' 語句。

壓縮代碼-JS、ES、CSS

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

會分析JS代碼語法樹,理解代碼的含義,從而做到去掉無效代碼、去掉日志輸入代碼、縮短變量名等優化。常用配置參數如下:

const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
//...
plugins: [
    new UglifyJSPlugin({
        compress: {
            warnings: false,  //刪除無用代碼時不輸出警告
            drop_console: true,  //刪除所有console語句,可以兼容IE
            collapse_vars: true,  //內嵌已定義但只使用一次的變量
            reduce_vars: true,  //提取使用多次但沒定義的靜態值到變量
        },
        output: {
            beautify: false, //最緊湊的輸出,不保留空格和制表符
            comments: false, //刪除所有注釋
        }
    })
]

使用webpack --optimize-minimize 啟動webpack,可以注入默認配置的UglifyJSPlugin

壓縮ES6:第三方UglifyJS插件

隨著越來越多的瀏覽器支持直接執行ES6代碼,應盡可能的運行原生ES6,這樣比起轉換后的ES5代碼,代碼量更少,且ES6代碼性能更好。直接運行ES6代碼時,也需要代碼壓縮,第三方的uglify-webpack-plugin提供了壓縮ES6代碼的功能:

npm i -D uglify-webpack-plugin@beta //要使用最新版本的插件
//webpack.config.json
const UglifyESPlugin = require('uglify-webpack-plugin');
//...
plugins:[
    new UglifyESPlugin({
        uglifyOptions: {  //比UglifyJS多嵌套一層
            compress: {
                warnings: false,
                drop_console: true,
                collapse_vars: true,
                reduce_vars: true
            },
            output: {
                beautify: false,
                comments: false
            }
        }
    })
]

另外要防止babel-loader轉換ES6代碼,要在.babelrc中去掉babel-preset-env,因為正是babel-preset-env負責把ES6轉換為ES5。

壓縮CSS:css-loader?minimize、PurifyCSSPlugin

cssnano基于PostCSS,不僅是刪掉空格,還能理解代碼含義,例如把color:#ff0000 轉換成 color:red,css-loader內置了cssnano,只需要使用 css-loader?minimize 就可以開啟cssnano壓縮。

另外一種壓縮CSS的方式是使用PurifyCSSPlugin,需要配合 extract-text-webpack-plugin 使用,它主要的作用是可以去除沒有用到的CSS代碼,類似JS的Tree Shaking。

使用Tree Shaking剔除JS死代碼

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

啟用Tree Shaking:

  • 修改.babelrc以保留ES6模塊化語句:
{
    "presets": [
        [
            "env", 
            { "module": false },   //關閉Babel的模塊轉換功能,保留ES6模塊化語法
        ]
    ]
}
  • 啟動webpack時帶上 --display-used-exports可以在shell打印出關于代碼剔除的提示

  • 使用UglifyJSPlugin,或者啟動時使用--optimize-minimize

  • 在使用第三方庫時,需要配置 resolve.mainFields: ['jsnext:main', 'main'] 以指明解析第三方庫代碼時,采用ES6模塊化的代碼入口

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

使用CDN加速靜態資源加載

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協議。

總之,構建需要滿足以下幾點:

  • 靜態資源導入的URL要變成指向CDN服務的絕對路徑的URL
  • 靜態資源的文件名需要帶上根據內容計算出的Hash值
  • 不同類型資源放在不同域名的CDN上
    最終配置:
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
 })
]

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

原理
大型網站通常由多個頁面組成,每個頁面都是一個獨立的單頁應用,多個頁面間肯定會依賴同樣的樣式文件、技術棧等。如果不把這些公共文件提取出來,那么每個單頁打包出來的chunk中都會包含公共代碼,相當于要傳輸n份重復代碼。如果把公共文件提取出一個文件,那么當用戶訪問了一個網頁,加載了這個公共文件,再訪問其他依賴公共文件的網頁時,就直接使用文件在瀏覽器的緩存,這樣公共文件就只用被傳輸一次。

應用方法

  1. 把多個頁面依賴的公共代碼提取到common.js中,此時common.js包含基礎庫的代碼
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
//...
plugins:[
    new CommonsChunkPlugin({
        chunks:['a','b'], //從哪些chunk中提取
        name:'common',  // 提取出的公共部分形成一個新的chunk
    })
]
  1. 找出依賴的基礎庫,寫一個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

分割代碼以按需加載

原理

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

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

做法

一個最簡單的例子:網頁首次只加載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在輸出時的文件名稱
}

書中另外提供了更復雜的React-Router中異步加載組件的實戰場景。

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

使用Prepack提前求值

原理
Prepack是一個部分求值器,編譯代碼時提前將計算結果放到編譯后的代碼中,而不是在代碼運行時才去求值。通過在便一階段預先執行源碼來得到執行結果,再直接將運行結果輸出以提升性能。但是現在Prepack還不夠成熟,用于線上環境還為時過早。

使用方法

const PrepackWebpackPlugin = require('prepack-webpack-plugin').default;
module.exports = {
    plugins:[
        new PrepackWebpackPlugin()
    ]
}

使用Scope Hoisting

原理
譯作“作用域提升”,是在Webpack3中推出的功能,它分析模塊間的依賴關系,盡可能將被打散的模塊合并到一個函數中,但不能造成代碼冗余,所以只有被引用一次的模塊才能被合并。由于需要分析模塊間的依賴關系,所以源碼必須是采用了ES6模塊化的,否則Webpack會降級處理不采用Scope Hoisting。

使用方法

const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
//...
plugins:[
    new ModuleConcatenationPlugin();
],
resolve:{
    mainFields:['jsnext:main','browser','main']
}

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

使用輸出分析工具

啟動Webpack時帶上這兩個參數可以生成一個json文件,輸出分析工具大多依賴該文件進行分析:

webpack --profile --json > stats.json 其中 --profile 記錄構建過程中的耗時信息,--json 以JSON的格式輸出構建結果,>stats.json 是UNIX / Linux系統中的管道命令,含義是將內容通過管道輸出到stats.json文件中。

  • 官方工具Webpack Analyse

打開該工具的官網http://webpack.github.io/anal...,就可以得到分析結果

  • webpack-bundle-analyzer

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

1.npm i -g webpack-bundle-analyzer安裝到全局

2.按照上面方法生成stats.json文件

3.在項目根目錄執行webpack-bundle-analyzer,瀏覽器會自動打開結果分析頁面。

其他Tips

  • 配置babel-loader時,use: [‘babel-loader?cacheDirectory’] cacheDirectory用于緩存babel的編譯結果,加快重新編譯的速度。另外注意排除node_modules文件夾,因為文件都使用了ES5的語法,沒必要再使用Babel轉換。
  • 配置externals,排除因為已使用script標簽引入而不用打包的代碼,noParse是排除沒使用模塊化語句的代碼。
  • 配置performance參數可以輸出文件的性能檢查配置。
  • 配置profile:true,是否捕捉Webpack構建的性能信息,用于分析是什么原因導致構建性能不佳。
  • 配置cache:true,是否啟用緩存來提升構建速度。
  • 可以使用url-loader把小圖片轉換成base64嵌入到JS或CSS中,減少加載次數。
  • 通過imagemin-webpack-plugin壓縮圖片,通過webpack-spritesmith制作雪碧圖。
  • 開發環境下將devtool設置為cheap-module-eval-source-map,因為生成這種source map的速度最快,能加速構建。在生產環境下將devtool設置為hidden-source-map
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 寫在開頭 先說說為什么要寫這篇文章, 最初的原因是組里的小朋友們看了webpack文檔后, 表情都是這樣的: (摘...
    Lefter閱讀 5,314評論 4 31
  • 在現在的前端開發中,前后端分離、模塊化開發、版本控制、文件合并與壓縮、mock數據等等一些原本后端的思想開始...
    Charlot閱讀 5,480評論 1 32
  • 目錄第1章 webpack簡介 11.1 webpack是什么? 11.2 官網地址 21.3 為什么使用 web...
    lemonzoey閱讀 1,751評論 0 1
  • 構建工具逐漸成為前端工程必備的工具,Grunt、Gulp、Fis、Webpack等等,譯者有幸使用過Fis、Gul...
    陳堅生閱讀 6,047評論 4 64
  • 今天看到晶晶和茜茜為了一只貓咪冒著危險在大冷天花了一個多小時營救流浪貓 悅悅一早給我拿了一副手套,又暖又好用,帶著...
    吉祥三寶141319閱讀 155評論 0 0