【webpack】插件 plugins

官網插件地址javascript

插件(plugins)

插件是 webpack 的支柱功能。插件目的在於解決 loader 沒法實現的其餘事。css

webpack 插件是一個具備 apply 屬性的 JavaScript 對象。apply 屬性會被 webpack compiler 調用,而且 compiler 對象可在整個編譯生命週期訪問。如ConsoleLogOnBuildWebpackPlugin.jshtml

class ConsoleLogOnBuildWebpackPlugin {
    apply(compiler) {
    //compiler hook 的 tap 方法的第一個參數,
    //應該是駝峯式命名的插件名稱
        compiler.hooks.run.tap(pluginName, compilation => {
            console.log("webpack 構建過程開始!");
        });
    }
}
複製代碼

一些插件簡介vue

Name Description
AggressiveSplittingPlugin 將原來的 chunk 分紅更小的 chunk
BabelMinifyWebpackPlugin 使用 babel-minify進行壓縮
BannerPlugin 在每一個生成的 chunk 頂部添加 banner
CommonsChunkPlugin 提取 chunks 之間共享的通用模塊
CompressionWebpackPlugin 預先準備的資源壓縮版本,使用 Content-Encoding 提供訪問服務
ContextReplacementPlugin 重寫 require 表達式的推斷上下文
CopyWebpackPlugin 將單個文件或整個目錄複製到構建目錄
DefinePlugin 容許在編譯時(compile time)配置的全局常量
DllPlugin 爲了極大減小構建時間,進行分離打包
EnvironmentPlugin DefinePlugin 中 process.env 鍵的簡寫方式。
ExtractTextWebpackPlugin 從 bundle 中提取文本(CSS)到單獨的文件
HotModuleReplacementPlugin 啓用模塊熱替換(Enable Hot Module Replacement - HMR)
HtmlWebpackPlugin 簡單建立 HTML 文件,用於服務器訪問
I18nWebpackPlugin 爲 bundle 增長國際化支持
IgnorePlugin 從 bundle 中排除某些模塊
LimitChunkCountPlugin 設置 chunk 的最小/最大限制,以微調和控制 chunk
LoaderOptionsPlugin 用於從 webpack 1 遷移到 webpack 2
MinChunkSizePlugin 確保 chunk 大小超過指定限制
NoEmitOnErrorsPlugin 在輸出階段時,遇到編譯錯誤跳過
NormalModuleReplacementPlugin 替換與正則表達式匹配的資源
NpmInstallWebpackPlugin 在開發時自動安裝缺乏的依賴
ProvidePlugin 沒必要經過 import/require 使用模塊
SourceMapDevToolPlugin 對 source map進行更細粒度的控制
EvalSourceMapDevToolPlugin 對 eval source map 進行更細粒度的控制
UglifyjsWebpackPlugin 能夠控制項目中 UglifyJS 的版本
ZopfliWebpackPlugin 經過 node-zopfli 將資源預先壓縮的版本

更多第三方插件,請查看 awesome-webpack 列表。java


用法案例:CommonsChunkPlugin

The CommonsChunkPlugin 已經從 webpack v4 legato 中移除。想要了解在最新版本中如何處理 chunk,請查看 SplitChunksPlugin(該插件配置過程更爲便捷高效)。node

element-ui初始化工程爲例看下 vendor.js

import Vue from 'vue'
import ElementUI from 'element-ui'
複製代碼

因爲插件能夠攜帶參數/選項,你必須在 webpack 配置中,向 plugins 屬性傳入 new 實例。根據你的 webpack 用法,這裏有多種方式使用插件。react

//package.json中引入依賴
"devDependencies": {
    ...
    "html-webpack-plugin": "^2.24.1",
    "webpack": "^2.4.1",
    ...
 }
複製代碼
//webpack.config.js中引入
//經過 npm 直接安裝插件
const HtmlWebpackPlugin 
    = require('html-webpack-plugin');
//訪問webpack內置的插件
//CommonsChunkPlugin就是內置插件之一
const webpack = require('webpack'); 
複製代碼

