Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

icejs x vite mode support custom chunkName #4818

Closed
imsobear opened this issue Oct 28, 2021 · 3 comments
Closed

icejs x vite mode support custom chunkName #4818

imsobear opened this issue Oct 28, 2021 · 3 comments
Assignees

Comments

@imsobear
Copy link
Collaborator

imsobear commented Oct 28, 2021

What is the current behavior? 发生了什么?

image

vitejs/vite#745 (comment)

What is the expected behavior? 期望的结果是什么?

image

Any additional comments? 相关环境信息?

  • ice.js Version:2
  • build.json Configuration
  • Node Version:
  • Platform:
@ClarkXia
Copy link
Collaborator

vite 模式下生成 chunkName 主要包括以下两个问题:

  1. 分包的 chunk 名称无法通过 /webpackChunkName: "name"/ 的形式定制,特殊定制的情况下需要根据 build.rollupOptions.output.chunkFileNames
  2. 生成的 css 名称的后缀随机,无法确定入口需要提前加载的 css 文件是 index.css 还是 index2.css

问题 1 可以通过一定的规则进行自定义,问题 2 在后端输出 html 内容的部署模式下影响面较大,以下内容主要针对问题 2 的原因进行分析

css 在 rollup 中属于 assets 如需定制名称可以通过 build.rollupOptions.output.assetFileNames 进行定制,但由于 vite 内部的一些逻辑,导致无法获取构建产物的 css 文件来源,基本无法确定 index 中需要输出的 css 地址是什么

chunkFileNames 输出的信息
image

assetFileNames 输出的信息
image

导致上述原因的一些讨论:
vitejs/vite#5046
vitejs/vite#2375 (comment)

代码层面无法直接通过 generateBundle 分析出主要 css bundle 的原因:

https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/css.ts#L489-L505

在 vite 工程内部对 bundle 的信息进行了过滤,并通过 chunkToEmittedCssFileMap 的变量记录了 css chunk 相关信息,但这部分信息未暴露 API,导致 generateBundle 获取的 bundle 信息不全

对于后端输出的资源地址,vite 官方推荐结合 manifest 进行输出确定 index 和 css 的地址 https://vitejs.dev/guide/backend-integration.html#backend-integration

<!-- if production -->
<link rel="stylesheet" href="/assets/{{ manifest['main.js'].css }}" />
<script type="module" src="/assets/{{ manifest['main.js'].file }}"></script>

解决方案

问题一:定制 chunkName

如果上图所示 chunkFileNames 中的信息包含 facadeModuleId 和 isDynamicEntry 字段,开发者可以定制相应的方法实现自定义 bundle 的诉求。
对于 /webpackChunkName: "name"/ 的支持,需要在工程启动之前扫描源码中所有的 dynamic import 逻辑,并解析出 webpackChunkName 和具体 import 地址的对应关系,最终生成 chunkFileNames 函数实现。
一些实现手段:

  • 扫描逻辑配合 esbuild + es-module-lexer 进行,最终通过正则匹配获取 webpackChunkName 和具体加载的 dynamic import 的地址
  • dynamic import 的地址可以存在 alias 的情况,需要前置获取所有 alias 配置并进行解析匹配

问题二:无法确定主 css 地址

通过 manifest 中的信息获取主 css 地址,manifest 信息无法直接通过 generateBundle 获取,可以通过劫持其执行的逻辑获取到 manifest 信息:

{
  buildStart({ plugins }) {
    viteManifest = plugins.find(
      ({ name }) => name === 'vite:manifest',
    );
  },
  generateBundle: async (options, bundle, isWrite) => {
    // 记录 manifest 信息
    let filesData;
    await viteManifest.generateBundle.call(
      {
        ...this,
        emitFile: (file) => {
          if (file.type === 'chunk') return 'chunk id'
          filesData = JSON.parse(file.source as string)
          return 'asset id'
        },
      },
      options,
      bundle,
      isWrite,
    )
  },
}

默认情况下主 css 地址会直接输出到 html 页面中,不依赖 js 动态进行挂载,因此在确定主 css 资源内容后,生成一个指定的文件即可(比如默认以 index-main.css 命名)

@komaedaXnagito
Copy link

问一下问题2的解决方案能使用了吗?

@ClarkXia
Copy link
Collaborator

问一下问题2的解决方案能使用了吗?

已支持配置 cssChunkNames

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants