Webpack 最佳實踐總結(三)

還未看的,能夠點擊查看上兩篇文章喲:Webpack 最佳實踐總結(一)Webpack 最佳實踐總結(二)javascript

好了,這篇是第三篇,也是完結篇,我感受這一篇是最亂的一篇,湊合着看吧,不會讓你失望的php

整合 CSS 加工流

有時候,前端項目中除了 JavaScript 外,還有一個更重要的 CSS 須要咱們花點精力進去。這裏主要陳述一下如何將 CSS 加工流整合到 webpack 中,由於 CSS Modules 的狀況比較複雜,全部暫還未打算介紹更多關於 CSS Modules 的內容css

CSS 工做流指什麼?好的工做流能夠提供開發效率,節約開發成本。這裏要介紹的是 CSS 工做流中的一種很廣泛的代碼加工流程:正常的 CSS 業務邏輯開發流程須要通過 CSS 預處理器(如 Sass 或 Less),而後再通過後處理器(如 PostCSS)進行深加工。Sass 和 less 讓咱們吃上'語法糖'去快捷編寫 CSS,PostCSS 可讓咱們再也不關心每條語句是否兼顧不一樣和不一樣版本的瀏覽器html

在 webpack 上整合 CSS 加工流實現方式以下:前端

配置預處理器java

這裏以 Sass 做爲預處理器,以下:node

// webpack.config.js
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  module: {
    rules: [
      // ...
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            { loader: 'css-loader', options: { minimize: true } },
            'postcss-loader',
            'sass-loader'
          ]
        })
      }
    ]
  }
}

配置後處理器webpack

這裏以 PostCSS 做爲後處理器,以下:git

// webpack.config.js
const webpack = require('webpack');
const autoprefixer = require('autoprefixer');

module.exports = {
  plugins: [
    new webpack.LoaderOptionsPlugin({
      options: {
        postcss: [
          autoprefixer({
            browsers: [
              'last 3 version',
              'ie >= 10'
            ]
          })
        ],
        context: staticSourcePath
      }
    })
  ]
}

設置外聯github

// webpack.config.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');

// 存放靜態資源,諸如圖片或者是 normalize.css
const staticSourcePath = path.join(__dirname, 'static');

module.exports = {
  // ...
  entry: {
    // 設置入口文件,順序是靜態資源 -> custom.scss -> 項目裏其餘 scss
    base: path.resolve(staticSourcePath, 'src/public/custom.scss')
  },
  // ...
  plugins: [
    // 建立 <link> 標籤,並將 src 指向最終生成的 CSS 文件,須要 html-webpack-plugin
    new ExtractTextPlugin({
      filename: '[name].[contenthash].css',
      allChunks: true
    })
  ]
}

壓縮第三方庫

以 Moment.js 和 Lodash 爲例

Moment.js

Moment.js(v2.18.1) 是一個用於日期的 JavaScript 庫,默認狀況下,只有你安裝它到你的項目中,即便壓縮後,也會佔據217kb大小。相對於在2017年8月1日的統計,對比與 JavaScript 的 446kb 的平均大小,這是實在是太大了。不過 webpack 能夠去掉 Moment.js 其中無用的代碼。

其中有 165kb 的大小是用於本地化的語言包,即使你不去用它們,它們在默認的狀況下也會被包含進來。以下代碼來自 moment 的 gitihub

// moment/src/lib/locale/locales.js
function loadLocale(name) {
    var oldLocale = null;
    // TODO: Find a better way to register and load all the locales in Node
    if (!locales[name] && (typeof module !== 'undefined') &&
            module && module.exports) {
        try {
            oldLocale = globalLocale._abbr;
            require('./locale/' + name);
            // because defineLocale currently also sets the global locale, we
            // want to undo that for lazy loaded locales
            getSetGlobalLocale(oldLocale);
        } catch (e) { }
    }
    return locales[name];
}

上面的代碼會使 Moment.js 在運行期間動態地選擇相應文件去加載。