功能:該插件用於提取 chunks 之間共享的通用模塊。使用 CommonsChunkPlugin 從「應用程序 bundle」中提取 vendor 引用(vendor reference) 到 vendor bundle,並把引用 vendor 的部分替換爲 __webpack_require__() 調用jquery

entry.vendorCommonChunkPlugin的關係是怎麼樣的呢?CommonChunkPlugin的缺點是啥呢?webpack

...ios


Node API(O(∩_∩)O~,這個是啥)

TODO」即使使用 Node API,用戶也應該在配置中傳入 plugins 屬性。compiler.apply 並非推薦的使用方式。

//some-node-script.js
//訪問 webpack 運行時(runtime)
const webpack = require('webpack'); 
const configuration = require('./webpack.config.js');

let compiler = webpack(configuration);
compiler.apply(new webpack.ProgressPlugin());

compiler.run(function(err, stats) {
// ...
});
複製代碼

你知道嗎:以上看到的示例和 webpack 自身運行時(runtime) 極其相似。wepback 源碼中隱藏有大量使用示例,你能夠用在本身的配置和腳本中。


官網插件

HtmlWebpackPlugin

根據配置的入口和出口,自動生成index.html,且會自動引入相關的依賴。

  • 若是你想要了解更多 HtmlWebpackPlugin 插件提供的所有功能和選項,那麼你就應該多多熟悉 HtmlWebpackPlugin 倉庫。
  • 你還能夠看一下 html-webpack-template,除了默認模板以外,還提供了一些額外的功能。

CleanWebpackPlugin

  • 你可能已經注意到,因爲過去的指南和代碼示例遺留下來,致使咱們的 /dist 文件夾至關雜亂。
  • webpack 會生成文件,而後將這些文件放置在 /dist 文件夾中,可是 webpack 沒法追蹤到哪些文件是實際在項目中用到的。
  • 一般,在每次構建前清理 /dist 文件夾,是比較推薦的作法,所以只會生成用到的文件。讓咱們完成這個需求。
  • clean-webpack-plugin 是一個比較普及的管理插件,讓咱們安裝和配置下。
npm install clean-webpack-plugin --save-dev
複製代碼
  • webpack.config.js中配置:
const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    plugins: [
+     new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Output Management'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };
複製代碼
  • 如今執行 npm run build,再檢查 /dist 文件夾。若是一切順利,你如今應該不會再看到舊的文件,只有構建後生成的文件!

WebpackManifestPlugin

該插件可以在項目根目錄生成一份manifest.json的文件,經過該文件的映射關係可讓咱們知道webpack是如何追蹤全部模塊並映射到輸出bundle中的。

解讀webpack-manifest-plugin

//安裝插件:
npm install --save-dev webpack-manifest-plugin

//在 webpack.config.js中引入,大體以下:
var ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
   // ...
   plugins: [
     new ManifestPlugin() 
     // ManifestPlugin方法能夠接受一些選項參數options,如
     // new ManifestPlugin(options)
   ]
};

//3.可選參數以下:
options.fileName 表示要生成文件的名稱,默認爲manifest.json
options.publicPath 表示生成映射文件的路徑,默認爲output.publicPath

還有其餘的參數見官網
https://github.com/danethurber/webpack-manifest-plugin
複製代碼

HotModuleReplacementPlugin

開發環境啓用 HMR:啓用此功能實際上至關簡單。而咱們要作的,就是更新 webpack-dev-server 的配置,和使用 webpack 內置的 HMR 插件

IgnorePlugin

importrequire 調用時,忽略如下正則表達式匹配的模塊:

// requestRegExp 匹配(test)資源請求路徑的正則表達式。
// contextRegExp (可選)匹配(test)資源上下文(目錄)的正則表達式。
new webpack.IgnorePlugin(
    requestRegExp, [contextRegExp]
)
複製代碼

舉例:moment

好比咱們要使用moment這個第三方依賴庫,該庫主要是對時間進行格式化,而且支持多個國家語言。

import moment from 'moment'

