[READ-ONLY] Mirror of https://github.com/danielroe/nitro-vite-repros.
3.7 kB
85 lines
1import { fileURLToPath } from 'node:url'
2import { defineConfig } from 'vite'
3import { nitro } from 'nitro/vite'
4import type { Nitro } from 'nitro/types'
5
6const rendererEntry = fileURLToPath(new URL('./src/renderer.ts', import.meta.url))
7const globalCss = fileURLToPath(new URL('./src/app/assets/global.css', import.meta.url))
8
9export default defineConfig({
10 plugins: [
11 nitro({
12 runtimeConfig: { public: { probe: 'hello-from-runtime-config' } },
13 prerender: { routes: ['/', '/prerendered'] },
14 }),
15 {
16 // A Vite plugin that owns a custom virtual-module scheme, scoped
17 // to server-consumer envs. The ssr env build resolves these via
18 // the plugin pipeline; the deployable's nitro env rebundle does
19 // the same. The prerender Nitro does not, because it builds with
20 // standalone rolldown (see https://github.com/nitrojs/nitro/pull/4152
21 // for the related `nitro/*` proxy plumbing in service envs).
22 name: 'repro:virtual-fs',
23 enforce: 'pre',
24 applyToEnvironment: env => env.config.consumer === 'server',
25 resolveId: {
26 filter: { id: /^#virtual\// },
27 handler (id) { return '\0' + id },
28 },
29 load: {
30 filter: { id: /^\0#virtual\// },
31 handler (id) {
32 if (id === '\0#virtual/entry') return 'export default "live-entry-content"'
33 if (id === '\0#virtual/css') {
34 return `import ${JSON.stringify(globalCss)}\nexport default "css-loaded"`
35 }
36 },
37 },
38 },
39 {
40 // Mirror of the proxy plumbing landed in
41 // https://github.com/nitrojs/nitro/pull/4152: service environments
42 // must not bundle their own copy of `nitro/*` runtime modules,
43 // otherwise the ssr entry gets stub instances instead of sharing
44 // the Nitro environment's runtime state. The PR externalises
45 // `/^nitro(\/|$)/` from service envs in prod and proxies them via
46 // `__VITE_ENVIRONMENT_RUNNER_IMPORT__` in dev.
47 //
48 // In dev, Vite's env-runner short-circuits externalised
49 // bare-specifier imports to Node before the proxy plugin runs.
50 // `noExternal` here forces `nitro/*` through the plugin pipeline
51 // so the proxy can claim them. Without this, `useRuntimeConfig()`
52 // in dev returns `{ app: {}, nitro: {} }` (the stub at
53 // `nitro/dist/runtime/virtual/runtime-config.mjs`).
54 name: 'repro:noExternal-nitro',
55 configEnvironment (name) {
56 if (name !== 'ssr') return
57 return { resolve: { noExternal: [/^nitro(\/|$)/] } }
58 },
59 },
60 {
61 // Wire `src/renderer.ts` as the prerender Nitro's `/**` handler
62 // via a `.nitro` module hook (the shape `nitro/vite` scans for in
63 // `nitro/dist/vite.mjs`).
64 //
65 // The prerender Nitro spins up via
66 // `createNitro(prerendererConfig)` and builds with standalone
67 // rolldown when the main builder is `vite`, so none of the Vite
68 // plugins above reach it. The static chain
69 // `renderer.ts -> app/entry.ts -> #virtual/css` is unresolved in
70 // the prerender bundle; rolldown leaves the bare specifier in the
71 // output and Node errors at prerender runtime with
72 // `ERR_PACKAGE_IMPORT_NOT_DEFINED`. See README for the trace.
73 //
74 // Comment this plugin out to make the build succeed (without any
75 // prerendering — every prerender route 404s instead of 500ing).
76 name: 'repro:prerender-handler',
77 nitro: (nitroInstance: Nitro) => {
78 nitroInstance.hooks.hook('prerender:config', (prerendererConfig) => {
79 if (prerendererConfig.renderer) return
80 prerendererConfig.renderer = { handler: rendererEntry }
81 })
82 },
83 },
84 ],
85})