webpack优化

61 阅读3分钟

纪录一下自己的webpack优化的一点笔记

开发优化(dllplugin)

dllplugin也叫预打包,当插件安装多了以后,webpack每次运行/热更新都会很慢,所以需要我们做一次预打包,尤其是对于一些庞大的老vue2项目更是非做不可了,具体的配置流程如下

1.最外层目录新建dll.js,在这里定义需要预打包的包

const path = require('path')
const DllPlugin = require('webpack/lib/DllPlugin')
//const { srcPath, distPath } = require('@/utils/paths')
const dllPath = 'public/vendor'
module.exports = {
  mode: 'development',
  // JS 执行入口文件
  entry: {
    // 把 React 相关模块的放到一个单独的动态链接库
    // dllplugin预打包element有问题
    // vue 打包进去也会有问题
    vue: [
      'vue-router',
      'echarts',
      'vue',
      'vuex',
      'wangeditor',
      'axios',
      'lodash',
      'echarts-gl',
      'uuid'
    ]
  },
  output: {
    // 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
    // 也就是 entry 中配置的 react 和 polyfill
    filename: '[name].dll.js',
    // 输出的文件都放到 dist 目录下
    path: path.join(__dirname, dllPath),
    // 存放动态链接库的全局变量名称,例如对应 react 来说就是 _dll_react
    // 之所以在前面加上 _dll_ 是为了防止全局变量冲突
    library: '_dll_[name]'
  },
  plugins: [
    // 接入 DllPlugin
    new DllPlugin({
      // 动态链接库的全局变量名称,需要和 output.library 中保持一致
      // 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
      // 例如 react.manifest.json 中就有 "name": "_dll_react"
      name: '_dll_[name]',
      // 描述动态链接库的 manifest.json 文件输出时的文件名称
      path: path.join(path.join(__dirname, dllPath), '[name].manifest.json')
    })
  ]
}

接着在vue.config.js中配置预打包命令

// dll动态链
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
   config.plugins.push(
      new DllReferencePlugin({
        //  context: __dirname,
        // manifest就是我们第3步中打包出来的json文件
        //    manifest: require('./vendor-manifest.json'),
        manifest: require('./public/vendor/vue.manifest.json')
      })
    )

接着在入门文件index.html引入已经预打包好的包

<script src="./vendor/vue.dll.js"></script>

这里是我的文件路径,大家可以参考

image.png

生产优化 cdn,入口index.html引入常用包cdn服务器地址,优化产出包大小

const cdn = {
  css: ['https://unpkg.com/element-ui/lib/theme-chalk/index.css'],
  js: [
    'https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js',
    'https://unpkg.com/element-ui/lib/index.js'
  ]
}
   config.externals = {
        // <script></script>标签会生成一个全局属性
        vue: 'Vue',
        'element-ui': 'ELEMENT'
        //  vuex: 'Vuex',
        //   'vue-router': 'VueRouter',
        // axios: 'axios'
      }
    }
     if (isProd) {
      //生产环境注入cdn
      config.plugin('html').tap((args) => {
        args[0].cdn = cdn
        return args
      })
    }

在入门index.html文件引入

 <title><%= htmlWebpackPlugin.options.title %></title>
    <!-- 使用CDNCSS文件 -->
    <% for (var i in htmlWebpackPlugin.options.cdn &&
    htmlWebpackPlugin.options.cdn.css) { %>
    <!-- <link
      href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
      rel="preload"
      as="style"
    /> -->
    <link
      href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
      rel="stylesheet"
    />
    <% } %>
    <!-- 使用CDNJS文件 -->
  </head>
  <body>
    <noscript>
      <strong>
        We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
        properly without JavaScript enabled. Please enable it to continue.
      </strong>
    </noscript>
    <div id="app"></div>
    <% for (var i in htmlWebpackPlugin.options.cdn &&
    htmlWebpackPlugin.options.cdn.js) { %> -->
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>

生产优化其余的办法

    // 修改抽离css插件
      config.plugin('extract-css').tap(() => [
        {
          filename: 'css/[name].[contenthash:8].${timeStamp}.css',
          chunkFilename: 'css/[name].[contenthash:8].${timeStamp}.css'
        }
     ])
     // 对异步同步代码都做处理
        chunks: 'all',
        // 缓存分组      
        cacheGroups: {
          vendor: {
            name: 'vendor', // chunk 名称
            priority: 1, // 权限更高,优先抽离,重要!!!
            test: /node_modules/,
            // minSize: 0, // 大小限制
            minChunks: 1 // 最少复用过几次
          },
          // 公共的模块
          common: {
            name: 'common', // chunk 名称
            priority: 0 // 优先级
            //   minSize: 0, // 公共模块的大小限制
            //  minChunks: 2 // 公共模块最少复用过几次
          }
        }
      }) 

补充一点,对于刚打包出来文件需要用户手动清理缓存这个问题如何解决?

  // 输出重构 打包编译后的js文件名称,添加时间戳
    config.output.filename(`js/js[name].${timeStamp}.js`)
    config.output.chunkFilename(`js/chunk.[id].${timeStamp}.js`)
    
    在入口文件上添加 no store/cache,强行不走缓存

切割js代码优化

   config.optimization.splitChunks({
        chunks: "all",
        cacheGroups: {
          libs: {
            name: "chunk-libs",
            test: /[\\/]node_modules[\\/]/,
            priority: 10,
            chunks: "initial", // only package third parties that are initially dependent
          },
          elementUI: {
            name: "chunk-elementUI", // split elementUI into a single package
            priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
            test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
          },
          commons: {
            name: "chunk-commons",
            test: resolve("src/components"), // can customize your rules
            minChunks: 3, //  minimum common number
            priority: 5,
            reuseExistingChunk: true,
          },
        },
      });