@analogjs/vite-plugin-nitro 3.0.0-alpha.1 → 3.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/package.json +5 -9
  2. package/src/index.d.ts +9 -9
  3. package/src/index.js +6 -2
  4. package/src/index.js.map +1 -1
  5. package/src/lib/build-server.d.ts +3 -2
  6. package/src/lib/build-server.js +103 -76
  7. package/src/lib/build-server.js.map +1 -1
  8. package/src/lib/build-sitemap.d.ts +6 -6
  9. package/src/lib/build-sitemap.js +48 -60
  10. package/src/lib/build-sitemap.js.map +1 -1
  11. package/src/lib/build-ssr.d.ts +2 -2
  12. package/src/lib/build-ssr.js +16 -18
  13. package/src/lib/build-ssr.js.map +1 -1
  14. package/src/lib/hooks/post-rendering-hook.d.ts +1 -1
  15. package/src/lib/hooks/post-rendering-hook.js +10 -6
  16. package/src/lib/hooks/post-rendering-hook.js.map +1 -1
  17. package/src/lib/options.d.ts +114 -106
  18. package/src/lib/plugins/dev-server-plugin.d.ts +3 -3
  19. package/src/lib/plugins/dev-server-plugin.js +91 -101
  20. package/src/lib/plugins/dev-server-plugin.js.map +1 -1
  21. package/src/lib/plugins/page-endpoints.d.ts +5 -5
  22. package/src/lib/plugins/page-endpoints.js +28 -63
  23. package/src/lib/plugins/page-endpoints.js.map +1 -1
  24. package/src/lib/utils/get-content-files.d.ts +54 -54
  25. package/src/lib/utils/get-content-files.js +88 -97
  26. package/src/lib/utils/get-content-files.js.map +1 -1
  27. package/src/lib/utils/get-page-handlers.d.ts +58 -58
  28. package/src/lib/utils/get-page-handlers.js +70 -84
  29. package/src/lib/utils/get-page-handlers.js.map +1 -1
  30. package/src/lib/utils/load-esm.d.ts +18 -18
  31. package/src/lib/utils/node-web-bridge.d.ts +1 -1
  32. package/src/lib/utils/node-web-bridge.js +50 -45
  33. package/src/lib/utils/node-web-bridge.js.map +1 -1
  34. package/src/lib/utils/register-dev-middleware.d.ts +12 -12
  35. package/src/lib/utils/register-dev-middleware.js +41 -44
  36. package/src/lib/utils/register-dev-middleware.js.map +1 -1
  37. package/src/lib/utils/renderers.d.ts +50 -39
  38. package/src/lib/utils/renderers.js +69 -56
  39. package/src/lib/utils/renderers.js.map +1 -1
  40. package/src/lib/utils/rolldown.d.ts +2 -0
  41. package/src/lib/utils/rolldown.js +12 -0
  42. package/src/lib/utils/rolldown.js.map +1 -0
  43. package/src/lib/vite-plugin-nitro.d.ts +3 -3
  44. package/src/lib/vite-plugin-nitro.js +493 -577
  45. package/src/lib/vite-plugin-nitro.js.map +1 -1
  46. package/README.md +0 -125
  47. package/src/lib/options.js +0 -2
  48. package/src/lib/options.js.map +0 -1
  49. package/src/lib/utils/load-esm.js +0 -23
  50. package/src/lib/utils/load-esm.js.map +0 -1
@@ -1,599 +1,515 @@
1
- import { build, createDevServer, createNitro } from 'nitro/builder';
2
- import * as vite from 'vite';
3
- import { mergeConfig, normalizePath } from 'vite';
4
- import { relative, resolve } from 'node:path';
5
- import { pathToFileURL } from 'node:url';
6
- import { existsSync, readFileSync } from 'node:fs';
7
- import { buildServer } from './build-server.js';
8
- import { buildSSRApp } from './build-ssr.js';
9
- import { pageEndpointsPlugin } from './plugins/page-endpoints.js';
10
- import { getPageHandlers } from './utils/get-page-handlers.js';
11
- import { buildSitemap } from './build-sitemap.js';
12
- import { devServerPlugin } from './plugins/dev-server-plugin.js';
13
- import { toWebRequest, writeWebResponseToNode, } from './utils/node-web-bridge.js';
14
- import { getMatchingContentFilesWithFrontMatter } from './utils/get-content-files.js';
15
- import { ssrRenderer, clientRenderer, apiMiddleware, } from './utils/renderers.js';
16
- let clientOutputPath = '';
17
- let rendererIndexEntry = '';
1
+ import { buildServer, isVercelPreset } from "./build-server.js";
2
+ import { getBundleOptionsKey, isRolldown } from "./utils/rolldown.js";
3
+ import { buildSSRApp } from "./build-ssr.js";
4
+ import { apiMiddleware, clientRenderer, ssrRenderer } from "./utils/renderers.js";
5
+ import { pageEndpointsPlugin } from "./plugins/page-endpoints.js";
6
+ import { getPageHandlers } from "./utils/get-page-handlers.js";
7
+ import { buildSitemap } from "./build-sitemap.js";
8
+ import { toWebRequest, writeWebResponseToNode } from "./utils/node-web-bridge.js";
9
+ import { devServerPlugin } from "./plugins/dev-server-plugin.js";
10
+ import { getMatchingContentFilesWithFrontMatter } from "./utils/get-content-files.js";
11
+ import { build, createDevServer, createNitro } from "nitro/builder";
12
+ import { mergeConfig, normalizePath } from "vite";
13
+ import { relative, resolve } from "node:path";
14
+ import { pathToFileURL } from "node:url";
15
+ import { existsSync, readFileSync } from "node:fs";
16
+ //#region packages/vite-plugin-nitro/src/lib/vite-plugin-nitro.ts
18
17
  function createNitroMiddlewareHandler(handler) {
19
- return {
20
- route: '/**',
21
- handler,
22
- middleware: true,
23
- };
18
+ return {
19
+ route: "/**",
20
+ handler,
21
+ middleware: true
22
+ };
24
23
  }