//設置語言
moment.locale('zh-cn');
let r = moment().endOf('day').fromNow();
console.log(r);
複製代碼
  • 這樣打印出來的就是中文的時間,由於我在使用這個API的時候,前面設置了語言類型moment.locale爲中文zh-cn
  • 可是,雖然我設置了語言爲中文,可是在打包的時候,是會將全部語言都打包進去的。這樣就致使包很大,打包速度又慢
  • 因此,最好可以少打包一些沒用的依賴目錄進去
  • moment的包含./locale/該字段路徑的文件目錄就是各國語言的目錄,好比./locale/zh-cn就是中文語言
  • 使用IgnorePlugin
let webpack = require('webpack');
plugins:[
    //moment這個庫中,若是引用了./locale/目錄的內容,
    //就忽略掉,不會打包進去
    new webpack.IgnorePlugin(/\.\/locale/,/moment/),
]
複製代碼
  • 咱們雖然按照上面的方法忽略了包含./locale/該字段路徑的文件目錄,可是也使得咱們使用的時候不能顯示中文語言了,因此這個時候能夠手動引入中文語言的目錄
import moment from 'moment'
//手動引入所須要的語言包
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
let r = moment().endOf('day').fromNow();
console.log(r);
複製代碼
  • 這樣就OK了。既可以顯示中文,又把沒必要要的語言包都忽略打包了

DllPlugin

DLLPluginDLLReferencePlugin 用某種方法實現了拆分 bundles,同時還大大提高了構建的速度dll是一種最簡單粗暴而且極其有效的優化方式)。

  1. Webpack 打包的時候,對於一些不常常更新的第三方庫,好比 reactlodash,咱們但願能和本身的代碼分離開,Webpack 社區有兩種方案 CommonsChunkPluginDLLPlugin
  2. 對於 CommonsChunkPlugin
    • webpack 每次打包實際仍是須要去處理這些第三方庫,只是打包完以後,能把第三方庫和咱們本身的代碼分開。
    • 且每次工程從新打包,verdors也會從新打包,打包的chunkhash就會改變,致使每次發佈,vendors的緩存都會失效。這樣增長了用戶的流量消耗和首屏加載時間。
  3. DLLPlugin 則是能把第三方代碼徹底分離開,即每次只打包項目自身的代碼。引入的第三方包沒有改變就不須要從新打包。
  4. DLLPlugin具體用法:
/** 要使用 DLLPlugin,須要額外新建一個配置文件。 因此對於用這種方式打包的項目, 通常會有下面兩個配置文件: webpack.config.js webpack.dll.config.js 先來看下 webpack.dll.config.js */
const webpack = require('webpack')
const library = '[name]_lib'
const path = require('path')
module.exports = {
    entry: {
        vendors: ['react', 'lodash']
        //上面的vendors,看到有人有的libs
    },
    output: {
        filename: '[name].dll.js',
        path: 'dist/',
        library
    },
    plugins: [
        new webpack.DllPlugin({
        //執行的上下文環境,對以後DllReferencePlugin有用
            context: __dirname,
            path: path.join(
                __dirname, 'dist/[name]-manifest.json'
            ),
            // This must match the output.library option above
            name: library
        }),
    ],
}


//再改下 webpack.config.js 文件
const webpack = require('webpack')
module.exports = {
    entry: {
      app: './src/index'
    },
    output: {
      filename: 'app.bundle.js',
      path: 'dist/',
    },
    plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            //下面的vendors有人用libs
            manifest: require('./dist/vendors-manifest.json')
        })
    ]
}

/** manifest: require('./dist/vendors-manifest.json') 這裏的路徑要和 webpack.dll.config.js 裏面的對應。 而後運行: */
$ webpack --config webpack.dll.config.js
$ webpack --config webpack.config.js

//而後你的 html 文件像下面這樣引用
<script src="/dist/vendors.dll.js"></script>
<script src="/dist/app.bundle.js"></script>

/** 上面的用法也存在一些不方便的地方, 好比在 webpack.config.js 中要明確 指出對應的 manifest.json 文件。 還有當 DLL 須要更新的時候, 好比 react 升級了,或者加入新的第三方庫, 都須要手動像下面這樣編譯一次。 */
$ webpack --config webpack.dll.config.js


