18個webpack插件總有一款適合你的

前言

何爲插件(Plugin)?專一處理 webpack 在編譯過程當中的某個特定的任務的功能模塊,能夠稱爲插件。javascript

Plugin 是一個擴展器,它豐富了 webpack 自己,針對是 loader 結束後,webpack 打包的整個過程,它並不直接操做文件,而是基於事件機制工做,會監聽 webpack 打包過程當中的某些節點,執行普遍的任務。css

Plugin 的特色html

  • 是一個獨立的模塊
  • 模塊對外暴露一個 js 函數
  • 函數的原型 (prototype) 上定義了一個注入 compiler 對象的 apply方法 apply 函數中須要有經過 compiler 對象掛載的 webpack 事件鉤子,鉤子的回調中能拿到當前編譯的 compilation 對象,若是是異步編譯插件的話能夠拿到回調 callback
  • 完成自定義子編譯流程並處理 complition 對象的內部數據
  • 若是異步編譯插件的話,數據處理完成後執行 callback 回調。

HotModuleReplacementPlugin

模塊熱更新插件。Hot-Module-Replacement 的熱更新是依賴於 webpack-dev-server,後者是在打包文件改變時更新打包文件或者 reload 刷新整個頁面,HRM 是隻更新修改的部分。vue

HotModuleReplacementPluginwebpack模塊自帶的,因此引入webpack後,在plugins配置項中直接使用便可。java

const webpack = require('webpack')

plugins: [
  new webpack.HotModuleReplacementPlugin(), // 熱更新插件
]

html-webpack-plugin

生成 html 文件。將 webpack 中entry配置的相關入口 chunkextract-text-webpack-plugin抽取的 css 樣式 插入到該插件提供的template或者templateContent配置項指定的內容基礎上生成一個 html 文件,具體插入方式是將樣式link插入到head元素中,script插入到head或者body中。node

const HtmlWebpackPlugin = require('html-webpack-plugin')

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: path.join(__dirname, '/index.html'),
    minify: {
      // 壓縮HTML文件
      removeComments: true, // 移除HTML中的註釋
      collapseWhitespace: true, // 刪除空白符與換行符
      minifyCSS: true, // 壓縮內聯css
    },
    inject: true,
  }),
]

inject 有四個選項值react

  • true:默認值,script 標籤位於 html 文件的 body 底部
  • body:script 標籤位於 html 文件的 body 底部(同 true)
  • head:script 標籤位於 head 標籤內
  • false:不插入生成的 js 文件,只是單純的生成一個 html 文件

多頁應用打包jquery

有時,咱們的應用不必定是一個單頁應用,而是一個多頁應用,那麼如何使用 webpack 進行打包呢。webpack

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  entry: {
    index: './src/index.js',
    login: './src/login.js',
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash:6].js',
  },
  //...
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html', //打包後的文件名
    }),
    new HtmlWebpackPlugin({
      template: './public/login.html',
      filename: 'login.html', //打包後的文件名
    }),
  ],
}

若是須要配置多個 HtmlWebpackPlugin,那麼 filename 字段不可缺省,不然默認生成的都是 index.htmlios

可是有個問題,index.htmllogin.html 會發現,都同時引入了 index.f7d21a.jslogin.f7d21a.js,一般這不是咱們想要的,咱們但願 index.html 中只引入 index.f7d21a.jslogin.html 只引入 login.f7d21a.js

HtmlWebpackPlugin 提供了一個 chunks 的參數,能夠接受一個數組,配置此參數僅會將數組中指定的 js 引入到 html 文件中

module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html', //打包後的文件名
      chunks: ['index'],
    }),
    new HtmlWebpackPlugin({
      template: './public/login.html',
      filename: 'login.html', //打包後的文件名
      chunks: ['login'],
    }),
  ],
}

這樣執行 npm run build,能夠看到 index.html 中僅引入了 index 的 js 文件,而 login.html 中也僅引入了 login 的 js 文件。

clean-webpack-plugin

clean-webpack-plugin 用於在打包前清理上一次項目生成的 bundle 文件,它會根據 output.path 自動清理文件夾;這個插件在生產環境用的頻率很是高,由於生產環境常常會經過 hash 生成不少 bundle 文件,若是不進行清理的話每次都會生成新的,致使文件夾很是龐大。

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

plugins: [
  new HtmlWebpackPlugin({
    template: path.join(__dirname, '/index.html'),
  }),
  new CleanWebpackPlugin(), // 所要清理的文件夾名稱
]

extract-text-webpack-plugin

將 css 成生文件,而非內聯 。該插件的主要是爲了抽離 css 樣式,防止將樣式打包在 js 中引發頁面樣式加載錯亂的現象

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

plugins: [
  // 將css分離到/dist文件夾下的css文件夾中的index.css
  new ExtractTextPlugin('css/index.css'),
]

mini-css-extract-plugin