24
+ /**
25
+ * Creates a `rollup:before` hook that marks specified packages as external
26
+ * in Nitro's bundler config (applied to both the server build and the
27
+ * prerender build).
28
+ *
29
+ * ## Subpath matching (Rolldown compatibility)
30
+ *
31
+ * When `bundlerConfig.external` is an **array**, Rollup automatically
32
+ * prefix-matches entries — `'rxjs'` in the array will also externalise
33
+ * `'rxjs/operators'`, `'rxjs/internal/Observable'`, etc.
34
+ *
35
+ * Rolldown (the default bundler in Nitro v3) does **not** do this. It
36
+ * treats array entries as exact strings. To keep behaviour consistent
37
+ * across both bundlers, the **function** branch already needed explicit
38
+ * subpath matching. We now use the same `isExternal` helper for all
39
+ * branches so that `'rxjs'` reliably matches `'rxjs/operators'`
40
+ * regardless of whether the existing `external` value is a function,
41
+ * array, or absent.
42
+ *
43
+ * Without this, the Nitro prerender build fails on Windows CI with:
44
+ *
45
+ * [RESOLVE_ERROR] Could not resolve 'rxjs/operators'
46
+ */
25
47
  function createRollupBeforeHook(externalEntries) {
26
- return (_nitro, bundlerConfig) => {
27
- removeInvalidRollupCodeSplitting(_nitro, bundlerConfig);
28
- if (externalEntries.length === 0) {
29
- return;
30
- }
31
- const existing = bundlerConfig.external;
32
- if (!existing) {
33
- bundlerConfig.external = externalEntries;
34
- }
35
- else if (typeof existing === 'function') {
36
- bundlerConfig.external = (source, importer, isResolved) => existing(source, importer, isResolved) ||
37
- externalEntries.includes(source);
38
- }
39
- else if (Array.isArray(existing)) {
40
- bundlerConfig.external = [...existing, ...externalEntries];
41
- }
42
- else {
43
- bundlerConfig.external = [existing, ...externalEntries];
44
- }
45
- };
48
+ const isExternal = (source) => externalEntries.some((entry) => source === entry || source.startsWith(entry + "/"));
49
+ return (_nitro, bundlerConfig) => {
50
+ sanitizeNitroBundlerConfig(_nitro, bundlerConfig);
51
+ if (externalEntries.length === 0) return;
52
+ const existing = bundlerConfig.external;
53
+ if (!existing) bundlerConfig.external = externalEntries;
54
+ else if (typeof existing === "function") bundlerConfig.external = (source, importer, isResolved) => existing(source, importer, isResolved) || isExternal(source);
55
+ else if (Array.isArray(existing)) bundlerConfig.external = [...existing, ...externalEntries];
56
+ else bundlerConfig.external = [existing, ...externalEntries];
57
+ };
46
58
  }
47
59
  function appendNoExternals(noExternals, ...entries) {
48
- if (!noExternals) {
49
- return entries;
50
- }
51
- return Array.isArray(noExternals)
52
- ? [...noExternals, ...entries]
53
- : noExternals;
60
+ if (!noExternals) return entries;
61
+ return Array.isArray(noExternals) ? [...noExternals, ...entries] : noExternals;
54
62
  }
55
- function removeInvalidRollupCodeSplitting(_nitro, bundlerConfig) {
56
- // Workaround for a Nitro v3 alpha bundler bug:
57
- //
58
- // Analog does not add `output.codeSplitting` to Nitro's Rollup config, but
59
- // Nitro 3.0.1-alpha.2 builds an internal server bundler config that can
60
- // still contain that key while running under Vite 8 / Rolldown. At runtime
61
- // this surfaces as:
62
- //
63
- // Warning: Invalid output options (1 issue found)
64
- // - For the "codeSplitting". Invalid key: Expected never but received "codeSplitting".
65
- //
66
- // That warning comes from Nitro's own bundler handoff, not from user config
67
- // in Analog apps. We remove only the invalid `output.codeSplitting` field
68
- // right before Nitro starts prerender/server builds.
69
- //
70
- // Why this is safe:
71
- // - Analog is not relying on Nitro-side `output.codeSplitting`.
72
- // - The warning path only rejects the option; removing it restores the
73
- // default Nitro/Rollup behavior instead of changing any Analog semantics.
74
- // - The hook is narrowly scoped to the final Nitro bundler config, so it
75
- // does not affect the normal Vite client/SSR environment build config.
76
- const output = bundlerConfig['output'];
77
- if (!output || Array.isArray(output) || typeof output !== 'object') {
78
- return;
79
- }
80
- if ('codeSplitting' in output) {
81
- delete output['codeSplitting'];
82
- }
83
- // Nitro's default server bundler config currently enables manual chunking for
84
- // node_modules. Under Nitro v3 alpha + Rollup 4.59 this can crash during the
85
- // prerender rebundle with "Cannot read properties of undefined (reading
86
- // 'included')" while generating chunks. A single server bundle is acceptable
87
- // here, so strip manualChunks until the upstream bug is fixed.
88
- if ('manualChunks' in output) {
89
- delete output['manualChunks'];
90
- }
63
+ /**
64
+ * Patches Nitro's internal Rollup/Rolldown bundler config to work around
65
+ * incompatibilities in the Nitro v3 alpha series.
66
+ *
67
+ * Called from the `rollup:before` hook, this function runs against the *final*
68
+ * bundler config that Nitro assembles for its server/prerender builds it
69
+ * does NOT touch the normal Vite client or SSR environment configs.
70
+ *
71
+ * Each workaround is narrowly scoped and safe to remove once the corresponding
72
+ * upstream Nitro issue is resolved.
73
+ */
74
+ function sanitizeNitroBundlerConfig(_nitro, bundlerConfig) {
75
+ const output = bundlerConfig["output"];
76
+ if (!output || Array.isArray(output) || typeof output !== "object") return;
77
+ if ("codeSplitting" in output) delete output["codeSplitting"];
78
+ if ("manualChunks" in output) delete output["manualChunks"];
79
+ const VALID_ROLLUP_PLACEHOLDER = /^\[(?:name|hash|format|ext)\]$/;
80
+ const chunkFileNames = output["chunkFileNames"];
81
+ if (typeof chunkFileNames === "function") {
82
+ const originalFn = chunkFileNames;
83
+ output["chunkFileNames"] = (...args) => {
84
+ const result = originalFn(...args);
85
+ if (typeof result !== "string") return result;
86
+ return result.replace(/\[[^\]]+\]/g, (match) => VALID_ROLLUP_PLACEHOLDER.test(match) ? match : `_${match.slice(1, -1)}_`);
87
+ };
88
+ }
91
89
  }