/** ---非官方插件(不需關注,沒有緩存做用了吧?)---- 由於上面這些問題, 因此基於官方的 DllReferencePlugin, 有一個 Dll Link Plugin。連接以下: www.npmjs.com/package/dll-link-webpack-plugin 使用這個插件, 只須要對 webpack.config.js 做下小小的改動 */
const webpack = require('webpack')
const DllLinkPlugin = require('dll-link-webpack-plugin')

module.exports = {
    // ...
    plugins: [
        new DllLinkPlugin({
            config: require('webpack.dll.config.js')
        })
    ]
}
/** 直接替換掉 DllReferencePlugin, 而後傳入對應的 DLL 配置文件就能夠了。 每次打包的時候,只須要運行 */
$ webpack --config webpack.config.js
/** 上面的命令便會自動生成對應的 vendors 文件, 須要更新的時候,也會自動更新。 */
複製代碼

SplitChunksPlugin

  1. 在默認狀況下,SplitChunksPlugin 僅僅影響按需加載的代碼塊,由於更改初始塊會影響HTML文件應包含的腳本標記以運行項目。

  2. webpack將根據如下條件自動拆分代碼塊:

    • 會被共享的代碼塊或者 node_mudules 文件夾中的代碼塊
    • 體積大於30KB的代碼塊(在gz壓縮前)
    • 按需加載代碼塊時的並行請求數量不超過5個
    • 加載初始頁面時的並行請求數量不超過3個
    //舉例:
    
    // 文件一:impvue.js
    import 'vue'
    ...
    
    // 文件二:index.js
    // 動態加載 impvue.js
    import('./impvue')
    ...
    
    /**
    打包以後的結果會建立一個包含 vue 的獨立代碼塊,
    當包含 impvue.js 的原始代碼塊被調用時,
    這個獨立代碼塊會並行請求進來。
    緣由:
        1) vue 來自 node_modules 文件夾
        2) vue 體積超過30KB
        3) 導入調用時的並行請求數爲2
        4) 不影響頁面初始加載
    */
    
    複製代碼
  3. 咱們這樣作的緣由是由於,vue代碼並不像你的業務代碼那樣常常變更,把它單獨提取出來就能夠和你的業務代碼分開緩存,極大的提升效率。

  4. SplitChunksPlugin的默認配置

splitChunks: {
    /** chunks屬性用來選擇分割哪些代碼塊, 可選值有: 'all'(全部代碼塊) 'async'(按需加載的代碼塊) 'initial'(初始化代碼塊) */
    chunks: "async",
    minSize: 30000, // 模塊的最小體積
    minChunks: 1, // 模塊的最小被引用次數
    maxAsyncRequests: 5, // 按需加載的最大並行請求數
    maxInitialRequests: 3, // 一個入口最大並行請求數
    automaticNameDelimiter: '~', // 文件名的鏈接符
    name: true,
    /** 緩存組是個有趣的功能: 在默認設置中, 會將`node_mudules`中的模塊打包進`vendors`, 引用超過兩次的模塊分配到`default` `bundle` 中。 更能夠經過 `priority` 來設置優先級。 */
    cacheGroups: { // 緩存組
        vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10
        },
        default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
        }
    }
}
複製代碼
  1. 在項目中添加SplitChunksPlugin
/** 爲了方便演示,咱們先安裝兩個類庫: lodash 和 axios, npm i lodash axios -S 修改 main.js,引入 lodash 和axios 並調用相應方法: */
import Modal from './components/modal/modal'
import './assets/style/common.less'
import _ from 'lodash'
import axios from 'axios'
const App = function () {
  let div = document.createElement('div')
  div.setAttribute('id', 'app')
  document.body.appendChild(div)
  let dom = document.getElementById('app')
  let modal = new Modal()
  dom.innerHTML = modal.template({
    title: '標題',
    content: '內容',
    footer: '底部'
  })
}
const app = new App()
console.log(_.camelCase('Foo Bar'))
axios.get('aaa')

