[vuejs/vue-cli]使用multi-page模式时chunks无法注入script

2023-12-19 298 views
8
Version

3.11.0

Environment info
windows 10
Steps to reproduce
  1. 安装 vue-cli 工具
  2. 使用cli创建一个工程
  3. 配置pages参数
    
    const path = require('path');
    const fs = require('fs');
    const glob = require('glob');

const mode = require('./mode.config');

function resolve(dir) { return path.join(__dirname, dir); } const ROOT_PATH = resolve('../src/modules');

const entries = glob.sync(${ROOT_PATH}/**/main.js) || []; const useMultiplePages = ((entries.length > 0) && (mode.multiple === true)); const _pages = useMultiplePages ? {} : undefined;

console.log('PAGE MODE', useMultiplePages ? 'multi-page' : 'single');

if (useMultiplePages) { // 默认入口文件 _pages.app = { // page 的入口 entry: resolve('../src/main.js'), // 模板来源 template: resolve('../public/index.html'), // 在 dist/index.html 的输出 filename: 'index.html', // 当使用 title 选项时, // template 中的 title 标签需要是 <%= htmlWebpackPlugin.options.title %> title: '', // 在这个页面中包含的块,默认情况下会包含 // 提取出来的通用 chunk 和 vendor chunk。 // chunks: ['vendors', 'chunk-vendors', 'chunk-common', 'app'], };

// 子模块入口文件
entries.forEach((item, index) => {
    const name = path.basename(path.dirname(item));
    const template = path.join(path.dirname(item), 'public/index.html');
    const title = path.join(path.dirname(item), 'title');

    console.log(fs.readFileSync(title));

    _pages[name] = {
        // page 的入口
        entry: item,
        // 模板来源
        template: fs.existsSync(template) ? template : resolve('../public/index.html'),
        // 在 dist/index.html 的输出
        filename: `${name}/index.html`,
        // 当使用 title 选项时,
        // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
        title: fs.existsSync(title) ? fs.readFileSync(title, { encoding: 'utf8' }).replace(/^([\s]+)|([\s]+)$/g, '') : '',
        // 在这个页面中包含的块,默认情况下会包含
        // 提取出来的通用 chunk 和 vendor chunk。
        // chunks: ['vendors', 'chunk-vendors', 'chunk-common', name],
    };
});

console.log(_pages);

}

const pages = _pages;

// 多页配置 module.exports = pages;


4. 执行 serve 或 build
### What is expected?
能够正常渲染出页面

### What is actually happening?
1. chunks 没有注入到 HTML 页面中
2. 由于第1点,导致页面不能渲染显示。

---
在使用vue-cli创建一个工程时,使用multi-page模式。配置 pages 参数。
通执 serve 和 build 后,页面相关的 chunks 不会被注入到 HTML文件中,导致页面无法执行渲染。
在排查过程中,发现 html-webpack-plugin 插件在处理 chunks 参数时采用的是 绝对匹配 的方式来过滤 chunk。 我在 html-webpack-plugin ##的github也提了issue( #https://github.com/jantimon/html-webpack-plugin/issues/1319 ),如果 html-webpack-plugin的作者不采纳,cli 这边能否实现呢?

<!-- generated by vue-issues. DO NOT REMOVE -->

回答

1

很抱歉,请问能否更详细地描述一下你碰到的问题,以及需要我们实现什么功能? 目前的 issue 内容太过简略了,我无法理解到底是什么问题。

另外,对于 Bug 反馈,我们是要求必须提供可以运行的复现代码的(最好是一个 Git 仓库)

5

@sodatea 内容已更新,请看一下。谢谢

2

chunks: ['vendors', 'chunk-vendors', 'chunk-common', name], 这个配置不能注释,他的作用就是在HTML注入提取出来的通用 chunk 和 vendor chunk、当前单页js

5

chunks: ['vendors', 'chunk-vendors', 'chunk-common', 'app'] 是配置要注入到html的chunk 如果你保留的Preload的话,俺这儿有个插件,可以自动注入Preload的资源(因为Preload插件已经确定好了这个html需要的资源(有序)),就不用填这个选项了,然后你就可以随意拆分chunk了

4

可以不设置,如果这里没有设置,那么会有一个默认值会处理这个参数

4

这一个的问题是 html-webpack-plugin 这个插件处理问题

5
  1. 你提供的代码仍然不能直接运行,我还是不太明白你碰到的问题是什么
  2. 究竟是什么 chunks 没有注入到页面?具体改了哪些配置?是另外配置了 splitChunks 然后再改 pages 设置后出的问题吗?
  3. 如果 html-webpack-plugin的作者不采纳,cli 这边能否实现呢

    这里我也没懂你要 CLI 实现什么……

3

@sodatea 是所有的chunks都没有注入到页面。 关于第3点意思就是如果 html-webpack-plugin 里的filterChunks方法不调整过滤匹配规则,cli工具能否继承html-webpack-plugin,在他的基础上实现宽松的匹配规则(实现分支:https://github.com/zwlijun/html-webpack-plugin/tree/feature/multi-page-chunks)。这个修改我也在html-webpack-plugin的github上提交了pull requests,不过现在没有反应。 html-webpack-plugin 修改: 修改前的代码

  /**
   * Return all chunks from the compilation result which match the exclude and include filters
   * @param {any} chunks
   * @param {string[]|'all'} includedChunks
   * @param {string[]} excludedChunks
   */
  filterChunks (chunks, includedChunks, excludedChunks) {
    return chunks.filter(chunkName => {
      // Skip if the chunks should be filtered and the given chunk was not added explicity
      if (Array.isArray(includedChunks) && includedChunks.indexOf(chunkName) === -1) {
        return false;
      }
      // Skip if the chunks should be filtered and the given chunk was excluded explicity
      if (Array.isArray(excludedChunks) && excludedChunks.indexOf(chunkName) !== -1) {
        return false;
      }
      // Add otherwise
      return true;
    });
  }

修改后的代码:

  /**
   * Return all chunks from the compilation result which match the exclude and include filters
   * @param {any} chunks
   * @param {string[]|{test(chunkName: string): boolean}|((chunkName: string) => boolean)|'all'} includedChunks
   * @param {string[]|{test(chunkName: string): boolean}|((chunkName: string) => boolean)} excludedChunks
   */
  filterChunks (chunks, includedChunks, excludedChunks) {
    return chunks.filter(chunkName => {
      // Skip if the chunks should be filtered and the given chunk was not added explicity
      if (Array.isArray(includedChunks) && includedChunks.indexOf(chunkName) === -1) { // chunks: Array
        return false;
      } else if (includedChunks instanceof RegExp) { // chunks: RegExp
        return includedChunks.test(chunkName);
      } else if (typeof includedChunks === 'function') { // chunks: Function
        return includedChunks(chunkName);
      }
      // if (Array.isArray(includedChunks) && includedChunks.indexOf(chunkName) === -1) {
      //   return false;
      // }

      // Skip if the chunks should be filtered and the given chunk was excluded explicity
      if (Array.isArray(excludedChunks) && excludedChunks.indexOf(chunkName) !== -1) { // chunks: Array
        return false;
      } else if (excludedChunks instanceof RegExp) { // chunks: RegExp
        return !excludedChunks.test(chunkName);
      } else if (typeof excludedChunks === 'function') { // chunks: Function
        return excludedChunks(chunkName);
      }
      // if (Array.isArray(excludedChunks) && excludedChunks.indexOf(chunkName) !== -1) {
      //   return false;
      // }
      // Add otherwise
      return true;
    });
  }
3

我大概懂你的问题了(虽然还是没明白什么情况下才会出现这个问题)

但既然是上游插件的问题的话,我认为 Vue CLI 不应该为了修一个小 bug 而直接 fork 过来改。我们没有这个精力保证后续的持续维护。

如果你实在有需要,可以自己在 package.json 里添加 resolutions 字段,把 html-webpack-plugin 指向你 fork 修改后的 GitHub 仓库 (yarn 直接支持解析 resolutions,npm 可以用 https://www.npmjs.com/package/npm-force-resolutions)