Update 12-01: The htML-webpack-plugin already supports this plugin. javascript – How to use Webpack 4 SplitChunksPlugin with HtmlWebpackPlugin for Multiple Page Application? – Stack Overflow

A few days ago, a colleague asked such a question in the group: A vue-CLI startup project uses multi-page packaging to package two applications A and B. Application A introduces the Vant library ipunt component, and application B introduces the Vant library list component. If you pack the Vant into a separate package, it will have both inputs and Lists, so app A loads the List component it doesn’t need, and app B loads the input component it doesn’t need. How do you optimize?

The vuE-CLI’s own separation logic allows only two public chunks, chunk-vendors and chunk-common, to be separated at most. This can be seen by executing Vue Inspect under the VUE project.

Chunk-vendors indicate that all modules referenced under node_modules are grouped into one chunk. As you can see, this granularity is very coarse. This may be sufficient for general applications, but not for the requirements mentioned at the beginning of this article. So we need to configure WebPack to override the default configuration of Vue.

Vue-cli you can configureWebpack using vue.config.js. Write the configuration in the configureWebpack field.

We’ve created a vuE-CLI multi-page application as a demo, you can download it and have a look. Github link: github.com/neilzhang61…

In our example project, Vuant-tree-shaking, there are two application entries, index and subPage. The index. HTML page uses Vant’s Button component and Switch component. The subpage. HTML page uses vant Badge and Switch.

What we hope is that the shared switches can be packaged into chunk-vendors, and so only buttons used by index pages can be packaged into chunk-vant-indexes, Only the Badge used by the subpage page can be packed into chunk-ant -subpage.

The core file to implement this requirement is vue.config.js, which contains the following contents:

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  pages: {
    index: {
      // Page entry
      entry: 'src/main.js'.// Template source
      template: 'public/index.html'.// Output in dist/index.html
      filename: 'index.html'.// When using the title option,
      / / title of the template tag needs to be < title > < % = htmlWebpackPlugin. Options. The title % > < / title >
      title: 'Index Page'.// The blocks contained in this page are contained by default
      // The extracted generic chunk and Vendor chunk.
      chunks: ['chunk-vendors'.'chunk-vant-index'.'index']},// When using the entry only string format,
    // The template will be derived to 'public/subpage.html'
    // And if it can't be found, go back to 'public/index.html'.
    // The output file name is derived to 'subpage.html'.
    subpage: {
      entry: 'src/main2.js'.chunks: ['chunk-vendors'.'chunk-vant-subpage'.'subpage']}},productionSourceMap: false.configureWebpack: {
    plugins: [
      new BundleAnalyzerPlugin()
    ],
    optimization: {
      splitChunks: {
        cacheGroups: {
          vendors: {
            name: 'chunk-vendors'.test: /[\\/]node_modules[\\/]/,
            priority: -10.chunks: 'initial'
          },
          vantIndex: {
            name: 'chunk-vant-index'.// test: /[\\/]node_modules[\\/](vant)[\\/]/,
            test (module) {
              // console.log(module)
              const size = module._chunks.size
              let chunkName = ' '
              if (size === 1) {
                chunkName = [...module._chunks.values()][0].name
              }

              let path = module.resource
              if(! path)return false
              path = path.replace(/\\/g.'/')
              const result = path && /node_modules\/vant\n*/.test(path) && size === 1 && chunkName === 'index'
              return result
            },
            minSize: 1.priority: -5.chunks: 'all',},vantSubpage: {
            name: 'chunk-vant-subpage'.// test: /[\\/]node_modules[\\/](vant)[\\/]/,
            test (module) {
              // console.log(module)
              const size = module._chunks.size
              let chunkName = ' '
              if (size === 1) {
                chunkName = [...module._chunks.values()][0].name
              }

              let path = module.resource
              if(! path)return false
              path = path.replace(/\\/g.'/')
              const result = path && /node_modules\/vant\n*/.test(path) && size === 1 && chunkName === 'subpage'
              return result
            },
            minSize: 1.priority: -5.chunks: 'all',},}},}},}Copy the code

In this file, the two objects that come into play are vantIndex and vantSubpage. explain

  • nameField indicates the name of the file when it was generated.
  • testA field can be a regular expression or a function. When it is a function, if it returns true, it will be matchedmodeleThey were assigned to this chunk.
  • minSizeThe field represents the minimum byte limit for a chunk. The default value is 20000 bytes. Let’s change this to 1, otherwise if the chunk is too small, even if the test condition is met, the chunk will not separate.
  • priorityField indicates the priority. If multiple rules can be matched, which rule is preferred. Negative numbers are allowed. A larger number has a higher priority.
  • chunksThe fields indicate what chunks to extract code from, and there are three optional string values initial, Async, and all

As you can see, for our purposes, we are essentially determining when the test function in vantIndex and vantSubpage returns true.

Using vantSubpage as an example, the test function should return true if the following conditions are met:

  1. The currentmoduleIs a module under the Vant package. namely/node_modules\/vant\n*/.test(path)Is true, wherepathmodule.resourceYou can get it.
  2. The currentmoduleBe dependent on only one page. namelymodule._chunks.size === 1, includingmodule._chunksIs aSetIt stores dependencies on thismoduleThe description object of the page. When its length is 1, it means that only one page depends on thismodule.
  3. The currentmoduleThe name of the dependent page issubpage, i.e.,chunkName === 'subpage'.

VantIndex similarly.

After we execute YARN Build or NPM run build, we can split the chunk the way we want.

Chunk-vaant-index.d01042a3. js and chunk-vaant-subpage.53f1df41.js are chunks that the two separated pages cannot share.

We can also see using the BundleAnalyzerPlugin that chunk-vendor.b4fd1d08.js contains only the vant common code and vant Switch component code, Chunk-ant -index. d01042A3. js has only the code of Button component, chunk-ant -subpage.53f1df41.js has only the Badge. Our purpose has been achieved.

Although splitting chunks is of limited significance in the context of the examples in this article, there are other requirements that can be easily implemented once you understand how Webpack chunks are divided.

reference

  1. How can the vue.config.js file in VUe-cli3 be configured so that chunk-vendors are split to be referenced by different pages? · Issue #3018 · Vuejs /vue- CLI
  2. Webpack minSize of optimization of the subcontract and maxSize | xing-hai zhang’s personal blog – star blog – front end development
  3. SplitChunksPlugin | webpack