92
- function resolveClientOutputPath(workspaceRoot, rootDir, configuredOutDir, ssrBuild) {
93
- if (clientOutputPath) {
94
- return clientOutputPath;
95
- }
96
- if (!ssrBuild) {
97
- return resolve(workspaceRoot, rootDir, configuredOutDir || 'dist/client');
98
- }
99
- // SSR builds write server assets to dist/<app>/ssr, but the renderer template
100
- // still needs the client index.html emitted to dist/<app>/client.
101
- return resolve(workspaceRoot, 'dist', rootDir, 'client');
90
+ function resolveClientOutputPath(cachedPath, workspaceRoot, rootDir, configuredOutDir) {
91
+ if (cachedPath) return cachedPath;
92
+ if (configuredOutDir) return resolve(workspaceRoot, rootDir, configuredOutDir);
93
+ return resolve(workspaceRoot, "dist", rootDir, "client");
102
94
  }
95
+ function registerIndexHtmlVirtual(nitroConfig, clientOutputPath) {
96
+ const indexHtml = readFileSync(resolve(clientOutputPath, "index.html"), "utf8");
97
+ nitroConfig.virtual = {
98
+ ...nitroConfig.virtual,
99
+ "#analog/index": `export default ${JSON.stringify(indexHtml)};`
100
+ };
101
+ }
102
+ /**
103
+ * Converts the built SSR entry path into a specifier that Nitro's bundler
104
+ * can resolve, including all relative `./assets/*` chunk imports inside
105
+ * the entry.
106
+ *
107
+ * The returned path **must** be an absolute filesystem path with forward
108
+ * slashes (e.g. `D:/a/analog/dist/apps/blog-app/ssr/main.server.js`).
109
+ * This lets Rollup/Rolldown determine the entry's directory and resolve
110
+ * sibling chunk imports like `./assets/core-DTazUigR.js` correctly.
111
+ *
112
+ * ## Why not pathToFileURL() on Windows?
113
+ *
114
+ * Earlier versions converted the path to a `file:///D:/a/...` URL on
115
+ * Windows, which worked with Nitro v2 + Rollup. Nitro v3 switched its
116
+ * default bundler to Rolldown, and Rolldown does **not** extract the
117
+ * importer directory from `file://` URLs. This caused every relative
118
+ * import inside the SSR entry to fail during the prerender build:
119
+ *
120
+ * [RESOLVE_ERROR] Could not resolve './assets/core-DTazUigR.js'
121
+ * in ../../dist/apps/blog-app/ssr/main.server.js
122
+ *
123
+ * `normalizePath()` (from Vite) simply converts backslashes to forward
124
+ * slashes, which both Rollup and Rolldown handle correctly on all
125
+ * platforms.
126
+ */
103
127
  function toNitroSsrEntrypointSpecifier(ssrEntryPath) {
104
- // Nitro rebundles the generated SSR entry. On Windows, a file URL preserves
105
- // the importer location so relative "./assets/*" imports resolve correctly.
106
- return process.platform === 'win32'
107
- ? pathToFileURL(ssrEntryPath).href
108
- : normalizePath(ssrEntryPath);
128
+ return normalizePath(ssrEntryPath);
129
+ }
130
+ function applySsrEntryAlias(nitroConfig, options, workspaceRoot, rootDir) {
131
+ const ssrOutDir = options?.ssrBuildDir || resolve(workspaceRoot, "dist", rootDir, "ssr");
132
+ if (options?.ssr || nitroConfig.prerender?.routes?.length) {
133
+ const ssrEntry = toNitroSsrEntrypointSpecifier(resolveBuiltSsrEntryPath(ssrOutDir));
134
+ nitroConfig.alias = {
135
+ ...nitroConfig.alias,
136
+ "#analog/ssr": ssrEntry
137
+ };
138
+ }
109
139
  }
110
140
  function resolveBuiltSsrEntryPath(ssrOutDir) {
111
- const candidatePaths = [
112
- resolve(ssrOutDir, 'main.server.mjs'),
113
- resolve(ssrOutDir, 'main.server.js'),
114
- resolve(ssrOutDir, 'main.server'),
115
- ];
116
- const ssrEntryPath = candidatePaths.find((candidatePath) => existsSync(candidatePath));
117
- if (!ssrEntryPath) {
118
- throw new Error(`Unable to locate the built SSR entry in "${ssrOutDir}". Expected one of: ${candidatePaths.join(', ')}`);
119
- }
120
- return ssrEntryPath;
141
+ const candidatePaths = [
142
+ resolve(ssrOutDir, "main.server.mjs"),
143
+ resolve(ssrOutDir, "main.server.js"),
144
+ resolve(ssrOutDir, "main.server")
145
+ ];
146
+ const ssrEntryPath = candidatePaths.find((candidatePath) => existsSync(candidatePath));
147
+ if (!ssrEntryPath) throw new Error(`Unable to locate the built SSR entry in "${ssrOutDir}". Expected one of: ${candidatePaths.join(", ")}`);
148
+ return ssrEntryPath;
121
149
  }
122
- export function nitro(options, nitroOptions) {
123
- const workspaceRoot = options?.workspaceRoot ?? process.cwd();
124
- const sourceRoot = options?.sourceRoot ?? 'src';
125
- let isTest = process.env['NODE_ENV'] === 'test' || !!process.env['VITEST'];
126
- const baseURL = process.env['NITRO_APP_BASE_URL'] || '';
127
- const prefix = baseURL ? baseURL.substring(0, baseURL.length - 1) : '';
128
- const apiPrefix = `/${options?.apiPrefix || 'api'}`;
129
- const useAPIMiddleware = typeof options?.useAPIMiddleware !== 'undefined'
130
- ? options?.useAPIMiddleware
131
- : true;
132
- let isBuild = false;
133
- let isServe = false;
134
- let ssrBuild = false;
135
- let config;
136
- let nitroConfig;
137
- let environmentBuild = false;
138
- let hasAPIDir = false;
139
- const rollupExternalEntries = [];
140
- const routeSitemaps = {};
141
- const routeSourceFiles = {};
142
- let rootDir = workspaceRoot;
143
- return [
144
- (options?.ssr
145
- ? devServerPlugin({
146
- entryServer: options?.entryServer,
147
- index: options?.index,
148
- routeRules: nitroOptions?.routeRules,
149
- })
150
- : false),
151
- {
152
- name: '@analogjs/vite-plugin-nitro',
153
- async config(userConfig, { mode, command }) {
154
- isServe = command === 'serve';
155
- isBuild = command === 'build';
156
- ssrBuild = userConfig.build?.ssr === true;
157
- config = userConfig;
158
- isTest = isTest ? isTest : mode === 'test';
159
- rootDir = relative(workspaceRoot, config.root || '.') || '.';
160
- hasAPIDir = existsSync(resolve(workspaceRoot, rootDir, `${sourceRoot}/server/routes/${options?.apiPrefix || 'api'}`));
161
- const buildPreset = process.env['BUILD_PRESET'] ??
162
- nitroOptions?.preset ??
163
- (process.env['VERCEL'] ? 'vercel' : undefined);
164
- const pageHandlers = getPageHandlers({
165
- workspaceRoot,
166
- sourceRoot,
167
- rootDir,
168
- additionalPagesDirs: options?.additionalPagesDirs,
169
- hasAPIDir,
170
- });
171
- const resolvedClientOutputPath = resolveClientOutputPath(workspaceRoot, rootDir, config.build?.outDir, ssrBuild);
172
- rendererIndexEntry = normalizePath(resolve(resolvedClientOutputPath, 'index.html'));
173
- nitroConfig = {
174
- rootDir: normalizePath(rootDir),
175
- preset: buildPreset,
176
- compatibilityDate: '2024-11-19',
177
- logLevel: nitroOptions?.logLevel || 0,
178
- serverDir: normalizePath(`${sourceRoot}/server`),
179
- scanDirs: [
180
- normalizePath(`${rootDir}/${sourceRoot}/server`),
181
- ...(options?.additionalAPIDirs || []).map((dir) => normalizePath(`${workspaceRoot}${dir}`)),
182
- ],
183
- output: {
184
- dir: normalizePath(resolve(workspaceRoot, 'dist', rootDir, 'analog')),
185
- publicDir: normalizePath(resolve(workspaceRoot, 'dist', rootDir, 'analog/public')),
186
- },
187
- buildDir: normalizePath(resolve(workspaceRoot, 'dist', rootDir, '.nitro')),
188
- typescript: {
189
- generateTsConfig: false,
190
- },
191
- runtimeConfig: {
192
- apiPrefix: apiPrefix.substring(1),
193
- prefix,
194
- },
195
- // Analog provides its own renderer handler; prevent Nitro v3 from
196
- // auto-detecting index.html in rootDir and adding a conflicting one.
197
- renderer: false,
198
- imports: {
199
- autoImport: false,
200
- },
201
- hooks: {
202
- 'rollup:before': createRollupBeforeHook(rollupExternalEntries),
203
- },
204
- rollupConfig: {
205
- onwarn(warning) {
206
- if (warning.message.includes('empty chunk') &&
207
- warning.message.endsWith('.server')) {
208
- return;
209
- }
210
- },
211
- plugins: [pageEndpointsPlugin()],
212
- },
213
- handlers: [
214
- ...(hasAPIDir
215
- ? []
216
- : useAPIMiddleware
217
- ? [createNitroMiddlewareHandler('#ANALOG_API_MIDDLEWARE')]
218
- : []),
219
- ...pageHandlers,
220
- ],
221
- routeRules: hasAPIDir
222
- ? undefined
223
- : useAPIMiddleware
224
- ? undefined
225
- : {
226
- [`${prefix}${apiPrefix}/**`]: {
227
- proxy: { to: '/**' },
228
- },
229
- },
230
- virtual: {
231
- '#ANALOG_SSR_RENDERER': ssrRenderer(rendererIndexEntry),
232
- '#ANALOG_CLIENT_RENDERER': clientRenderer(rendererIndexEntry),
233
- ...(hasAPIDir ? {} : { '#ANALOG_API_MIDDLEWARE': apiMiddleware }),
234
- },
235
- };
236
- if (isVercelPreset(buildPreset)) {
237
- nitroConfig = withVercelOutputAPI(nitroConfig, workspaceRoot, buildPreset);
238
- }
239
- if (isCloudflarePreset(buildPreset)) {
240
- nitroConfig = withCloudflareOutput(nitroConfig);
241
- }
242
- if (isNetlifyPreset(buildPreset) &&
243
- rootDir === '.' &&
244
- !existsSync(resolve(workspaceRoot, 'netlify.toml'))) {
245
- nitroConfig = withNetlifyOutputAPI(nitroConfig, workspaceRoot);
246
- }
247
- if (isFirebaseAppHosting()) {
248
- nitroConfig = withAppHostingOutput(nitroConfig);
249
- }
250
- if (!ssrBuild && !isTest) {
251
- // store the client output path for the SSR build config
252
- clientOutputPath = resolvedClientOutputPath;
253
- }
254
- if (isBuild) {
255
- nitroConfig.publicAssets = [
256
- { dir: normalizePath(clientOutputPath), maxAge: 0 },
257
- ];
258
- // In Nitro v3, renderer.entry is resolved via resolveModulePath()
259
- // during options normalization, which requires a real filesystem path.
260
- // Virtual modules (prefixed with #) can't survive this resolution.
261
- // Instead, we add the renderer as a catch-all handler directly —
262
- // this is functionally equivalent to what Nitro does internally
263
- // (it converts renderer.entry into a { route: '/**', lazy: true }
264
- // handler), but avoids the filesystem resolution step.
265
- const rendererHandler = options?.ssr
266
- ? '#ANALOG_SSR_RENDERER'
267
- : '#ANALOG_CLIENT_RENDERER';
268
- nitroConfig.handlers = [
269
- ...(nitroConfig.handlers || []),
270
- {
271
- handler: rendererHandler,
272
- route: '/**',
273
- lazy: true,
274
- },
275
- ];
276
- if (isEmptyPrerenderRoutes(options)) {
277
- nitroConfig.prerender = {};
278
- nitroConfig.prerender.routes = ['/'];
279
- }
280
- if (options?.prerender) {
281
- nitroConfig.prerender = nitroConfig.prerender ?? {};
282
- nitroConfig.prerender.crawlLinks = options?.prerender?.discover;
283
- let routes = [];
284
- const prerenderRoutes = options?.prerender?.routes;
285
- if (isArrayWithElements(prerenderRoutes)) {
286
- routes = prerenderRoutes;
287
- }
288
- else if (typeof prerenderRoutes === 'function') {
289
- routes = await prerenderRoutes();
290
- }
291
- nitroConfig.prerender.routes = routes.reduce((prev, current) => {
292
- if (!current) {
293
- return prev;
294
- }
295
- if (typeof current === 'string') {
296
- prev.push(current);
297
- return prev;
298
- }
299
- if ('route' in current) {
300
- if (current.sitemap) {
301
- routeSitemaps[current.route] = current.sitemap;
302
- }
303
- if (current.outputSourceFile) {
304
- const sourcePath = resolve(workspaceRoot, rootDir, current.outputSourceFile);
305
- routeSourceFiles[current.route] = readFileSync(sourcePath, 'utf8');
306
- }
307
- prev.push(current.route);
308
- // Add the server-side data fetching endpoint URL
309
- if ('staticData' in current) {
310
- prev.push(`${apiPrefix}/_analog/pages/${current.route}`);
311
- }
312
- return prev;
313
- }
314
- const affectedFiles = getMatchingContentFilesWithFrontMatter(workspaceRoot, rootDir, current.contentDir);
315
- affectedFiles.forEach((f) => {
316
- const result = current.transform(f);
317
- if (result) {
318
- if (current.sitemap) {
319
- routeSitemaps[result] =
320
- current.sitemap && typeof current.sitemap === 'function'
321
- ? current.sitemap?.(f)
322
- : current.sitemap;
323
- }
324
- if (current.outputSourceFile) {
325
- const sourceContent = current.outputSourceFile(f);
326
- if (sourceContent) {
327
- routeSourceFiles[result] = sourceContent;
328
- }
329
- }
330
- prev.push(result);
331
- // Add the server-side data fetching endpoint URL
332
- if ('staticData' in current) {
333
- prev.push(`${apiPrefix}/_analog/pages/${result}`);
334
- }
335
- }
336
- });
337
- return prev;
338
- }, []);
339
- }
340
- if (ssrBuild) {
341
- if (process.platform === 'win32') {
342
- nitroConfig.noExternals = appendNoExternals(nitroConfig.noExternals, 'std-env');
343
- }
344
- rollupExternalEntries.push('rxjs', 'node-fetch-native/dist/polyfill');
345
- nitroConfig = {
346
- ...nitroConfig,
347
- moduleSideEffects: ['zone.js/node', 'zone.js/fesm2015/zone-node'],
348
- handlers: [
349
- ...(hasAPIDir
350
- ? []
351
- : useAPIMiddleware
352
- ? [createNitroMiddlewareHandler('#ANALOG_API_MIDDLEWARE')]
353
- : []),
354
- ...pageHandlers,
355
- // Preserve the renderer catch-all handler added above
356
- {
357
- handler: rendererHandler,
358
- route: '/**',
359
- lazy: true,
360
- },
361
- ],
362
- };
363
- }
364
- }
365
- nitroConfig = mergeConfig(nitroConfig, nitroOptions);
366
- return {
367
- environments: {
368
- client: {
369
- build: {
370
- outDir: config?.build?.outDir ||
371
- resolve(workspaceRoot, 'dist', rootDir, 'client'),
372
- },
373
- },
374
- ssr: {
375
- build: {
376
- ssr: true,
377
- [vite.rolldownVersion ? 'rolldownOptions' : 'rollupOptions']: {
378
- input: options?.entryServer ||
379
- resolve(workspaceRoot, rootDir, `${sourceRoot}/main.server.ts`),
380
- },
381
- outDir: options?.ssrBuildDir ||
382
- resolve(workspaceRoot, 'dist', rootDir, 'ssr'),
383
- },
384
- },
385
- },
386
- builder: {
387
- sharedPlugins: true,
388
- buildApp: async (builder) => {
389
- environmentBuild = true;
390
- const builds = [builder.build(builder.environments['client'])];
391
- if (options?.ssr || nitroConfig.prerender?.routes?.length) {
392
- builds.push(builder.build(builder.environments['ssr']));
393
- }
394
- await Promise.all(builds);
395
- const ssrOutDir = options?.ssrBuildDir ||
396
- resolve(workspaceRoot, 'dist', rootDir, `ssr`);
397
- if (options?.ssr || nitroConfig.prerender?.routes?.length) {
398
- const ssrEntryPath = resolveBuiltSsrEntryPath(ssrOutDir);
399
- const ssrEntry = toNitroSsrEntrypointSpecifier(ssrEntryPath);
400
- nitroConfig.alias = {
401
- ...nitroConfig.alias,
402
- '#analog/ssr': ssrEntry,
403
- };
404
- }
405
- await buildServer(options, nitroConfig, routeSourceFiles);
406
- if (nitroConfig.prerender?.routes?.length &&
407
- options?.prerender?.sitemap) {
408
- const publicDir = nitroConfig.output?.publicDir;
409
- if (!publicDir) {
410
- throw new Error('Nitro public output directory is required to build the sitemap.');
411
- }
412
- console.log('Building Sitemap...');
413
- // sitemap needs to be built after all directories are built
414
- await buildSitemap(config, options.prerender.sitemap, nitroConfig.prerender.routes, publicDir, routeSitemaps);
415
- }
416
- console.log(`\n\nThe '@analogjs/platform' server has been successfully built.`);
417
- },
418
- },
419
- };
420
- },
421
- async configureServer(viteServer) {
422
- if (isServe && !isTest) {
423
- const nitro = await createNitro({
424
- dev: true,
425
- // Nitro's Vite builder now rejects `build()` in dev mode, but Analog's
426
- // dev integration still relies on the builder-driven reload hooks.
427
- // Force the server worker onto Rollup for this dev-only path.
428
- builder: 'rollup',
429
- ...nitroConfig,
430
- });
431
- const server = createDevServer(nitro);
432
- await build(nitro);
433
- const apiHandler = async (req, res) => {
434
- // Nitro v3's dev server is fetch-first, so adapt Vite's Node
435
- // request once and let Nitro respond with a standard Web Response.
436
- const response = await server.fetch(toWebRequest(req));
437
- await writeWebResponseToNode(res, response);
438
- };
439
- if (hasAPIDir) {
440
- viteServer.middlewares.use((req, res, next) => {
441
- if (req.url?.startsWith(`${prefix}${apiPrefix}`)) {
442
- void apiHandler(req, res).catch((error) => next(error));
443
- return;
444
- }
445
- next();
446
- });
447
- }
448
- else {
449
- viteServer.middlewares.use(apiPrefix, (req, res, next) => {
450
- void apiHandler(req, res).catch((error) => next(error));
451
- });
452
- }
453
- viteServer.httpServer?.once('listening', () => {
454
- process.env['ANALOG_HOST'] = !viteServer.config.server.host
455
- ? 'localhost'
456
- : viteServer.config.server.host;
457
- process.env['ANALOG_PORT'] = `${viteServer.config.server.port}`;
458
- });
459
- // handle upgrades if websockets are enabled
460
- if (nitroOptions?.experimental?.websocket) {
461
- viteServer.httpServer?.on('upgrade', server.upgrade);
462
- }
463
- console.log(`\n\nThe server endpoints are accessible under the "${prefix}${apiPrefix}" path.`);
464
- }
465
- },
466
- async closeBundle() {
467
- // Skip when build is triggered by the Environment API
468
- if (environmentBuild) {
469
- return;
470
- }
471
- if (ssrBuild) {
472
- return;
473
- }
474
- if (isBuild) {
475
- if (options?.ssr) {
476
- console.log('Building SSR application...');
477
- await buildSSRApp(config, options);
478
- }
479
- if (nitroConfig.prerender?.routes?.length &&
480
- options?.prerender?.sitemap) {
481
- console.log('Building Sitemap...');
482
- // sitemap needs to be built after all directories are built
483
- await buildSitemap(config, options.prerender.sitemap, nitroConfig.prerender.routes, clientOutputPath, routeSitemaps);
484
- }
485
- const closeBundleSsrOutDir = options?.ssrBuildDir ||
486
- resolve(workspaceRoot, 'dist', rootDir, `ssr`);
487
- if (options?.ssr || nitroConfig.prerender?.routes?.length) {
488
- const ssrEntryPath = resolveBuiltSsrEntryPath(closeBundleSsrOutDir);
489
- const ssrEntry = toNitroSsrEntrypointSpecifier(ssrEntryPath);
490
- nitroConfig.alias = {
491
- ...nitroConfig.alias,
492
- '#analog/ssr': ssrEntry,
493
- };
494
- }
495
- await buildServer(options, nitroConfig, routeSourceFiles);
496
- console.log(`\n\nThe '@analogjs/platform' server has been successfully built.`);
497
- }
498
- },
499
- },
500
- {
501
- name: '@analogjs/vite-plugin-nitro-api-prefix',
502
- config() {
503
- return {
504
- define: {
505
- ANALOG_API_PREFIX: `"${baseURL.substring(1)}${apiPrefix.substring(1)}"`,
506
- },
507
- };
508
- },
509
- },
510
- ];
150
+ function nitro(options, nitroOptions) {
151
+ const workspaceRoot = options?.workspaceRoot ?? process.cwd();
152
+ const sourceRoot = options?.sourceRoot ?? "src";
153
+ let isTest = process.env.NODE_ENV === "test" || !!process.env["VITEST"];
154
+ const baseURL = process.env["NITRO_APP_BASE_URL"] || "";
155
+ const prefix = baseURL ? baseURL.substring(0, baseURL.length - 1) : "";
156
+ const apiPrefix = `/${options?.apiPrefix || "api"}`;
157
+ const useAPIMiddleware = typeof options?.useAPIMiddleware !== "undefined" ? options?.useAPIMiddleware : true;
158
+ const viteRolldownOutput = options?.vite?.build?.rolldownOptions?.output;
159
+ const viteRolldownOutputConfig = viteRolldownOutput && !Array.isArray(viteRolldownOutput) ? viteRolldownOutput : void 0;
160
+ const codeSplitting = viteRolldownOutputConfig?.codeSplitting;
161
+ let isBuild = false;
162
+ let isServe = false;
163
+ let ssrBuild = false;
164
+ let config;
165
+ let nitroConfig;
166
+ let environmentBuild = false;
167
+ let hasAPIDir = false;
168
+ let clientOutputPath = "";
169
+ const rollupExternalEntries = [];
170
+ const routeSitemaps = {};
171
+ const routeSourceFiles = {};
172
+ let rootDir = workspaceRoot;
173
+ return [
174
+ options?.ssr ? devServerPlugin({
175
+ entryServer: options?.entryServer,
176
+ index: options?.index,
177
+ routeRules: nitroOptions?.routeRules
178
+ }) : false,
179
+ {
180
+ name: "@analogjs/vite-plugin-nitro",
181
+ async config(userConfig, { mode, command }) {
182
+ isServe = command === "serve";
183
+ isBuild = command === "build";
184
+ ssrBuild = userConfig.build?.ssr === true;
185
+ config = userConfig;
186
+ isTest = isTest ? isTest : mode === "test";
187
+ rootDir = relative(workspaceRoot, config.root ? resolve(workspaceRoot, config.root) : workspaceRoot) || ".";
188
+ hasAPIDir = existsSync(resolve(workspaceRoot, rootDir, `${sourceRoot}/server/routes/${options?.apiPrefix || "api"}`));
189
+ const buildPreset = process.env["BUILD_PRESET"] ?? nitroOptions?.preset ?? (process.env["VERCEL"] ? "vercel" : void 0);
190
+ const pageHandlers = getPageHandlers({
191
+ workspaceRoot,
192
+ sourceRoot,
193
+ rootDir,
194
+ additionalPagesDirs: options?.additionalPagesDirs,
195
+ hasAPIDir
196
+ });
197
+ const resolvedClientOutputPath = resolveClientOutputPath(clientOutputPath, workspaceRoot, rootDir, config.build?.outDir);
198
+ nitroConfig = {
199
+ rootDir: normalizePath(rootDir),
200
+ preset: buildPreset,
201
+ compatibilityDate: "2025-11-19",
202
+ logLevel: nitroOptions?.logLevel || 0,
203
+ serverDir: normalizePath(`${sourceRoot}/server`),
204
+ scanDirs: [normalizePath(`${rootDir}/${sourceRoot}/server`), ...(options?.additionalAPIDirs || []).map((dir) => normalizePath(`${workspaceRoot}${dir}`))],
205
+ output: {
206
+ dir: normalizePath(resolve(workspaceRoot, "dist", rootDir, "analog")),
207
+ publicDir: normalizePath(resolve(workspaceRoot, "dist", rootDir, "analog/public"))
208
+ },
209
+ buildDir: normalizePath(resolve(workspaceRoot, "dist", rootDir, ".nitro")),
210
+ typescript: { generateTsConfig: false },
211
+ runtimeConfig: {
212
+ apiPrefix: apiPrefix.substring(1),
213
+ prefix
214
+ },
215
+ renderer: false,
216
+ imports: { autoImport: false },
217
+ hooks: { "rollup:before": createRollupBeforeHook(rollupExternalEntries) },
218
+ rollupConfig: {
219
+ onwarn(warning) {
220
+ if (warning.message.includes("empty chunk") && warning.message.endsWith(".server")) return;
221
+ },
222
+ plugins: [pageEndpointsPlugin()]
223
+ },
224
+ handlers: [...hasAPIDir ? [] : useAPIMiddleware ? [createNitroMiddlewareHandler("#ANALOG_API_MIDDLEWARE")] : [], ...pageHandlers],
225
+ routeRules: hasAPIDir ? void 0 : useAPIMiddleware ? void 0 : { [`${prefix}${apiPrefix}/**`]: { proxy: { to: "/**" } } },
226
+ virtual: {
227
+ "#ANALOG_SSR_RENDERER": ssrRenderer(),
228
+ "#ANALOG_CLIENT_RENDERER": clientRenderer(),
229
+ ...hasAPIDir ? {} : { "#ANALOG_API_MIDDLEWARE": apiMiddleware }
230
+ }
231
+ };
232
+ if (isVercelPreset(buildPreset)) nitroConfig = withVercelOutputAPI(nitroConfig, workspaceRoot);
233
+ if (isCloudflarePreset(buildPreset)) nitroConfig = withCloudflareOutput(nitroConfig);
234
+ if (isNetlifyPreset(buildPreset) && rootDir === "." && !existsSync(resolve(workspaceRoot, "netlify.toml"))) nitroConfig = withNetlifyOutputAPI(nitroConfig, workspaceRoot);
235
+ if (isFirebaseAppHosting()) nitroConfig = withAppHostingOutput(nitroConfig);
236
+ if (!ssrBuild && !isTest) clientOutputPath = resolvedClientOutputPath;
237
+ nitroConfig.alias = {};
238
+ if (isBuild) {
239
+ nitroConfig.publicAssets = [{
240
+ dir: normalizePath(clientOutputPath),
241
+ maxAge: 0
242
+ }];
243
+ const rendererHandler = options?.ssr ? "#ANALOG_SSR_RENDERER" : "#ANALOG_CLIENT_RENDERER";
244
+ nitroConfig.handlers = [...nitroConfig.handlers || [], {
245
+ handler: rendererHandler,
246
+ route: "/**",
247
+ lazy: true
248
+ }];
249
+ if (isEmptyPrerenderRoutes(options)) {
250
+ nitroConfig.prerender = {};
251
+ nitroConfig.prerender.routes = ["/"];
252
+ }
253
+ if (options?.prerender) {
254
+ nitroConfig.prerender = nitroConfig.prerender ?? {};
255
+ nitroConfig.prerender.crawlLinks = options?.prerender?.discover;
256
+ let routes = [];
257
+ const prerenderRoutes = options?.prerender?.routes;
258
+ if (isArrayWithElements(prerenderRoutes)) routes = prerenderRoutes;
259
+ else if (typeof prerenderRoutes === "function") routes = await prerenderRoutes();
260
+ nitroConfig.prerender.routes = routes.reduce((prev, current) => {
261
+ if (!current) return prev;
262
+ if (typeof current === "string") {
263
+ prev.push(current);
264
+ return prev;
265
+ }
266
+ if ("route" in current) {
267
+ if (current.sitemap) routeSitemaps[current.route] = current.sitemap;
268
+ if (current.outputSourceFile) {
269
+ const sourcePath = resolve(workspaceRoot, rootDir, current.outputSourceFile);
270
+ routeSourceFiles[current.route] = readFileSync(sourcePath, "utf8");
271
+ }
272
+ prev.push(current.route);
273
+ if ("staticData" in current) prev.push(`${apiPrefix}/_analog/pages/${current.route}`);
274
+ return prev;
275
+ }
276
+ getMatchingContentFilesWithFrontMatter(workspaceRoot, rootDir, current.contentDir).forEach((f) => {
277
+ const result = current.transform(f);
278
+ if (result) {
279
+ if (current.sitemap) routeSitemaps[result] = current.sitemap && typeof current.sitemap === "function" ? current.sitemap?.(f) : current.sitemap;
280
+ if (current.outputSourceFile) {
281
+ const sourceContent = current.outputSourceFile(f);
282
+ if (sourceContent) routeSourceFiles[result] = sourceContent;
283
+ }
284
+ prev.push(result);
285
+ if ("staticData" in current) prev.push(`${apiPrefix}/_analog/pages/${result}`);
286
+ }
287
+ });
288
+ return prev;
289
+ }, []);
290
+ }
291
+ if (ssrBuild || options?.ssr || nitroConfig.prerender?.routes?.length) {
292
+ if (process.platform === "win32") nitroConfig.noExternals = appendNoExternals(nitroConfig.noExternals, "std-env");
293
+ rollupExternalEntries.push("rxjs", "node-fetch-native/dist/polyfill");
294
+ nitroConfig = {
295
+ ...nitroConfig,
296
+ moduleSideEffects: ["zone.js/node", "zone.js/fesm2015/zone-node"],
297
+ handlers: [
298
+ ...hasAPIDir ? [] : useAPIMiddleware ? [createNitroMiddlewareHandler("#ANALOG_API_MIDDLEWARE")] : [],
299
+ ...pageHandlers,
300
+ {
301
+ handler: rendererHandler,
302
+ route: "/**",
303
+ lazy: true
304
+ }
305
+ ]
306
+ };
307
+ }
308
+ }
309
+ nitroConfig = mergeConfig(nitroConfig, nitroOptions);
310
+ return {
311
+ environments: {
312
+ client: { build: {
313
+ outDir: config?.build?.outDir || resolve(workspaceRoot, "dist", rootDir, "client"),
314
+ emptyOutDir: true,
315
+ ...isRolldown() && codeSplitting !== void 0 ? { rolldownOptions: { output: {
316
+ ...viteRolldownOutputConfig,
317
+ codeSplitting
318
+ } } } : {}
319
+ } },
320
+ ssr: { build: {
321
+ ssr: true,
322
+ [getBundleOptionsKey()]: { input: options?.entryServer || resolve(workspaceRoot, rootDir, `${sourceRoot}/main.server.ts`) },
323
+ outDir: options?.ssrBuildDir || resolve(workspaceRoot, "dist", rootDir, "ssr"),
324
+ emptyOutDir: true
325
+ } }
326
+ },
327
+ builder: {
328
+ sharedPlugins: true,
329
+ buildApp: async (builder) => {
330
+ environmentBuild = true;
331
+ const builds = [builder.build(builder.environments["client"])];
332
+ if (options?.ssr || nitroConfig.prerender?.routes?.length) builds.push(builder.build(builder.environments["ssr"]));
333
+ await Promise.all(builds);
334
+ applySsrEntryAlias(nitroConfig, options, workspaceRoot, rootDir);
335
+ const resolvedClientOutputPath = resolveClientOutputPath(clientOutputPath, workspaceRoot, rootDir, config.build?.outDir);
336
+ registerIndexHtmlVirtual(nitroConfig, resolvedClientOutputPath);
337
+ await buildServer(options, nitroConfig, routeSourceFiles);
338
+ if (nitroConfig.prerender?.routes?.length && options?.prerender?.sitemap) {
339
+ const publicDir = nitroConfig.output?.publicDir;
340
+ if (!publicDir) throw new Error("Nitro public output directory is required to build the sitemap.");
341
+ console.log("Building Sitemap...");
342
+ await buildSitemap(config, options.prerender.sitemap, nitroConfig.prerender.routes, publicDir, routeSitemaps);
343
+ }
344
+ console.log(`\n\nThe '@analogjs/platform' server has been successfully built.`);
345
+ }
346
+ }
347
+ };
348
+ },
349
+ async configureServer(viteServer) {
350
+ if (isServe && !isTest) {
351
+ const nitro = await createNitro({
352
+ dev: true,
353
+ builder: "rollup",
354
+ ...nitroConfig
355
+ });
356
+ const server = createDevServer(nitro);
357
+ await build(nitro);
358
+ const nitroSourceRoots = [normalizePath(resolve(workspaceRoot, rootDir, `${sourceRoot}/server`)), ...(options?.additionalAPIDirs || []).map((dir) => normalizePath(`${workspaceRoot}${dir}`))];
359
+ const isNitroSourceFile = (path) => {
360
+ const normalizedPath = normalizePath(path);
361
+ return nitroSourceRoots.some((root) => normalizedPath === root || normalizedPath.startsWith(`${root}/`));
362
+ };
363
+ let nitroRebuildPromise;
364
+ let nitroRebuildPending = false;
365
+ const rebuildNitroServer = () => {
366
+ if (nitroRebuildPromise) {
367
+ nitroRebuildPending = true;
368
+ return nitroRebuildPromise;
369
+ }
370
+ nitroRebuildPromise = (async () => {
371
+ do {
372
+ nitroRebuildPending = false;
373
+ await build(nitro);
374
+ } while (nitroRebuildPending);
375
+ viteServer.ws.send({ type: "full-reload" });
376
+ })().catch((error) => {
377
+ viteServer.config.logger.error(`[analog] Failed to rebuild Nitro dev server.\n${error instanceof Error ? error.stack || error.message : String(error)}`);
378
+ }).finally(() => {
379
+ nitroRebuildPromise = void 0;
380
+ });
381
+ return nitroRebuildPromise;
382
+ };
383
+ const onNitroSourceChange = (path) => {
384
+ if (!isNitroSourceFile(path)) return;
385
+ rebuildNitroServer();
386
+ };
387
+ viteServer.watcher.on("add", onNitroSourceChange);
388
+ viteServer.watcher.on("change", onNitroSourceChange);
389
+ viteServer.watcher.on("unlink", onNitroSourceChange);
390
+ const apiHandler = async (req, res) => {
391
+ await writeWebResponseToNode(res, await server.fetch(toWebRequest(req)));
392
+ };
393
+ if (hasAPIDir) viteServer.middlewares.use((req, res, next) => {
394
+ if (req.url?.startsWith(`${prefix}${apiPrefix}`)) {
395
+ apiHandler(req, res).catch((error) => next(error));
396
+ return;
397
+ }
398
+ next();
399
+ });
400
+ else viteServer.middlewares.use(apiPrefix, (req, res, next) => {
401
+ apiHandler(req, res).catch((error) => next(error));
402
+ });
403
+ viteServer.httpServer?.once("listening", () => {
404
+ process.env["ANALOG_HOST"] = !viteServer.config.server.host ? "localhost" : viteServer.config.server.host;
405
+ process.env["ANALOG_PORT"] = `${viteServer.config.server.port}`;
406
+ });
407
+ if (nitroOptions?.experimental?.websocket) viteServer.httpServer?.on("upgrade", server.upgrade);
408
+ console.log(`\n\nThe server endpoints are accessible under the "${prefix}${apiPrefix}" path.`);
409
+ }
410
+ },
411
+ async closeBundle() {
412
+ if (environmentBuild) return;
413
+ if (ssrBuild) return;
414
+ if (isBuild) {
415
+ if (options?.ssr) {
416
+ console.log("Building SSR application...");
417
+ await buildSSRApp(config, options);
418
+ }
419
+ if (nitroConfig.prerender?.routes?.length && options?.prerender?.sitemap) {
420
+ console.log("Building Sitemap...");
421
+ await buildSitemap(config, options.prerender.sitemap, nitroConfig.prerender.routes, clientOutputPath, routeSitemaps);
422
+ }
423
+ applySsrEntryAlias(nitroConfig, options, workspaceRoot, rootDir);
424
+ const resolvedClientOutputPath = resolveClientOutputPath(clientOutputPath, workspaceRoot, rootDir, config.build?.outDir);
425
+ registerIndexHtmlVirtual(nitroConfig, resolvedClientOutputPath);
426
+ await buildServer(options, nitroConfig, routeSourceFiles);
427
+ console.log(`\n\nThe '@analogjs/platform' server has been successfully built.`);
428
+ }
429
+ }
430
+ },
431
+ {
432
+ name: "@analogjs/vite-plugin-nitro-api-prefix",
433
+ config() {
434
+ return { define: { ANALOG_API_PREFIX: `"${baseURL.substring(1)}${apiPrefix.substring(1)}"` } };
435
+ }
436
+ }
437
+ ];
511
438
  }
512
439
  function isEmptyPrerenderRoutes(options) {
513
- if (!options || isArrayWithElements(options?.prerender?.routes)) {
514
- return false;
515
- }
516
- return !options.prerender?.routes;
440
+ if (!options || isArrayWithElements(options?.prerender?.routes)) return false;
441
+ return !options.prerender?.routes;
517
442
  }
518
443
  function isArrayWithElements(arr) {
519
- return !!(Array.isArray(arr) && arr.length);
444
+ return !!(Array.isArray(arr) && arr.length);
520
445
  }
521
- const isVercelPreset = (buildPreset) => process.env['VERCEL'] ||
522
- (buildPreset && buildPreset.toLowerCase().includes('vercel'));
523
- const withVercelOutputAPI = (nitroConfig, workspaceRoot, buildPreset) => ({
524
- ...nitroConfig,
525
- preset: nitroConfig?.preset ??
526
- (buildPreset?.toLowerCase().includes('vercel-edge')
527
- ? 'vercel-edge'
528
- : 'vercel'),
529
- vercel: {
530
- ...nitroConfig?.vercel,
531
- ...(buildPreset?.toLowerCase().includes('vercel-edge')
532
- ? {}
533
- : {
534
- entryFormat: nitroConfig?.vercel?.entryFormat ?? 'node',
535
- functions: {
536
- runtime: nitroConfig?.vercel?.functions?.runtime ?? 'nodejs24.x',
537
- ...nitroConfig?.vercel?.functions,
538
- },
539
- }),
540
- },
541
- output: {
542
- ...nitroConfig?.output,
543
- dir: normalizePath(resolve(workspaceRoot, '.vercel', 'output')),
544
- publicDir: normalizePath(resolve(workspaceRoot, '.vercel', 'output/static')),
545
- },
446
+ var withVercelOutputAPI = (nitroConfig, workspaceRoot) => ({
447
+ ...nitroConfig,
448
+ preset: nitroConfig?.preset ?? "vercel",
449
+ vercel: {
450
+ ...nitroConfig?.vercel,
451
+ entryFormat: nitroConfig?.vercel?.entryFormat ?? "node",
452
+ functions: {
453
+ runtime: nitroConfig?.vercel?.functions?.runtime ?? "nodejs24.x",
454
+ ...nitroConfig?.vercel?.functions
455
+ }
456
+ },
457
+ output: {
458
+ ...nitroConfig?.output,
459
+ dir: normalizePath(resolve(workspaceRoot, ".vercel", "output")),
460
+ publicDir: normalizePath(resolve(workspaceRoot, ".vercel", "output/static"))
461
+ }
546
462
  });
547
- const isCloudflarePreset = (buildPreset) => process.env['CF_PAGES'] ||
548
- (buildPreset && buildPreset.toLowerCase().includes('cloudflare-pages'));
549
- const withCloudflareOutput = (nitroConfig) => ({
550
- ...nitroConfig,
551
- output: {
552
- ...nitroConfig?.output,
553
- serverDir: '{{ output.publicDir }}/_worker.js',
554
- },
463
+ var isCloudflarePreset = (buildPreset) => process.env["CF_PAGES"] || buildPreset && (buildPreset.toLowerCase().includes("cloudflare-pages") || buildPreset.toLowerCase().includes("cloudflare_pages"));
464
+ var withCloudflareOutput = (nitroConfig) => ({
465
+ ...nitroConfig,
466
+ output: {
467
+ ...nitroConfig?.output,
468
+ serverDir: "{{ output.publicDir }}/_worker.js"
469
+ }
555
470
  });
556
- const isFirebaseAppHosting = () => !!process.env['NG_BUILD_LOGS_JSON'];
557
- const withAppHostingOutput = (nitroConfig) => {
558
- let hasOutput = false;
559
- return {
560
- ...nitroConfig,
561
- serveStatic: true,
562
- rollupConfig: {
563
- ...nitroConfig.rollupConfig,
564
- output: {
565
- ...nitroConfig.rollupConfig?.output,
566
- entryFileNames: 'server.mjs',
567
- },
568
- },
569
- hooks: {
570
- ...nitroConfig.hooks,
571
- compiled: () => {
572
- if (!hasOutput) {
573
- const buildOutput = {
574
- errors: [],
575
- warnings: [],
576
- outputPaths: {
577
- root: pathToFileURL(`${nitroConfig.output?.dir}`),
578
- browser: pathToFileURL(`${nitroConfig.output?.publicDir}`),
579
- server: pathToFileURL(`${nitroConfig.output?.dir}/server`),
580
- },
581
- };
582
- // Log the build output for Firebase App Hosting to pick up
583
- console.log(JSON.stringify(buildOutput, null, 2));
584
- hasOutput = true;
585
- }
586
- },
587
- },
588
- };
471
+ var isFirebaseAppHosting = () => !!process.env["NG_BUILD_LOGS_JSON"];
472
+ var withAppHostingOutput = (nitroConfig) => {
473
+ let hasOutput = false;
474
+ return {
475
+ ...nitroConfig,
476
+ serveStatic: true,
477
+ rollupConfig: {
478
+ ...nitroConfig.rollupConfig,
479
+ output: {
480
+ ...nitroConfig.rollupConfig?.output,
481
+ entryFileNames: "server.mjs"
482
+ }
483
+ },
484
+ hooks: {
485
+ ...nitroConfig.hooks,
486
+ compiled: () => {
487
+ if (!hasOutput) {
488
+ const buildOutput = {
489
+ errors: [],
490
+ warnings: [],
491
+ outputPaths: {
492
+ root: pathToFileURL(`${nitroConfig.output?.dir}`),
493
+ browser: pathToFileURL(`${nitroConfig.output?.publicDir}`),
494
+ server: pathToFileURL(`${nitroConfig.output?.dir}/server`)
495
+ }
496
+ };
497
+ console.log(JSON.stringify(buildOutput, null, 2));
498
+ hasOutput = true;
499
+ }
500
+ }
501
+ }
502
+ };
589
503
  };
590
- const isNetlifyPreset = (buildPreset) => process.env['NETLIFY'] ||
591
- (buildPreset && buildPreset.toLowerCase().includes('netlify'));
592
- const withNetlifyOutputAPI = (nitroConfig, workspaceRoot) => ({
593
- ...nitroConfig,
594
- output: {
595
- ...nitroConfig?.output,
596
- dir: normalizePath(resolve(workspaceRoot, 'netlify/functions')),
597
- },
504
+ var isNetlifyPreset = (buildPreset) => process.env["NETLIFY"] || buildPreset && buildPreset.toLowerCase().includes("netlify");
505
+ var withNetlifyOutputAPI = (nitroConfig, workspaceRoot) => ({
506
+ ...nitroConfig,
507
+ output: {
508
+ ...nitroConfig?.output,
509
+ dir: normalizePath(resolve(workspaceRoot, "netlify/functions"))
510
+ }
598
511
  });
512
+ //#endregion
513
+ export { nitro };
514
+
599
515
  //# sourceMappingURL=vite-plugin-nitro.js.map