webpack優化不徹底指南

基礎篇

最基本的一個webpack配置css

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
        entry: __dirname + "/app/main.js", //已屢次說起的惟一入口文件
        output: {
            path: __dirname + "/build",
            filename: "bundle-[hash].js"
        },
        devtool: 'none',
        devServer: {
            contentBase: "./public", //本地服務器所加載的頁面所在的目錄
            historyApiFallback: true, //不跳轉
            inline: true,
            hot: true
        },
        module: {
            rules: [{
                    test: /(\.jsx|\.js)$/,
                    use: {
                        loader: "babel-loader"
                    }
                }, {
                    test: /\.css$/,
                    use: ExtractTextPlugin.extract({
                        fallback: "style-loader",
                        use: [{
                            loader: "css-loader",
                            options: {
                                modules: true,
                                localIdentName: '[name]__[local]--[hash:base64:5]'
                            }
                        }, {
                            loader: "postcss-loader"
                        }],
                    })
                }
            }
        ]
    },
    plugins: [
        new webpack.BannerPlugin(),
        new HtmlWebpackPlugin({
            template: __dirname + "/app/index.tmpl.html" //new 一個這個插件的實例,並傳入相關的參數
        }),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.optimize.UglifyJsPlugin(),
        new ExtractTextPlugin("style.css")
    ]
};

複製代碼

接下來基於這份配置進行一個優化:
首先咱們得區分開發環境、生產環境以及測試環境(這個在國內用的公司少) 實現思路(參考vue-cil),通用配置能夠設置一個base文件而後exports,在其餘的配置文件中require進來。html

上面這個配置中new webpack.optimize.UglifyJsPlugin()就能夠放入webpack.prod.conf.js中,由於代碼壓縮醜化只須要在生產環境中使用,在開發過程開啓的話,不只編譯時間加長還不利於調試。vue

module與entry、output這個就能夠放到webpack.base.cong.js文件中,這些配置是通用的無論在生產環境仍是開發環境中都是用獲得的。node

devServer則是在開發過程當中須要啓動一個服務器而後再開啓熱替換功能。jquery

  • 在module中也可進行些優化,例如在後綴爲.js文件的處理中添加:

include: [resolve('src'), resolve('test')]webpack

這樣loader加載器就只會匹配src/與/test目錄下的文件,至於node_modules目錄下的文件則跳過,假如沒加這一限制條件的話,node_modules下那麼多的js文件,想一想都以爲恐怖,而且別人發佈出來的包文件通常都是通過babel轉成ES5標準的。git

  • 添加alias,如:

alias: {
'@': resolve('src')
}es6

這樣當webpack遇到import('@xxx')的時候就會直接在src/目錄下去尋找,能節省很多的目錄查詢時間github

進階篇

多頁面優化

當咱們的項目是多個頁面的時候,咱們須要用到HtmlWebpackPlugin插件,web

for(let i = 0; i< html.length; i++) {
  plugins.push(
    new HtmlWebpackPlugin({
        filename:fileName,
        template: path.join('./src/html/', fileName),
        inject: true,
        minify: {
          removeComments: true,
          collapseWhitespace: false,
          removeAttributeQuotes: true
        },
        chunksSortMode: 'dependency',
        chunks: ['manifest', 'vendor', cur]
      }))
  )
}
複製代碼

有多少個頁面就push多少個HtmlWebpackPlugin進去,至於頁面的獲取咱們能夠經過walk-sync來作到,經過獲取目錄下的入口文件來判斷有多少個頁面存在。
我在優化過程當中遇到個坑,當webpack從2.x升級爲3.x的時候,

compilation.getStats().toJson()

這個函數的執行時間會大大加長,我看到其實在issue裏頭有人提出來了,不過做者並無給合併到master中去。還有點就是:當頁面是多頁面的時候每一次小的改動都會把全部的html文件從新生成一次,針對這兩個優化我在Githubfork了下html-webpack-plugin,併發布了html-webpack-plugin-multihtml。咱們的項目一共是有49個頁面以前rebuild是花費5-7s ,優化後保持在1s左右。

提取公共代碼CommonsChunkPlugin

有些類庫如utils, bootstrap之類的可能被多個頁面共享,最好是能夠合併成一個js,而非每一個js單獨去引用。這樣可以節省一些空間。這時咱們能夠用到CommonsChunkPlugin,咱們指定好生成文件的名字,以及想抽取哪些入口js文件的公共代碼,webpack就會自動幫咱們合併好。

new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      chunks: Object.keys(entrys),
      minChunks: function (module, count) {
        return (module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0 && count > 8)
      }
}),
複製代碼

這個是針對多頁面優化的,CommonsChunkPlugin會本身計算當一個類庫被引用的次數超過8次,就把它打包至vendor中,這樣就沒必要全打包至一個index.js裏頭

externals提取經常使用庫

externals 配置選項提供了「從輸出的 bundle 中排除依賴」的方法。相反,所建立的 bundle 依賴於那些存在於用戶環境(consumer's environment)中的依賴。
externals主要是防止將某些import的包打包到bundle中,而是在運行時(runtime)再去從外部獲取這些擴展依賴

配置也挺簡單的接下來貼下代碼:

index.html中引入

<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
複製代碼
webpack.config.js中配置

externals: {
  jquery: 'jQuery'
}
複製代碼

這樣就能在代碼中經過import引用了:

import $ from 'jquery';
複製代碼

uglifyPlugin多線程壓縮代碼

在webpack的默認狀況下,都是單線程跑的,有個叫webpack-uglify-parallel的插件,它可以充分調用計算機的資源,利用計算機的多核特性進行代碼壓縮。
使用方法也挺簡單的, 把以前webpack.prod.conf.js中的

new webpack.optimize.UglifyJsPlugin({
  compress: {
    warnings: false,
    drop_console: true
  },
  comments: false
}),
複製代碼

替換爲

var os = require('os');
var UglifyJsParallelPlugin = require('webpack-uglify-parallel');

module.exports = {
    /// ... rest of config
    plugins: [
        new UglifyJsParallelPlugin({
            workers: os.cpus().length, // usually having as many workers as cpu cores gives good results
            // other uglify options
        })
    ]
}
複製代碼

便可 GitHub地址:webpack-uglify-parallel

Happypack

happypack 是 webpack 的一個插件,目的是經過多進程模型,來加速代碼構建。目前咱們項目中已經配置而且上線了,效果還能夠,從最初的40s減小到30s的編譯時間。
配置按照GitHub上的來,也不難

var HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

// 省略其他配置
module: {
  loaders: [
      {
        test: /\.less$/,
        loader: ExtractTextPlugin.extract('style',path.resolve(__dirname,'./node_modules', 'happypack/loader') + '?id=less'
        )
      }
    ]
  },
  plugins: [
      new HappyPack({
        id: 'less',
        loaders: ['css!less'],
        threadPool: happyThreadPool,
        cache: true,
        verbose: true
      })
  ]
複製代碼

我在優化咱們項目的webpack遇到了兩個坑,一個就是上面提到的,webpack2升級3編譯時間增多,另外一個就是devServer在低版本安卓機型上跑步起來。devServer這個使用"webpack-dev-server": "2.7.1"便可,由於2.9.x版本使用的是es6的寫法安卓4.1如下不支持,ie9如下也不支持。

相關文章
相關標籤/搜索