將 CSS 提取爲獨立的文件的插件,對每一個包含 css 的 js 文件都會建立一個 CSS 文件,支持按需加載 css 和 sourceMap。只能用在 webpack4 中,對比另外一個插件 extract-text-webpack-plugin 有如下特色:

  • 異步加載
  • 不重複編譯,性能更好
  • 更容易使用
  • 只針對 CSS

這個插件應該只用在生產環境配置,而且在 loaders 鏈中不使用 style-loader, 並且這個插件暫時不支持 HMR

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.(le|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../',
            },
          },
          'css-loader',
          'postcss-loader',
          'less-loader',
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css',
      chunkFilename: 'css/[id].[contenthash:8].css',
    }),
  ],
}

purifycss-webpack

有時候咱們 css 寫得多了或者重複了,這就形成了多餘的代碼,咱們但願在生產環境進行去除。

const path = require('path')
const PurifyCssWebpack = require('purifycss-webpack') // 引入PurifyCssWebpack插件
const glob = require('glob') // 引入glob模塊,用於掃描所有html文件中所引用的css

module.exports = merge(common, {
  plugins: [
    new PurifyCssWebpack({
      paths: glob.sync(path.join(__dirname, 'src/*.html')),
    }),
  ],
})

optimize-css-assets-webpack-plugin

咱們但願減少 css 打包後的體積,能夠用到 optimize-css-assets-webpack-plugin

const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin") // 壓縮css代碼

optimization: {
  minimizer: [
    // 壓縮css
    new OptimizeCSSAssetsPlugin({})
  ]

UglifyJsPlugin

uglifyJsPluginvue-cli 默認使用的壓縮代碼方式,用來對 js 文件進行壓縮,從而減少 js 文件的大小,加速 load 速度。它使用的是單線程壓縮代碼,打包時間較慢,因此能夠在開發環境將其關閉,生產環境部署時再把它打開。

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

plugins: [
  new UglifyJsPlugin({
    uglifyOptions: {
      compress: {
        warnings: false
      }
    },
    sourceMap: true,  //是否啓用文件緩存
    parallel: true   //使用多進程並行運行來提升構建速度
  })

ParallelUglifyPlugin

開啓多個子進程,把對多個文件壓縮的工做分別給多個子進程去完成,每一個子進程其實仍是經過 UglifyJS 去壓縮代碼,可是變成了並行執行。

const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')

plugins: [
  new ParallelUglifyPlugin({
    //cacheDir 用於配置緩存存放的目錄路徑。
    cacheDir: '.cache/',
    sourceMap: true,
    uglifyJS: {
      output: {
        comments: false,
      },
      compress: {
        warnings: false,
      },
    },
  }),
]

terser-webpack-plugin

Webpack4.0 默認是使用 terser-webpack-plugin 這個壓縮插件,在此以前是使用 uglifyjs-webpack-plugin,二者的區別是後者對 ES6 的壓縮不是很好,同時咱們能夠開啓 parallel 參數,使用多進程壓縮,加快壓縮。

const TerserPlugin = require('terser-webpack-plugin') // 壓縮js代碼

optimization: {
  minimizer: [
    new TerserPlugin({
      parallel: 4, // 開啓幾個進程來處理壓縮,默認是 os.cpus().length - 1
      cache: true, // 是否緩存
      sourceMap: false,
    }),
  ]
}

NoErrorsPlugin

報錯但不退出 webpack 進程。編譯出現錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段。這樣能夠確保輸出資源不會包含錯誤。

plugins: [new webpack.NoEmitOnErrorsPlugin()]

compression-webpack-plugin

全部現代瀏覽器都支持 gzip 壓縮,啓用 gzip 壓縮可大幅縮減傳輸資源大小,從而縮短資源下載時間,減小首次白屏時間,提高用戶體驗。

gzip 對基於文本格式文件的壓縮效果最好(如:CSS、JavaScript 和 HTML),在壓縮較大文件時每每可實現高達 70-90% 的壓縮率,對已經壓縮過的資源(如:圖片)進行 gzip 壓縮處理,效果很很差。

const CompressionPlugin = require('compression-webpack-plugin')

plugins: [
  new CompressionPlugin({
    // gzip壓縮配置
    test: /\.js$|\.html$|\.css/, // 匹配文件名
    threshold: 10240, // 對超過10kb的數據進行壓縮
    deleteOriginalAssets: false, // 是否刪除原文件
  }),
]

固然,這個方法還須要後端配置支持。

DefinePlugin

咱們能夠經過 DefinePlugin 能夠定義一些全局的變量,咱們能夠在模塊當中直接使用這些變量,無需做任何聲明,DefinePluginwebpack 自帶的插件。

plugins: [
  new webpack.DefinePlugin({
    DESCRIPTION: 'This Is The Test Text.',
  }),
]

// 直接引用
console.log(DESCRIPTION)

ProvidePlugin

自動加載模塊。 任什麼時候候,當 identifier 被看成未賦值的變量時, module 就會自動被加載,而且 identifier 會被這個 module 輸出的內容所賦值。這是 webpack 自帶的插件。

module.exports = {
  resolve: {
    alias: {
      jquery: './lib/jquery',
    },
  },
  plugins: [
    //提供全局的變量,在模塊中使用無需用require引入
    new webpack.ProvidePlugin({
      $: 'jquery',
      React: 'react',
    }),
  ],
}

DLLPlugin

這是在一個額外的獨立的 webpack 設置中建立一個只有 dll 的 bundle(dll-only-bundle)。 這個插件會生成一個名爲 manifest.json 的文件,這個文件是用來讓 DLLReferencePlugin 映射到相關的依賴上去的。

使用步驟以下

一、在 build 下建立 webpack.dll.config.js

const path = require('path')
const webpack = require('webpack')
module.exports = {
  entry: {
    vendor: [
      'vue-router',
      'vuex',
      'vue/dist/vue.common.js',
      'vue/dist/vue.js',
      'vue-loader/lib/component-normalizer.js',
      'vue',
      'axios',
      'echarts',
    ],
  },
  output: {
    path: path.resolve('./dist'),
    filename: '[name].dll.js',
    library: '[name]_library',
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.resolve('./dist', '[name]-manifest.json'),
      name: '[name]_library',
    }),
    // 建議加上代碼壓縮插件,不然dll包會比較大。
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
      },
    }),
  ],
}

