webpack优化与插件集合

快速上手

webpack 是一款项目模块打包器

起步,快速上手移步至 webpack 概念open in new window

压缩优化

深度 TreeShaking

  • webpack-deep-scope-plugin

  • webpack-parallel-uglify-plugin

  • purifycss-webpack

HTML 压缩

html-webpack-pluginopen in new window

new HtmlWebpackPlugin({
  inlineSource: ".css$",
  template: path.join(__dirname, `src/${pageName}/index.html`),
  filename: `${pageName}.html`,
  chunks: ["vendors", pageName],
  inject: true,
  minify: {
    html5: true,
    collapseWhitespace: true,
    preserveLineBreaks: false,
    minifyCSS: true,
    minifyJS: true,
    removeComments: false,
  },
});

图片压缩

image-webpack-loaderopen in new window

module.exports = {
  module: {
    rules: [{
      test: /\.(gif|png|jpe?g|svg)$/i,
      use: [
        'file-loader',
        {
          loader: 'image-webpack-loader',
          options: {
            bypassOnDebug: true, // webpack@1.x
            disable: true, // webpack@2.x and newer
          },
        },
      ],
    }]
  },
};

CSS 压缩

optimize-css-assets-webpack-pluginopen in new window

const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

webpackConfig.optimization = {
  // 启动压缩
  minimize: !(isWatchMode() || process.env.BABEL_ENV === 'test'),
  minimizer: [
    // CSS资源优化
    new OptimizeCSSAssetsPlugin({
      cssProcessorOptions: {
        // discardComments: {removeAll: true },
        // 避免 cssnano 重新计算 z-index
        //  safe: true,
        // cssnano通过移除注释、空白、重复规则、过时的浏览器前缀以及做出其他的优化来工作,一般能减少至少 50% 的大小
        // cssnano 集成了autoprefixer的功能。会使用到autoprefixer进行无关前缀的清理。默认不兼容ios8,会去掉部分webkit前缀,比如flex
        // 所以这里选择关闭,使用postcss的autoprefixer功能
        autoprefixer: false
      }
    })
  ],
  };

打包速度优化

代码求值

prepack-webpack-pluginopen in new window,对之前的代码进行求值,让下次打包更快!

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

速度分析

speed-measure-webpack-pluginopen in new window

speed-measure

cache-loader

通过上面的插件(speed-measure-webpack-plugin),可以分析到哪个 loader 速度过慢,我们就可以使用 cache-loaderopen in new window

module.exports = {
  module: {
    rules: [
      {
        test: /\.ext$/,
        use: ['cache-loader', ...loaders],
        include: path.resolve('src'),
      },
    ],
  },
};

开启全局缓存

对整个开启全局缓存,强缓存,慎用

hard-source-webpack-pluginopen in new window

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
 
module.exports = {
  plugins: [
    new HardSourceWebpackPlugin()
  ]
}

代码拆分

externals 配置去掉不需要编译的,可以抛弃 dll

splitChunks 公⽤库的代码拆分 去除打包

splitChunks: {
  chunks: 'async',
  minSize: 30000,
  minChunks: 1,
  maxAsyncRequests: 5,
  maxInitialRequests: 3,
  name: false,
  cacheGroups: {
    commons: {
      chunks: 'initial',
      minChunks: 2,
      maxInitialRequests: 5,
      minSize: 0,
      name: 'commons',
    },
  },
}

分离⻚⾯公⽤包 html-webpack-externals-pluginopen in new window

动态引入

@babel/plugin-syntax-dynamic-import

@babel/plugin-syntax-dynamic-importopen in new window 用以解析识别import()动态导入语法---并非转换,而是解析识别

.babelrc

{
  "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

动态polyfill

  1. js脚本直接引入,不编译
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?feature=Map,Set"></script>

使用动态,它会根据你的浏览器UA头,判断你是否支持某些特性,从而返回给你一个合适的polyfill。https://cdn.polyfill.io/v3/open in new window

<script type="module" src="main.js"></script>
<script nomodule src="main.es5.js"></script>
  1. 项目配置
$ npm install -S @babel/polyfill

# 项目入口引入 @babel/polyfill
import "@babel/polyfill"

此时打包会发现体积很大,下面配置根据自己的业务代码去加载对应的 polyfill

{
  test: /\.js$/,
  exclude: /node_modules/,
  loader: "babel-loader",
  options: {
    "presets": [['@babel/preset-env', {
      useBuiltIns: 'usage'
    }]]
  }
}

// 设置浏览器兼容版本
{
  loader: "babel-loader",
  options: {
    "presets": [['@babel/preset-env', {
      "targets": {
        "edge": "17",
        "firefox": "60",
        "chrome": "67",
        "safari": "11.1",
      }
    ]]
  }
},

配置优化

resolveLoader

如果我们编写了自定义的 Loarder,我们 需要引用 path.resolve(__dirname, './loaders/replaceLoader.js') 很不雅观,我们可以通过设置 resolveLoader 来达到和正常的 loader 引入一样。

resolveLoader: {
  modules: ['node_modules', 'loaders']
}

resolve

合理的配置 alias 可以让我们在引用路径的时候更加方便,过多的配置会影响打包速度

resolve: {
  alias: {
    '@': resolve('src'),
    '@less': resolve('less'),
    '@datas': resolve('datas'),
  }
}

shimming

使用 shimming 的配置如下

const webpack = require('webpack');

plugins: [
  new webpack.ProvidePlugin({
      '$': 'jquery',
  })
]

如果一个模块中使用了 $ 字符串,就会在模块中自动得引用jquery

生产力工具

打包进度条

progress-bar-webpack-pluginopen in new window

友好错误提示

friendly-errors-webpack-pluginopen in new window 识别某些类别的webpack错误,并清理,聚合和优先级,以提供更好的开发人员体验。

配合 webpack-dev-server 使用

const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

new FriendlyErrorsWebpackPlugin({
  compilationSuccessInfo: {
    messages: ['You application is running here http://localhost:8080'],
    notes: [
      'Some additionnal notes to be displayed unpon successful compilation',
    ],
  },
  onErrors: function (severity, errors) {
    //安装node-notifier 只想提示错误的话
  },
  quiet: true,
  clearConsole: true,
}),

通知提示运行状态

webpack-build-notifieropen in new window

const WebpackBuildNotifierPlugin = require('webpack-build-notifier');
 
module.exports = {
  plugins: [
    new WebpackBuildNotifierPlugin({
      title: "My Project Webpack Build",
      logo: path.resolve("./img/favicon.png"),
      suppressSuccess: true
    })
  ],
}
webpack-build-notifier

可视化分析打包文件

webpack-bundle-analyzeropen in new window 是一款在线可视化分析你打包文件的工具,可以让你清楚的看到每个文件的大小

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
 
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

webpack 分析面板

webpack-dashboardopen in new window 增强了 webpack 的输出,包含依赖的大小、进度和其他细节

webpack-dashboard

资源引用

更多构建工具

彩蛋

你是否经常会开多个终端窗口,一多人就懵逼了,别怕

const setTitle = require('node-bash-title');
const setIterm2Badge = require('set-iterm2-badge');

setTitle('🍻  Webpack开发环境配置');
setIterm2Badge('🍻 Dev开发');
Last Updated:
Contributors: kk