要解決它須要用到 ContextReplacementPlugin,一款替換上下文的插件,例子以下:

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.ContextReplacementPlugin(
      // 須要被處理的文件目錄位置
      /moment[\/\\]locale/,
      // 正則匹配須要被包括進來的文件
      /(en|zh-cn)\.js/
    )
  ]
};

Lodash

Lodash 是一款方便開發 JavaScript 的工具集合,測試版本爲4.17.4。

當你項目包含有 Lodash 的時候,你打包出來的文件至少增長 75kb,多出來的大小包含了 316 個 Lodash 的函數。若是你只是使用了其中少數,例如 20 個,那麼大概有 65 kb 是多餘的。下面將列出兩種去掉這些多餘的代碼的方法:

方法1:

還記得 webpack最佳實踐(一) 說起的 Tree-shaking 嗎?正由於有它,咱們能夠利用這個特性很是容易作到按需引用,以下:

import _ from 'lodash';
_.get();

修改成

import get from 'lodash/get';
get();

代碼量從 72kb 壓縮到 8.27kb

方法2:

方法1只適合剛開始玩一個項目的時候,並不怎麼適合玩開了的項目,除非重寫一次,這工做量太大了,另一個緣由是 lodash 的方法名會容易跟自定義的函數名衝突,形成隱藏性bug。方法2就是解決這兩個問題,那就是使用babel-plugin-lodash

babel-plugin-lodash 是一款經過 babel 去實現將 lodash 的import用法編譯爲最佳實踐的插件,配置以下:

打開.babelrc,添加下面配置

{
  "plugins": ["lodash"]
}

更多的配置方式能夠查看文檔,這裏再也不做太多介紹。更具體的優化效果看下面:

import _ from 'lodash';
_.get({ a: { b: 5 } }, 'a.b');

上面的代碼是沒有使用babel-plugin-lodash,使用以後,會被從新編譯爲下面:

import _get from 'lodash/get';
_get({ a: { b: 5 } }, 'a.b');

跟方法1同樣,代碼量從 72kb 壓縮到 8.27kb

固然若是你想更進一步壓縮代碼,能夠嘗試與lodash-webpack-plugin搭配,它會更深一步地去刪除一些lodash的方法裏的代碼。例如_.get默認支持深路徑查詢,若是你不須要支持深路徑查詢,你能夠開啓這個插件,這個方法就會被去掉這個支持:

只使用babel-plugin-lodash

import _ from 'lodash';
_.get({ a: { b: 5 } }, 'a.b');
// → returns 5

使用babel-plugin-lodashlodash-webpack-plugin 以後

import _get from 'lodash/get';
_get({ a: { b: 5 } }, 'a.b');
// → returns undefined

代碼量從72kb 壓縮到 772b

啓用 scope hoisting

scope hoisting 對於 webpack 來講,就是將之前的模塊引用鏈拍扁爲一個但又不會影響到已有的代碼。更好理解scope hoisting推薦閱讀:here

目前只有 webpack v3 以上版本才支持scope hoisting,開啓它是須要手動配置,以下:

// webpack.config.js
const webpack = require('webpack');

module.exports = {
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
};

其餘好用的插件

preload-webpack-plugin 讓靜態資源支持 DNS 預解析和預加載,配置以下:

// webpack.config.js
const PreloadWebpackPlugin = require('preload-webpack-plugin');
module.exports = {
  // ...
  plugins: [
    new PreloadWebpackPlugin({
      rel: 'preload',
      as: 'script',
      include: 'all',
      fileBlacklist: [/\.(css|map)$/, /base?.+/]
    })
  ]
}

script-ext-html-webpack-plugin 讓 js 加載方式支持 Async 或 defer,配置以下:

// webpack.config.js
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
module.exports = {
  // ...
  plugins: [
    new ScriptExtHtmlWebpackPlugin({
      defaultAttribute: 'defer'
    })
  ]
}

總結

有點亂,很差總結,大概就是整合 CSS 代碼加工流程到 webpack 中、壓縮第三方庫(Moment.js 和 Lodash )、啓用scope hoisting和其餘好用的插件

大概就這樣,內容較多~

文章首發於:https://www.linpx.com/p/webpa...
歡迎訪問個人博客:https://www.linpx.com

相關文章
相關標籤/搜索