在入口点自动加载块

问题描述

Webpack 配置是 Vue CLI 设置的一部分(可以使用 vue inspect 检查)。这是其中的一个相关部分:

  entry: {
    foo: [
      '.../src/foo.js'
    ],barWidget: [
      '.../src/barWidget.js'
    ],},optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          name: 'chunk-vendors',test: /[\\/]node_modules[\\/]/,priority: -10,chunks: 'initial'
        },common: {
          name: 'chunk-common',minChunks: 2,priority: -20,chunks: 'initial',reuseExistingChunk: true
        }
      }
    },...

HTML 输出是:

<script type="text/javascript" src="/assets/js/chunk-vendors.[HASH].js"></script>
<script type="text/javascript" src="/assets/js/foo.[HASH].js"></script>

<script type="text/javascript" src="/assets/js/chunk-vendors.[HASH].js"></script>
<script type="text/javascript" src="/assets/js/barWidget.[HASH].js"></script>

foo 拥有尽可能多的脚本标签没有问题,但 barWidget 是小部件入口点,应该立即加载,没有初始块依赖项。我的目的是让 barWidget 加载一行代码(为此目的可能会禁用哈希):

<script type="text/javascript" src="/assets/js/barWidget.js"></script>

但在当前状态下,如果省略 chunk-vendors,则无法加载。

我更愿意保留 vendorscommon 块,因为它们以合理的方式拆分并且可以在客户端的入口点之间重复使用,但我需要 {{1}自动加载它所依赖的块。一种不太可取的方法是禁用块,但仅对于 barWidget,其他入口点中的块拆分应保持不变。

重现它的方法基本上是一个添加了 2 个入口点的新 Vue CLI 项目,或者任何具有类似配置拆分的 Webpack 项目。

这里是 the project(为了完整性而列出):

package.json

barWidget

vue.config.js

{
  "name": "foobar","scripts": {
    "serve": "vue-cli-service serve","build": "vue-cli-service build"
  },"dependencies": {
    "core-js": "^3.6.5","vue": "^3.0.0"
  },"devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0","@vue/cli-service": "~4.5.0","@vue/compiler-sfc": "^3.0.0"
  }
}

public/foo.html

public/barWidget.html

module.exports = {
  pages: {
    foo: {
      entry: 'src/foo.js',template: 'public/foo.html',filename: 'foo.html'
    },barWidget: {
      entry: 'src/barWidget.js',template: 'public/barWidget.html',filename: 'barWidget.html'
    },};

src/foo.js

<!DOCTYPE html>
<html>
  <body>
    <div id="app"></div>
  </body>
</html>

Foo.vue

import { createApp } from 'vue'
import Foo from './Foo.vue'

createApp(Foo).mount('#app')

src/barWidget.js

<template>
  <HelloWorld msg="Foo"/>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  components: {
    HelloWorld
  }
}
</script>

BarWidget.vue

import { createApp } from 'vue'
import BarWidget from './BarWidget.vue'

createApp(BarWidget).mount('#app')
  • 可以通过 Webpack 强制 <template> <HelloWorld msg="Bar widget"/> </template> <script> import HelloWorld from './components/HelloWorld.vue' export default { components: { HelloWorld } } </script> 自动加载 barWidget,而无需在使用 chunk-vendors.[HASH].js 的地方显式加载吗?

  • 可以强制 barWidget.[HASH].js 入口点不使用其他初始块(barWidget 等)并输出自给自足的 chunk-vendors 包,而不影响拆分的工作方式其他入口点?

  • 对于所描述的场景还有其他选择吗?

解决方法

我认为您想要的是本webpack issue reply

回复使用一个函数来排除特定入口点的依赖项,使其不包含在块中:

  optimization: {
    splitChunks: {
      cacheGroups: {
          vendors: {
            // ... your current config,just change the chunks property            

            // Exclude pre-main dependencies going into vendors,as doing so
            // will result in webpack only loading pre-main once vendors loaded.
            // But pre-main is the one loading vendors.
            // Currently undocument feature:  https://github.com/webpack/webpack/pull/6791
            chunks: chunk => chunk.name !== "barWidget"
          }
      }
    }
  },

要使用 vue 执行此操作,只需像这样更改 vue.config.js 文件中的 webpack 配置:

module.exports = {
  configureWebpack: config => {
     config.optimization.splitChunks.cacheGroups.vendors.chunks = 
       chunk => chunk.name !== "barWidget";
  }
}

我还没有尝试过这个,但我认为它应该可以正常工作或进行一些最小的调整

,

您可以使用函数来过滤块。看到这个Webpack issue

vue.confi.js

module.exports = {
  pages: {
    foo: {
      entry: 'src/foo.js',template: 'public/foo.html',filename: 'foo.html'
    },barWidget: {
      entry: 'src/barWidget.js',template: 'public/barWidget.html',filename: 'barWidget.html',chunks: ['barWidget']
    },},chainWebpack: config => {
    if (process.env.NODE_ENV !== 'test') {
      config.optimization.splitChunks({
        cacheGroups: {
          defaultVendors: {
            name: `chunk-vendors`,test: /[\\/]node_modules[\\/]/,priority: -10,chunks: chunk => chunk.name !== "barWidget"
          },common: {
            name: `chunk-common`,minChunks: 2,priority: -20,chunks: 'initial',reuseExistingChunk: true
          }
        }
      })
    }
  }
}

注意 pages.barWidget.chunks - 它是必需的,否则 HtmlWebpackPlugin 会将供应商块包含到 barWidget.html 中,即使它根本不需要...

结果: Result