vikejs/vike

plugin-legacy breaks vike build (missing _temp_manifest.json)

kazuma1989 opened this issue · 27 comments

Description

Hi 👋

repro here 👉 https://github.com/kazuma1989/repro-vike-vite-plugin-legacy

I met an issue saying:

repro-vike-vite-plugin-legacy % npm run build

> build
> vite build

vite v4.4.9 building for production...
✓ 173 modules transformed.
computing gzip size (0)...[vike:buildConfig] [vike@0.4.142][Bug] You stumbled upon a bug in Vike's source code. Go to https://github.com/vikejs/vike/issues/new and copy-paste this error; a maintainer will fix the bug (usually under 24 hours).
✓ built in 3.81s
error during build:
Error: [vike@0.4.142][Bug] You stumbled upon a bug in Vike's source code. Go to https://github.com/vikejs/vike/issues/new and copy-paste this error; a maintainer will fix the bug (usually under 24 hours).
    at Object.writeBundle (file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/vike/dist/esm/node/plugin/plugins/buildConfig.js:54:17)
    at file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/rollup/dist/es/shared/node-entry.js:25544:40
    at async Promise.all (index 2)
    at PluginDriver.hookParallel (file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/rollup/dist/es/shared/node-entry.js:25472:9)
    at file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/rollup/dist/es/shared/node-entry.js:26792:13
    at catchUnfinishedHookActions (file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/rollup/dist/es/shared/node-entry.js:25910:16)
    at build (file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/vite/dist/node/chunks/dep-df561101.js:48011:22)
    at CAC.<anonymous> (file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/vite/dist/node/cli.js:822:9)

The file file:///Users/kazuma/kazuma1989/repro-vike-vite-plugin-legacy/node_modules/vike/dist/esm/node/plugin/plugins/buildConfig.js:54:17 in the stack trace corresponds to https://github.com/vikejs/vike/blob/v0.4.142/vite-plugin-ssr/node/plugin/plugins/buildConfig.ts#L72.

After investigating, I found that this occurs because the writeBundle hook will be called twice when using the plugin-legacy. When the hook is called the first time, Vite won't emit manifestEntry (e.g. _temp_manifest.json) yet.
cf. https://github.com/vitejs/vite/blob/v4.4.9/packages/vite/src/node/plugins/manifest.ts#L155

Cloud you please fix this? 🙏

Does everything work if you manually remove that assertion?

Thank you for reply 👍

Does everything work if you manually remove that assertion?

Sorry but no because the line after the assertion requires manifestEntry to exist.

const manifestFilePathOld = path.join(dir, manifestEntry.fileName);

(Optional chaining manifestEntry?.fileName doesn't work here because path.join() requires strings, not undefined.)

If I change the condition like below, everything works (build succeeds and the assets.json is emit).

         async writeBundle(options, bundle) {
             const manifestEntry = bundle[manifestTempFile];
-            if (generateManifest) {
+            if (generateManifest && manifestEntry) {
                 assert(manifestEntry);
                 const { dir } = options;
                 assert(dir);
                 const manifestFilePathOld = path.join(dir, manifestEntry.fileName);
                 // Ideally we'd move dist/_temp_manifest.json to dist/server/client-assets.json instead of dist/assets.json
                 //  - But we can't because there is no guarentee whether dist/server/ is generated before or after dist/client/ (generating dist/server/ after dist/client/ erases dist/server/client-assets.json)
                 //  - We'll able to do so once we replace `$ vite build` with `$ vike build`
                 const manifestFilePathNew = path.join(dir, '..', 'assets.json');
                 await fs.rename(manifestFilePathOld, manifestFilePathNew);
             }
             else {
                 assert(!manifestEntry);
             }
         }

Hm, seems like there is some kind regression on Vite's part. I'll check your reproduction later. Let me know if it's urgent (I can pre-release your workaround until I implement a proper fix).

Thank you very much! But it's not that urgent, so I don't want to bother you to make a pre-release.

the same bug, there is still a lot browsers not support module type

I'll have a look at it this week. As always: let me know if it's urgent.

I'll have a look at it this week. As always: let me know if it's urgent.

yes, I think it is urgent。 Because,without legacy plugin, we can't use vike in prod environment

If I change the condition like below, everything works

This temporary workaround is released as vike@0.4.142-commit-ebf6e2d. Let me know if you still get issues.

I'll implement a proper fix later this week.

It seems this has been broken again in v0.4.161 where this plugin has been refactored. At the moment, it is failing for us with

ENOENT: no such file or directory, open '/<obscured>/dist/client/_temp_manifest.json'

triggered from this line

const clientManifestMod = await fixServerAssets(outDirs)

Not really sure how this could be fixed yet.

This can be easily reproduced with the reproduction above when you install vike@0.4.163. It also persists when updating vite

npm install vike@latest vite@latest @vitejs/plugin-react@latest @vitejs/plugin-legacy@latest
npm run build

Actually, this reproduction is already broken starting with v0.4.151 for other reasons because it tries to read assets.json from the dist folder. If you build with v0.4.150 first, though, this issue does not manifest as it will just read the file from the previous build (which may not be relevant for the current build).

@lukastaegert I could indeed reproduce. It's again an issue with how Vike and the legacy plugin hooks themselves into Vite's build process. We're actually currently implementing a Vike CLI which should solve the problem once and for all.

Do you mind waiting until we release Vike's CLI? We'll likely need to make it a breaking change and thus release a new major which will delay its release. Let me know if it's a blocker.

Updated reproduction with latest Vike version: https://github.com/brillout/repro-vike-vite-plugin-legacy.

I think it is fine for us to stick with 0.4.150 for a little longer

Actually, re-implementing the workaround was easy. Fix pre-released as 0.4.163-commit-2305d5b.

Nice, this solves the issue above. In my local setup, which is a little bigger (and I did not manage to fully boil it down to a good reproduction), it now fails here

Error: [vike@0.4.163-commit-2305d5b][Bug] You stumbled upon a Vike bug. Go to https://github.com/vikejs/vike/issues/new and copy-paste this error. A maintainer will fix the bug (usually under 24 hours).
    at copyAssets (file:///.../node_modules/.pnpm/vike@0.4.163-commit-2305d5b_vite@5.1.4/node_modules/vike/dist/esm/node/plugin/plugins/buildConfig/fixServerAssets.js:41:5)
    at fixServerAssets (file:///.../node_modules/.pnpm/vike@0.4.163-commit-2305d5b_vite@5.1.4/node_modules/vike/dist/esm/node/plugin/plugins/buildConfig/fixServerAssets.js:25:11)
    at Object.handler (file:///.../node_modules/.pnpm/vike@0.4.163-commit-2305d5b_vite@5.1.4/node_modules/vike/dist/esm/node/plugin/plugins/buildConfig.js:81:51)
    at PluginDriver.hookParallel (file:///.../node_modules/.pnpm/rollup@4.12.0/node_modules/rollup/dist/es/shared/node-entry.js:19501:17)
    at file:///.../node_modules/.pnpm/rollup@4.12.0/node_modules/rollup/dist/es/shared/node-entry.js:20501:13
    at catchUnfinishedHookActions (file:///.../node_modules/.pnpm/rollup@4.12.0/node_modules/rollup/dist/es/shared/node-entry.js:19923:16)
    at build (file:///.../node_modules/.pnpm/vite@5.1.4_@types+node@20.5.1_sass@1.71.1_terser@5.28.1/node_modules/vite/dist/node/chunks/dep-jDlpJiMN.js:66934:22)
    at triggerFullBuild (file:///.../node_modules/.pnpm/vike@0.4.163-commit-2305d5b_vite@5.1.4/node_modules/vike/dist/esm/node/plugin/plugins/autoFullBuild.js:78:9)
    at Object.handler (file:///.../node_modules/.pnpm/vike@0.4.163-commit-2305d5b_vite@5.1.4/node_modules/vike/dist/esm/node/plugin/plugins/autoFullBuild.js:31:25)
    at async Promise.all (index 0)
    at PluginDriver.hookParallel (file:///.../node_modules/.pnpm/rollup@4.12.0/node_modules/rollup/dist/es/shared/node-entry.js:19499:17)
    at file:///.../node_modules/.pnpm/rollup@4.12.0/node_modules/rollup/dist/es/shared/node-entry.js:20501:13
    at catchUnfinishedHookActions (file:///.../node_modules/.pnpm/rollup@4.12.0/node_modules/rollup/dist/es/shared/node-entry.js:19923:16)
    at build (file:///.../node_modules/.pnpm/vite@5.1.4_@types+node@20.5.1_sass@1.71.1_terser@5.28.1/node_modules/vite/dist/node/chunks/dep-jDlpJiMN.js:66934:22)
    at CAC.<anonymous> (file:///.../node_modules/.pnpm/vite@5.1.4_@types+node@20.5.1_sass@1.71.1_terser@5.28.1/node_modules/vite/dist/node/cli.js:842:9) {
  code: 'PLUGIN_ERROR',
  plugin: 'vike:buildConfig',
  hook: 'writeBundle'
}

Basically it expects the assets directory to exist, which does not. Removing the assert moves the error to a later point (without a stack trace)

[Error: [vike:buildConfig] ENOENT: no such file or directory, lstat '/.../dist/server/assets'] {
  errno: -2,
  code: 'PLUGIN_ERROR',
  syscall: 'lstat',
  path: '/.../dist/server/assets',
  pluginCode: 'ENOENT',
  plugin: 'vike:buildConfig',
  hook: 'writeBundle'
}
 ELIFECYCLE  Command failed with exit code 1.

Indeed dist/server/assets/ is expected to exist. (Vike needs to know where static assets referenced by the server-side live).

Maybe you, or a plugin, changed the default value of config.build.assetsDir. (Vike currently expects it to be assets.) Checking the value console.log(config.build.assetsDir) in a configResolved(config) hook will give you insights in that regard.

Yes, I do indeed need to move it to /spa/assets for technical reasons. Is there a reason this value is hard-coded?

Setting config.build.assetsDir should work again as per 0.4.163-commit-407cb5c.

In my production setup, this now fails when pre-rendering the HTML with

Cannot find module '/.../dist/server/spa/assets/chunk-BNyIB68C.js' imported from /.../dist/server/entry.mjs

Still did not manage to find a simpler reproduction, though. In a nutshell, these are the relevant parts of my vite.config

import graphql from '@rollup/plugin-graphql';
import legacy from '@vitejs/plugin-legacy';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
import { ssr } from 'vike/plugin';
import svgLoader from 'vite-svg-loader';
import generateHtml from './plugins/generateHtml';

const legacyPlugin = legacy({
  modernPolyfills: true,
  targets: [
    '> 0.5%',
    'last 1 version',
    'Edge >= 16',
    'Opera >= 58',
    'Safari >= 10.1',
    'Firefox >= 52',
    'Chrome >= 57',
    'iOS >= 11',
    'Samsung >= 8',
    'ChromeAndroid >= 71',
    'Android >= 4.3',
    'not dead',
  ],
});

export default defineConfig({
  root: __dirname,
  plugins: [
    vue(),
    svgLoader({
      svgoConfig: {
        plugins: ['prefixIds'],
      },
    }),
    graphql(),
    ssr({ prerender: true }),
    legacyPlugin,
    generateHtml(legacyPlugin),
  ],
  base: '/spa/',
  resolve: {
    alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
    extensions: ['.js', '.ts', '.jsx', '.tsx'],
  },
  build: {
    manifest: true,
    outDir: 'dist',
    minify: 'terser',
    terserOptions: { safari10: true },
    rollupOptions: {
      output: {
        chunkFileNames: 'spa/assets/chunk-[hash].js',
      },
    },
  },
  css: { preprocessorOptions: { scss: { charset: false } } },
  optimizeDeps: { include: ['intersection-observer'] }
});

generateHtml is a post-processing step that on closeBundle reads all HTML files from disc and applies the legacy transforms as well as some CSS inlining.

Removing build.assetsDir: 'spa/assets' fixes it, but curiously it breaks again if I change build.rollupOptions.output.chunkFileNames to 'assets/chunk-[hash].js' without the "spa/" prefix. The error is mostly the same except "/spa" is missing in the path of the imported file.

When looking into "dist" there is indeed no assets or spa folder. Only the entry point .mjs files are generated at this point. On the other hand with build.assetsDir set to "assets", everything is working and the folder and chunks are generated. Actually, the assets reside in server/spa/assets...

I'm not sure what could cause this and how this could be related to Vike. The best would be a reproduction, ideally a minimum one.

I finally managed to create a reproduction https://github.com/lukastaegert/vike-vue-repro
It is based on the vue template. The use of multi-level scss imports was necessary to trigger the bug, don't ask me why.

The use of multi-level scss imports was necessary to trigger the bug, don't ask me why.

Hm, it makes me further think that it's unrelated to Vike. But I'll have a look at the repro later today.

Maybe, but the reproduction works flawlessly with vike@0.4.160.

With vike@0.4.161, you get this error:

[Error: [vike:buildConfig] ENOENT: no such file or directory, open '/.../vike-legacy-repro/dist/client/_temp_manifest.json'] {
  errno: -2,
  code: 'PLUGIN_ERROR',
  syscall: 'open',
  path: '/.../vike-legacy-repro/dist/client/_temp_manifest.json',
  pluginCode: 'ENOENT',
  plugin: 'vike:buildConfig',
  hook: 'writeBundle'
}

And starting with vike@0.4.164 the error takes its current form

Error: Cannot find module '/.../vike-legacy-repro/dist/server/spa/assets/chunk-CuntopgX.js' imported from /.../vike-legacy-repro/dist/server/entries/pages_error.mjs
    at finalizeResolution (node:internal/modules/esm/resolve:264:11)
    at moduleResolve (node:internal/modules/esm/resolve:917:10)
    at defaultResolve (node:internal/modules/esm/resolve:1130:11)
    at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:396:12)
    at ModuleLoader.resolve (node:internal/modules/esm/loader:365:25)
    at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:240:38)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:85:39)
    at link (node:internal/modules/esm/module_job:84:36) {
  code: 'ERR_MODULE_NOT_FOUND',
  url: 'file:///.../vike-legacy-repro/dist/server/spa/assets/chunk-CuntopgX.js'
}

So if the bug is not in vike, something in vike changed to reveal the bug.

Ok good to know, I'll dig into what's the Vike change that causes this.

Fix pre-released in 0.4.165-commit-6dfef11. Let me know if you run into other regressions or issues.