emosheeep / vite-plugin-virtual-mpa

Out-of-box MPA plugin for Vite, generate multiple entries using only one template.
https://stackblitz.com/~/github.com/emosheeep/vite-plugin-virtual-mpa
MIT License
120 stars 15 forks source link

改进:仅根据实际 `pages` 配置响应虚拟入口,不在配置内的 html 资源由 vite 正常响应 #15

Closed jiadesen closed 1 year ago

jiadesen commented 1 year ago

如题

emosheeep commented 1 year ago

之前考虑过,不过因为实际使用的时候没有遇到相关场景所以也就搁置了,周末有空看下

emosheeep commented 1 year ago

我发现,不在配置内的文件依旧响应了,但是打包后的产物依旧是不包含的那些未配置的文件的,比如说example里面的index.html,产物里面并不存在这个文件,是不是会造成一些疑惑

jiadesen commented 1 year ago

vite 现在的默认行为是:

  1. 对于单页应用,使用根目录的 index.html 即可,所有配置默认即可,也没有必要使用这个插件。
  2. 对于多页应用,需要参照官方多页应用模式配置使用,而且一旦使用,构建产出将严格按照配置进行构建,这就意味着,如果将 main 注释掉,将不会构建默认的 index 入口,但该入口在开发环境依然可以访问
// vite.config.js
import { resolve } from 'path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        // 注释 index 入口
        // main: resolve(__dirname, 'index.html'),
        nested: resolve(__dirname, 'nested/index.html'),
      },
    },
  },
})

不在配置内的文件依旧响应了,但是打包后的产物依旧是不包含的那些未配置的文件的

所以,对于多入口需求,我们和官方设计保持一致,构建产物将严格按照多入口配置进行。

jiadesen commented 1 year ago

再看官方文档关于index.html 与项目根目录的描述,其中很重要的一句话是 在开发期间 Vite 是一个服务器,而 index.html 是该 Vite 项目的入口文件。这就意味着,项目所有的资源在开发期间都可以单独访问,这是Vite 只需要在浏览器请求源码时进行转换并按需提供源码的基础

emosheeep commented 1 year ago

我准备提供一下preview服务器的一些默认配置,遇到了一点问题,我再看看🤔

jiadesen commented 1 year ago

准备提供一下preview服务器的一些默认配置

没太明白,有什么诉求以及想达到的效果,可以详细说说么?

jiadesen commented 1 year ago

是 vite 的 preview 服务么?如果是的话这应该跟插件本身没有关系。

emosheeep commented 1 year ago

是的,因为开发和构建用的工具不一样,经常出现本地开发和线上效果不一样。所以总需要验证本地产物正确性。但是目前只做了开发服务器的配置,没有配置预览服务器,需要简单配置一下html fallback

jiadesen commented 1 year ago

预览服务是独立的,和开发服务可以共存啊,你是想通过开发服务访问产物么?

jiadesen commented 1 year ago

经常出现本地开发和线上效果不一样

这个问题也详细说说?我想我可以提供一些解决方案

emosheeep commented 1 year ago

经常出现本地开发和线上效果不一样

这个问题也详细说说?我想我可以提供一些解决方案

没事,这个问题主要来自于 rollup 和 esbuild 的表现不一致,发现一个解决一个就好了

jiadesen commented 1 year ago

发现一个解决一个就好了

这个很难受啊,比如使用 vant,通过提取所有 vant 样式到一个文件来解决开发和产物表现不一致的问题:

// 构建配置
build: {
    // 底层 Rollup 打包配置
    rollupOptions: {
        output: {
            manualChunks(id) {
                const regVantStyles =
                    /[\\/]node_modules[\\/]vant(.*)\.(s?css|less|sass)$/;

                switch (true) {
                    case regVantStyles.test(id):
                        return "chunk-vant-styles";
                }
            },
        },
    },
},
emosheeep commented 1 year ago

你这种还只是样式,我们直接是报错,比如开发时正常运行,线上报错,xxx is not a function,排查发现是一个函数的打包出来变成了default,就是原本 a(),现在要用a.default()。这中很明显就是打包工具差异性造成的,需要做一些额外配置才能保持一致

jiadesen commented 1 year ago

这么严重...我这使用 @vitejs/plugin-legacy 配合 .browserslistrc 配置一切都还好,兼容性目标跟 vue3 对齐,ios10 能跑往上就不再看了...

Chrome >= 51
iOS >= 10
emosheeep commented 1 year ago

不是浏览器问题,是产物问题,commonjs和esm的转换问题默认行为不一致

emosheeep commented 1 year ago

https://github.com/emosheeep/vite-plugin-virtual-mpa/pull/26 感兴趣可以看下

jiadesen commented 1 year ago

emosheeep commented 1 year ago

vite 现在的默认行为是:

  1. 对于单页应用,使用根目录的 index.html 即可,所有配置默认即可,也没有必要使用这个插件。
  2. 对于多页应用,需要参照官方多页应用模式配置使用,而且一旦使用,构建产出将严格按照配置进行构建,这就意味着,如果将 main 注释掉,将不会构建默认的 index 入口,但该入口在开发环境依然可以访问
// vite.config.js
import { resolve } from 'path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        // 注释 index 入口
        // main: resolve(__dirname, 'index.html'),
        nested: resolve(__dirname, 'nested/index.html'),
      },
    },
  },
})

不在配置内的文件依旧响应了,但是打包后的产物依旧是不包含的那些未配置的文件的

所以,对于多入口需求,我们和官方设计保持一致,构建产物将严格按照多入口配置进行。

https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/index.ts#L642-L643

我查看了官方的配置,官方根据 appType 为 mpa 还是 spa 来决定是否采用 spaFallback,这里应该就是你说的逻辑吧,对应的 htmlFallbackMiddleware 在这里

然后我感觉我们之前的实现有问题,也就是这块 https://github1s.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/htmlFallback.ts#L7

          {
            /** Vite's default behavior */
            from: /.*/,
            to: ctx => {
              const { parsedUrl: { pathname } } = ctx;
              return normalizePath(pathname?.endsWith('.html') ? pathname : `${pathname}/index.html`);
            },
          },

] 这里重定向有问题,pathname 如果是,/test/icon.svg 他会重定向到 /test/icon.svg/index.html

emosheeep commented 1 year ago

我觉得好像我们和这里保持一致就行了,判断下,如果只有一个page就认为是 spa 否则认为是 mpa,然后用官方的 fallback 插件就行

jiadesen commented 1 year ago

这里重定向有问题,pathname 如果是,/test/icon.svg 他会重定向到 /test/icon.svg/index.html

不是有 htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] 么,我这里测试没观察到问题...

jiadesen commented 1 year ago

要不你先改改看,我也研究下

emosheeep commented 1 year ago

是这样,我的场景

createMpaPlugin({
        rewrites: [
          // 开发环境使用boe.html作为entry
          { from: /\/audit\/((?!.*\.svg)).*/, to: '/audit/boe.html' },
        ],
        pages: [
          { name: 'boe', data: { iconPath: '/icon-boe.svg' } },
          { name: 'prod', data: { iconPath: '/icon-prod.svg' } },
        ],
      }),

我怀疑是不是我的rewrites写的有问题

emosheeep commented 1 year ago

有空再改改看,先搬砖了

emosheeep commented 1 year ago
image

上面那个配置,它就会变成这样,但是这个路劲他其实是vite 的 public目录下的内容 我发现很神奇的是,这个路径如果不直接通过浏览器地址栏输入,他就是可以正常被解析到图片的,但是如果在浏览器地址栏直接输入这个地址,就会出现这个问题,奇怪,是哪里理解的不对吗