/** ----------------------------- 使用SplitChunksPlugin不須要安裝任何依賴, 只需在 webpack.config.js 中的 config對象 添加 optimization 屬性: */
optimization: {
    splitChunks: {
      chunks: 'initial',
      automaticNameDelimiter: '.',
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: 1
        }
      }
    },
    //通常都配合runtimeChunkPlugin使用
    runtimeChunk: {
      name: entrypoint => `manifest.${entrypoint.name}`
    }
  }
/** 配置 runtimeChunk 會給每一個入口添加一個只包含runtime的額外的代碼塊, name 的值也能夠是字符串,不過這樣就會給每一個入口添加相同的 runtime, 配置爲函數時,返回當前的entry對象,便可分入口設置不一樣的runtime。 */

/** 咱們再安裝一個 webpack-bundle-analyzer, 這個插件會清晰的展現出打包後的各個bundle所依賴的模塊: 引入: */
const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin
//使用,在plugins數組中添加便可:
new BundleAnalyzerPlugin()
複製代碼
  1. 能夠看看Webpack4SplitChunksPlugin這裏說起的問題

BannerPlugin

爲每一個 chunk 文件頭部添加 banner(註釋/版權)。

new webpack.BannerPlugin(options)
//options選項:
{
  banner: string, // 其值爲字符串,將做爲註釋存在
  raw: boolean, // 若是值爲 true,將直出,不會被做爲註釋
  entryOnly: boolean, // 若是值爲 true,將只在入口 chunks 文件中添加
  test: string | RegExp | Array,
  include: string | RegExp | Array,
  exclude: string | RegExp | Array,
}
複製代碼

CopyWebpackPlugin:拷貝靜態文件

將單個文件或整個目錄直接從源目錄拷貝到構建目錄.

//config:配置了一些參數
new CopyWebpackPlugin([
  {
    from: path.resolve(__dirname, '../static'),
    to: config.build.assetsSubDirectory,
    ignore: ['.*']
  },
  //上面的static目錄先無論,
  //咱們先看這個,文件中是一些客戶可自行修改的配置
  //獨立出來,方便修改
  {
    from: path.resolve(config.directory.root, 'sysconfig.js'),
    to: 'sysconfig.js'
  },
])
複製代碼

打包好的工程下:

ExtractTextWebpackPlugin:分離CSS文件

MiniCssExtractPlugin這個呢?

const ExtractTextPlugin 
    = require("extract-text-webpack-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader"
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin("styles.css"),
    /** 我看咱們的工程中是這樣配置的 具體的後續再好好看下: new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), allChunks: true, }), */
  ]
}
複製代碼

它會將全部的入口 chunk(entry chunks)中引用的 *.css,移動到獨立分離的 CSS 文件。所以,你的樣式將再也不內嵌到 JS bundle 中,而是會放到一個單獨的 CSS 文件(即 styles.css)當中。 若是你的樣式文件大小較大,這會作更快提早加載,由於 CSS bundle 會跟 JS bundle 並行加載。

再來看個CSS優化(壓縮)相關的另外一個插件optimize-css-assets-webpack-plugin:

/**這個插件能夠接受下列配置(均爲可選): assetNameRegExp: 正則,用於匹配須要優化的資源名。默認值是 /\.css$/g cssProcessor: 用於壓縮和優化CSS 的處理器,默認是 cssnano.這是一個函數, 應該按照 cssnano.process 接口(接受一個CSS和options參數,返回一個Promise) canPrint: {bool} 表示插件可以在console中打印信息,默認值是true */

// webpack4+
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// webpack4 
module.exports = {
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourcMap: true
      }),
      new OptimizeCssAssetsPlugin({
        assetNameRegExp: /\.optimize\.css$/g,
        cssProcessor: require('cssnano'),
        cssProcessorOptions: { safe: true, discardComments: { removeAll: true } },
        canPrint: true
      }),
    ],
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    }),
  ]
};

//webpack3中通常配合 ExtractTextPlugin一塊兒使用。
複製代碼

UglifyjsWebpackPlugin

此插件使用uglify-js進行js文件的壓縮。

  • 下面說明是來自:關閉開發環境的代碼壓縮UglifyJsPlugin
  • 開發環境是不須要去壓縮代碼,主要是由於太耗性能了,每修改一個地方就要花幾秒去等待頁面渲染,很是浪費開發時間,解決辦法就是配置不一樣的環境變量
  • 去在開發環境的時候不要這個UglifyJsPlugin插件,爲此,webpack4又增長了新的Mode,且默認值是production;並且更新後的webpack默認是有UglifyJsPlugin這個配置的
  • 也就是說在不設置任何環境變量的狀況下,始終會有壓縮代碼的行爲出現,致使編譯極其耗時,那個人解決辦法就是在package.json文件啓動時設置環境變量:

Tree Shaking:一個術語,一般用於描述移除 JavaScript 上下文中的未引用代碼(dead-code)。新的webpack 4 正式版本,擴展了這個檢測能力,經過 package.jsonsideEffects 屬性做爲標記,向 compiler 提供提示,代表項目中的哪些文件是 pure(純的 ES2015 模塊),由此能夠安全地刪除文件中未使用的部分。

  • 這種方式是經過 package.jsonsideEffects 屬性來實現的。
{
  "name": "your-project",
  "sideEffects": false
}
複製代碼
  • 若是你的代碼確實有一些反作用,那麼能夠改成提供一個數組:
{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js"
  ]
}
複製代碼
  • webpack 4 開始,也能夠經過 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: "production"
};
複製代碼

DefinePlugin

實用webpack插件之DefinePlugin

DefinePlugin 容許建立一個在編譯時能夠配置的全局常量。這可能會對開發模式和發佈模式的構建容許不一樣的行爲很是有用。若是在開發構建中,而不在發佈構建中執行日誌記錄,則可使用全局常量來決定是否記錄日誌。這就是 DefinePlugin 的用處,設置它,就能夠忘記開發和發佈構建的規則。

new webpack.DefinePlugin({
/** 在vue-cli建立的項目中, 凡是src下的文件,均可以訪問到下面這些變量,如VERSION, 例如main.js,App.vue等等 */
  PRODUCTION: JSON.stringify(true),
  VERSION: JSON.stringify("5fa3b9"),
  BROWSER_SUPPORTS_HTML5: true,
  TWO: "1+1",
  //根據process.env.NODE_ENV區分環境,引入配置文件
  process.env: {NODE_ENV: "development"},
})
複製代碼

EnvironmentPlugin: 是一個經過 DefinePlugin 來設置 process.env 環境變量的快捷方式。

new webpack.EnvironmentPlugin(['NODE_ENV', 'DEBUG'])
//上面的寫法和下面這樣使用 DefinePlugin 的效果相同:
new webpack.DefinePlugin({
 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
 'process.env.DEBUG': JSON.stringify(process.env.DEBUG)
})
複製代碼

HashedModuleIdsPlugin

該插件會根據模塊的相對路徑生成一個四位數的hash做爲模塊id, 建議用於生產環境。用該插件可使vendor(第三方庫)的hash保持不變。參照指南中的緩存一節:模塊標識符

//其餘具體說明再看看
new webpack.HashedModuleIdsPlugin({
  hashFunction: 'sha256',
  hashDigest: 'hex',
  hashDigestLength: 20
})
複製代碼

ZipPlugin(好像官網沒列)

發佈的時候可使用 壓縮插件將資源(圖片,配置文件等)壓縮成一個 .zip 文件

//參數中配置了須要將工程打包
if (config.build.productionToZip) {
  const ZipPlugin = require('zip-webpack-plugin')
  webpackConfig.plugins.push(
    new ZipPlugin({
      path: config.build.assetsZipRoot,
      filename: 'build.zip',
      extension: 'zip',
    })
  )
}
複製代碼

ModuleConcatenationPlugin

  • webpack2處理後的每一個模塊均被一個函數包裹,以下:
/* 50 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
    window.lib = {}
    ...   
/* harmony default export */ __webpack_exports__["a"] = (window.lib);
 
/***/ }),
複製代碼
  • 這樣會帶來一個問題:下降瀏覽器中JS執行效率,這主要是閉包函數下降了JS引擎解析速度。
  • 因而webpack團隊參考Closure CompilerRollup JS,將一些有聯繫的模塊,放到一個閉包函數裏面去,經過減小閉包函數數量從而加快JS的執行速度。
  • webpack3經過設置ModuleConcatenationPlugin使用這個新特性:
module.exports = { 
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
}
複製代碼
  • 記住,此插件僅適用於由 webpack 直接處理的 ES6 模塊。在使用轉譯器(transpiler)時,你須要禁用對模塊的處理(例如 Babel 中的 modules 選項)。

NpmInstallWebpackPlugin

在開發時自動安裝缺乏的依賴:package.json中須要配置了纔會自動安裝哦

//安裝
npm install --save-dev npm-install-webpack-plugin

//用法
//不要忘記引入哦
const NpmInstallPlugin = require('npm-install-webpack-plugin')
//插件配置:
plugins: [
  new NpmInstallPlugin()
],

//至關於:
plugins: [
  new NpmInstallPlugin({
    // 使用 --save 或者 --save-dev
    dev: false,
    // 安裝缺乏的 peerDependencies
    peerDependencies: true,
    // 減小控制檯日誌記錄的數量
    quiet: false,
    // npm command used inside company, yarn is not supported yet
    npm: 'tnpm'
  });
],

//能夠提供一個 Function 來動態設置 dev:
plugins: [
  new NpmInstallPlugin({
    dev: function(module, path) {
      return [
        "babel-preset-react-hmre",
        "webpack-dev-middleware",
        "webpack-hot-middleware",
      ].indexOf(module) !== -1;
    },
  }),
],
複製代碼

ProvidePlugin

自動加載模塊,而沒必要處處 importrequire

//要自動加載 jquery,咱們能夠將兩個變量都指向對應的 node 模塊:
new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'
})
//而後在咱們任意源碼中:
$('#item'); // <= 起做用
jQuery('#item'); // <= 起做用

//使用:Lodash Map
new webpack.ProvidePlugin({
  _map: ['lodash', 'map']
})

//使用:Vue.js
new webpack.ProvidePlugin({
  Vue: ['vue/dist/vue.esm.js', 'default']
})
複製代碼

LimitChunkCountPlugin

當你在編寫代碼時,可能已經添加了許多代碼分離點(code split point)來實現按需加載(load stuff on demand)。在編譯完以後,你可能會注意到有一些很小的 chunk - 這產生了大量 HTTP 請求開銷。幸運的是,此插件能夠經過合併的方式,後處理你的 chunk,以減小請求數。

//改善`chunk`傳輸的插件

//LimitChunkCountPlugin
new webpack.optimize.LimitChunkCountPlugin({
  maxChunks: 5, // 必須大於或等於 1
  minChunkSize: 1000
})

/**MinChunkSizePlugin: 經過合併小於 minChunkSize 大小的 chunk, 將 chunk 體積保持在指定大小限制以上。 */
new webpack.optimize.MinChunkSizePlugin({
  // Minimum number of characters
  minChunkSize: 10000 
})

/** AggressiveSplittingPlugin能夠將 bundle拆分紅更小的chunk, 直到各個 chunk 的大小達到 option 設置的 maxSize。 它經過目錄結構將模塊組織在一塊兒。 */
new webpack.optimize.AggressiveSplittingPlugin({
    minSize: 30000, // 字節,分割點。默認:30720
    maxSize: 50000, // 字節,每一個文件最大字節。默認:51200
    chunkOverhead: 0, // 默認:0
    entryChunkMultiplicator: 1, // 默認:1
})
複製代碼

SourceMapDevToolPlugin

開發模式下的插件工具瞭解下

生成source map的兩種配置

  1. 配置devtool
//最簡單的生成source map的方式是,以下配置webpack.config.js,
const path = require('path');

