webpack4 代码分离

前沿

  • 刚开始将vue-cli版本升级到@vue-cli3版本时,查看@vue-cli3文档时,知道它会实现代码分离,自己写的demo时,打包时生成了大量的chunk文件,当时并没有想太多,觉得自己使用@vue-cli3版本成功,就以为自己掌握了它。直到开发项目时,需要处理项目中的chunk,只需要保留第三方vendor和本身的业务代码,这个时候自己去研究webpack和vue-cli才发现自己时井底之蛙,一直只是停留在使用的程度上,离真正的掌握还很遥远。下面是我处理该问题的思路。

MiniCssExtractPlugin

  • 刚开始处理时,想一步一步来处理,先处理css,将所有多与的css整合到一个完成的css文件中,
  • 这个时候,跟公司的老哥交流了一下,感谢他跟我讲了他经验,收益良多。他让我看看MiniCssExtractPlugin,webpack4专门用来处理css的插件,
  • 由于当前使用的是vue-cli3,它的vue.config.js配置想需要在chainWebpack中操作,于是参考了文档中以下的代码:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 
function recursiveIssuer(m) {
  if (m.issuer) {
    return recursiveIssuer(m.issuer);
  } else if (m.name) {
    return m.name;
  } else {
    return false;
  }
}
 
module.exports = {
  entry: {
    foo: path.resolve(__dirname, 'src/foo'),
    bar: path.resolve(__dirname, 'src/bar'),
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        fooStyles: {
          name: 'foo',
          test: (m, c, entry = 'foo') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
        barStyles: {
          name: 'bar',
          test: (m, c, entry = 'bar') =>
            m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
          chunks: 'all',
          enforce: true,
        },
      },
    },
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

下面是我的写法

  • 为何加上环境判断?是因为打包时,这个配置文件可正式运行,但是在本地开发时,会报TypeError: Cannot read property 'cacheGroups' of undefined的错误。
chainWebpack: (config) => {
    const fileRule = config.module.rule('file')
    fileRule.uses.clear()
    fileRule
      .test(/\.(xls|xlsx)$/)
      .include.add(path.resolve(__dirname, './src/uploadTemplate'))
      .end()
      .use('file-loader')
      .loader('file-loader')
      .options({
        name: '[path][name].[ext]',
      })
    if (process.env.NODE_ENV === 'production') { // 判断环境
      // console.log(config.optimization)
      const splitOptions = config.optimization.get('splitChunks')
      // 这里的 appStyles 中的 app 是入口文件的配置名称(从 vue inspect 中可以得到)
      splitOptions.cacheGroups.appStyles = {
        name: 'styles',
        test: (m, c, entry = 'app') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
        chunks: 'all',
        minChunks: 1,
        enforce: true,
      }
      config.optimization.splitChunks(splitOptions)
    }
  • 这种方案确实解决了css的chunk问题,但是所有的chunk都打包成了一个文件,但这种方法,js也打包出了一个同样名称的js文件,而且在继续使用类似的方法去修改js中的chunk时,却怎么也不生效。

import()

  • 此时上面的思路已经走不下去了,无法控制的打包整合,此时不得不麻烦一下我的leader,感谢他耐心你的帮我重新指明了方向import(),与ES新提案中的import()方法类似;
  • webpack官网原文:Dynamically load modules. Calls to import() are treated as split points, meaning the requested module and its children are split out into a separate chunk.
  • 简单的说,它的意思就是webpack以import()code-split,在工程打包阶段,webpack需要将所有import()的模块都进行单独打包.
  • 直到这个时候,我才知道问题的根本出在哪里,不说那么多,先建一个demo,将所有的文件使用import()动态引入,打包时发现出现大量的chunk文件,再换成import/from的方式,则仅仅css和js都只有vendors/app。完成需求。

import()的注释用法

onst ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')
const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')
// 没有指定webpackChunkName,每个组件打包成一个js文件。

const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')
const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')
// 这里指定了相同的webpackChunkName,会合并打包成一个js文件。
  • webpackChunkName: 从webpack 2.6.0开始,给定字符串中的占位符[index]和[request]分别支持递增的数字或实际解析的文件名。

你可能感兴趣的:(webpack4 代码分离)