二、在 webpack.prod.conf.js 的 plugin 後面加入配置

new webpack.DllReferencePlugin({
  manifest: require('../dist/vendor-manifest.json'),
})

三、package.json文件中添加快捷命令(build:dll)

"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "node build/build.js",
    "build:dll": "webpack --config build/webpack.dll.conf.js"
  }

生產環境打包的時候先npm run build:dll命令會在打包目錄下生成 vendor-manifest.json 文件與 vendor.dll.js 文件。而後npm run build生產其餘文件。

四、根目錄下的入口 index.html 加入引用

<script type="text/javascript" src="./vendor.dll.js"></script>

HappyPack

HappyPack 能讓 webpack 把任務分解給多個子進程去併發的執行,子進程處理完後再把結果發送給主進程。要注意的是 HappyPackfile-loaderurl-loader 支持的不友好,因此不建議對該 loader 使用。

一、HappyPack 插件安裝

npm i -D happypack

二、webpack.base.conf.js 文件對 module.rules 進行配置

module: {
  rules: [
    {
      test: /\.js$/,
      use: ['happypack/loader?id=babel'],
      include: [resolve('src'), resolve('test')],
      exclude: path.resolve(__dirname, 'node_modules'),
    },
    {
      test: /\.vue$/,
      use: ['happypack/loader?id=vue'],
    },
  ]
}

三、在生產環境 webpack.prod.conf.js 文件進行配置

const HappyPack = require('happypack')
// 構造出共享進程池,在進程池中包含5個子進程
const HappyPackThreadPool = HappyPack.ThreadPool({ size: 5 })
plugins: [
  new HappyPack({
    // 用惟一的標識符id,來表明當前的HappyPack是用來處理一類特定的文件
    id: 'babel',
    // 如何處理.js文件,用法和Loader配置中同樣
    loaders: ['babel-loader?cacheDirectory'],
    threadPool: HappyPackThreadPool,
  }),
  new HappyPack({
    id: 'vue', // 用惟一的標識符id,來表明當前的HappyPack是用來處理一類特定的文件
    loaders: [
      {
        loader: 'vue-loader',
        options: vueLoaderConfig,
      },
    ],
    threadPool: HappyPackThreadPool,
  }),
]

注意,當項目較小時,多線程打包反而會使打包速度變慢。

copy-webpack-plugin

咱們在 public/index.html 中引入了靜態資源,可是打包的時候 webpack 並不會幫咱們拷貝到 dist 目錄,所以 copy-webpack-plugin 就能夠很好地幫我作拷貝的工做了。

const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        {
          from: 'public/js/*.js',
          to: path.resolve(__dirname, 'dist', 'js'),
          flatten: true,
        },
      ],
    }),
  ],
}

IgnorePlugin

這是 webpack 內置插件,它的做用是:忽略第三方包指定目錄,讓這些指定目錄不要被打包進去。

好比咱們要使用 moment 這個第三方依賴庫,該庫主要是對時間進行格式化,而且支持多個國家語言。雖然我設置了語言爲中文,可是在打包的時候,是會將全部語言都打包進去的。這樣就致使包很大,打包速度又慢。對此,咱們能夠用 IgnorePlugin 使得指定目錄被忽略,從而使得打包變快,文件變小。

const 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)

原文地址

相關文章
相關標籤/搜索