module.exports = {
    devtool: 'source-map',
    entry: {
        index: path.resolve(__dirname, 'src/index.js'),
    },
    output: {
        devtoolModuleFilenameTemplate: '[resource-path]',
        path: path.resolve(__dirname, 'dist/'),
        filename: 'index.js',
    },
    module: {
        rules: [
            { 
                test: /\.js$/, 
                use: { 
                    loader: 'babel-loader', 
                    query: { presets: ['@babel/preset-env'] } 
                } 
                
            },
        ]
    },
};
/** 其中,devtool默認值爲false, 配置爲source-map表示以獨立的文件形式生成source map。 所以,dist/ 文件夾下,會產生兩個文件, index.js index.js.map index.js文件末尾,webpack會自動添加一行註釋, //# sourceMappingURL=index.js.map 瀏覽器解析到這裏,會自動根據index.js的相對路徑,請求map文件並加載它。 */
複製代碼
  1. SourceMapDevToolPlugin
/** 除了直接配置devtool以外, 還可使用webpack官方插件SourceMapDevToolPlugin, 進行更細粒度的source map配置。 */
const path = require('path');
const webpack = require('webpack');

module.exports = {
    // devtool: 'source-map',
    entry: {
        index: path.resolve(__dirname, 'src/index.js'),
    },
    output: {
        // devtoolModuleFilenameTemplate: '[resource-path]',
        path: path.resolve(__dirname, 'dist/'),
        filename: 'index.js',
    },
    module: {
        rules: [
            { 
                test: /\.js$/, 
                use: { 
                    loader: 'babel-loader', 
                    query: { presets: ['@babel/preset-env'] } 
                } 
            },
        ]
    },
    plugins: [
        new webpack.SourceMapDevToolPlugin({
            filename: '[file].map',
            moduleFilenameTemplate: '[resource-path]',
            append: '\n//# sourceMappingURL=http://127.0.0.1:8080/dist/[url]'
        }),
    ],
};
/** 以上配置中,咱們註釋掉了 devtool和devtoolModuleFilenameTemplate, 將它們配置到了SourceMapDevToolPlugin中。 這樣配置,dist/目錄最後也會生成兩個文件, index.js index.js.map 因爲咱們使用了該插件的append功能, 修改了sourceMappingURL地址, 所以,index.js末尾source map文件的地址就變成了, //# sourceMappingURL=http://127.0.0.1:8080/dist/index.js.map */
複製代碼
  1. 注:這裏值得一提的是
同時配置devtool和SourceMapDevToolPlugin是不行的,
index.js文件末尾會被添加兩行sourceMappingURL,
//# sourceMappingURL=http://127.0.0.1:8080/dist/index.js.map
//# sourceMappingURL=index.js.map

並且map文件的內容也不正確,是一個空的map文件,
複製代碼
  1. EvalSourceMapDevToolPlugin:對 eval source map 進行更細粒度的控制
  2. webpack——devtool裏的7SourceMap模式 咱們先來看看文檔對這 7 種模式的解釋:
模式 解釋
eval 每一個module會封裝到 eval 裏包裹起來執行,而且會在末尾追加註釋 //@ sourceURL.
source-map 生成一個SourceMap文件.
hidden-source-map 和 source-map 同樣,但不會在 bundle 末尾追加註釋.
inline-source-map 生成一個 DataUrl 形式的 SourceMap 文件.
eval-source-map 每一個module會經過eval()來執行,而且生成一個DataUrl形式的SourceMap
cheap-source-map 生成一個沒有列信息(column-mappings)的SourceMaps文件,不包含loader的 sourcemap(譬如 babel 的 sourcemap)
cheap-module-source-map 生成一個沒有列信息(column-mappings)的SourceMaps文件,同時 loader 的 sourcemap 也被簡化爲只包含對應行的。
- 注1:webpack 不只支持這 7 種,
並且它們仍是能夠任意組合上面的eval、inline、hidden關鍵字,
就如文檔所說,你能夠設置 souremap 選項爲:
    cheap-module-inline-source-map。

- 注2:若是你的modules裏面已經包含了SourceMaps,
你須要用source-map-loader 來和合並生成一個新的 SourceMaps。
複製代碼

還有不少其餘的,須要時自行搜索學習便可

......


Webpack打包優化

Webpack 4進階

跟着Vue-cli來'學'打包優化

相關文章
相關標籤/搜索