@analogjs/vite-plugin-nitro 2.4.0-alpha.3 → 2.4.0-beta.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.
- package/README.md +2 -2
- package/package.json +2 -4
- package/src/index.d.ts +1 -1
- package/src/lib/build-server.d.ts +1 -1
- package/src/lib/build-server.js +3 -30
- package/src/lib/build-server.js.map +1 -1
- package/src/lib/hooks/post-rendering-hook.d.ts +1 -1
- package/src/lib/options.d.ts +1 -1
- package/src/lib/plugins/dev-server-plugin.js +2 -4
- package/src/lib/plugins/dev-server-plugin.js.map +1 -1
- package/src/lib/plugins/page-endpoints.js +10 -33
- package/src/lib/plugins/page-endpoints.js.map +1 -1
- package/src/lib/utils/get-content-files.js +4 -1
- package/src/lib/utils/get-content-files.js.map +1 -1
- package/src/lib/utils/get-page-handlers.d.ts +1 -1
- package/src/lib/utils/get-page-handlers.js +3 -5
- package/src/lib/utils/get-page-handlers.js.map +1 -1
- package/src/lib/utils/register-dev-middleware.d.ts +32 -4
- package/src/lib/utils/register-dev-middleware.js +43 -22
- package/src/lib/utils/register-dev-middleware.js.map +1 -1
- package/src/lib/utils/renderers.d.ts +3 -42
- package/src/lib/utils/renderers.js +26 -98
- package/src/lib/utils/renderers.js.map +1 -1
- package/src/lib/vite-plugin-nitro.d.ts +1 -1
- package/src/lib/vite-plugin-nitro.js +68 -207
- package/src/lib/vite-plugin-nitro.js.map +1 -1
- package/src/lib/utils/node-web-bridge.d.ts +0 -3
- package/src/lib/utils/node-web-bridge.js +0 -50
- package/src/lib/utils/node-web-bridge.js.map +0 -1
|
@@ -1,130 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* This code runs inside Nitro's server runtime (Node.js context) where
|
|
5
|
-
* event.node is always populated. In h3 v2, event.node is typed as optional,
|
|
6
|
-
* so we use h3's first-class event properties (event.path, event.method) where
|
|
7
|
-
* possible and apply optional chaining when accessing the Node.js context for
|
|
8
|
-
* the Angular renderer which requires raw req/res objects.
|
|
9
|
-
*
|
|
10
|
-
* h3 v2 idiomatic APIs used:
|
|
11
|
-
* - defineHandler (replaces defineEventHandler / eventHandler)
|
|
12
|
-
* - event.path (replaces event.node.req.url)
|
|
13
|
-
* - getResponseHeader compat shim (still available in h3 v2)
|
|
14
|
-
*/
|
|
15
|
-
export function ssrRenderer(templatePath) {
|
|
16
|
-
return `
|
|
17
|
-
import { readFileSync } from 'node:fs';
|
|
18
|
-
import { createFetch } from 'ofetch';
|
|
19
|
-
import { defineHandler, fetchWithEvent } from 'h3';
|
|
1
|
+
export const ssrRenderer = `
|
|
2
|
+
import { eventHandler, getResponseHeader } from 'h3';
|
|
20
3
|
// @ts-ignore
|
|
21
4
|
import renderer from '#analog/ssr';
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import template from '#analog/index';
|
|
22
7
|
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
url.replace(/\\/index\\.html(?=$|[?#])/, '/');
|
|
26
|
-
|
|
27
|
-
export default defineHandler(async (event) => {
|
|
28
|
-
event.res.headers.set('content-type', 'text/html; charset=utf-8');
|
|
29
|
-
const noSSR = event.res.headers.get('x-analog-no-ssr');
|
|
30
|
-
const requestPath = normalizeHtmlRequestUrl(event.path);
|
|
8
|
+
export default eventHandler(async (event) => {
|
|
9
|
+
const noSSR = getResponseHeader(event, 'x-analog-no-ssr');
|
|
31
10
|
|
|
32
11
|
if (noSSR === 'true') {
|
|
33
12
|
return template;
|
|
34
13
|
}
|
|
35
14
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// During prerendering (Nitro v3 fetch-based pipeline), event.node is undefined.
|
|
40
|
-
// The Angular renderer requires a req object with at least { headers, url },
|
|
41
|
-
// so we provide a minimal stub to avoid runtime errors in prerender context.
|
|
42
|
-
const req = event.node?.req
|
|
43
|
-
? {
|
|
44
|
-
...event.node.req,
|
|
45
|
-
url: requestPath,
|
|
46
|
-
originalUrl: requestPath,
|
|
47
|
-
}
|
|
48
|
-
: {
|
|
49
|
-
headers: { host: 'localhost' },
|
|
50
|
-
url: requestPath,
|
|
51
|
-
originalUrl: requestPath,
|
|
52
|
-
connection: {},
|
|
53
|
-
};
|
|
54
|
-
const res = event.node?.res;
|
|
55
|
-
const fetch = createFetch({
|
|
56
|
-
fetch: (resource, init) => {
|
|
57
|
-
const url = resource instanceof Request ? resource.url : resource.toString();
|
|
58
|
-
return fetchWithEvent(event, url, init);
|
|
59
|
-
}
|
|
15
|
+
const html = await renderer(event.node.req.url, template, {
|
|
16
|
+
req: event.node.req,
|
|
17
|
+
res: event.node.res,
|
|
60
18
|
});
|
|
61
19
|
|
|
62
|
-
const html = await renderer(requestPath, template, { req, res, fetch });
|
|
63
|
-
|
|
64
20
|
return html;
|
|
65
21
|
});`;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
* Client-only renderer virtual module content.
|
|
69
|
-
*
|
|
70
|
-
* Used when SSR is disabled — simply serves the static index.html template
|
|
71
|
-
* for every route, letting the client-side Angular router handle navigation.
|
|
72
|
-
*/
|
|
73
|
-
export function clientRenderer(templatePath) {
|
|
74
|
-
return `
|
|
75
|
-
import { readFileSync } from 'node:fs';
|
|
76
|
-
import { defineHandler } from 'h3';
|
|
22
|
+
export const clientRenderer = `
|
|
23
|
+
import { eventHandler } from 'h3';
|
|
77
24
|
|
|
78
|
-
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
import template from '#analog/index';
|
|
79
27
|
|
|
80
|
-
export default
|
|
81
|
-
event.res.headers.set('content-type', 'text/html; charset=utf-8');
|
|
28
|
+
export default eventHandler(async () => {
|
|
82
29
|
return template;
|
|
83
30
|
});
|
|
84
31
|
`;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* API middleware virtual module content.
|
|
88
|
-
*
|
|
89
|
-
* Intercepts requests matching the configured API prefix and either:
|
|
90
|
-
* - Uses event-bound internal forwarding for GET requests (except .xml routes)
|
|
91
|
-
* - Uses request proxying for all other methods to forward the full request
|
|
92
|
-
*
|
|
93
|
-
* h3 v2 idiomatic APIs used:
|
|
94
|
-
* - defineHandler (replaces defineEventHandler / eventHandler)
|
|
95
|
-
* - event.path (replaces event.node.req.url)
|
|
96
|
-
* - event.method (replaces event.node.req.method)
|
|
97
|
-
* - proxyRequest is retained internally because it preserves Nitro route
|
|
98
|
-
* matching for event-bound server requests during SSR/prerender
|
|
99
|
-
* - Object.fromEntries(event.req.headers.entries()) replaces direct event.node.req.headers access
|
|
100
|
-
*
|
|
101
|
-
* `fetchWithEvent` keeps the active event context while forwarding to a
|
|
102
|
-
* rewritten path, which avoids falling through to the HTML renderer when
|
|
103
|
-
* SSR code makes relative API requests.
|
|
104
|
-
*/
|
|
105
32
|
export const apiMiddleware = `
|
|
106
|
-
import {
|
|
107
|
-
import { useRuntimeConfig } from '
|
|
33
|
+
import { eventHandler, proxyRequest } from 'h3';
|
|
34
|
+
import { useRuntimeConfig } from '#imports';
|
|
108
35
|
|
|
109
|
-
export default
|
|
36
|
+
export default eventHandler(async (event) => {
|
|
110
37
|
const prefix = useRuntimeConfig().prefix;
|
|
111
38
|
const apiPrefix = \`\${prefix}/\${useRuntimeConfig().apiPrefix}\`;
|
|
112
39
|
|
|
113
|
-
if (event.
|
|
114
|
-
const reqUrl = event.
|
|
40
|
+
if (event.node.req.url?.startsWith(apiPrefix)) {
|
|
41
|
+
const reqUrl = event.node.req.url?.replace(apiPrefix, '');
|
|
115
42
|
|
|
116
43
|
if (
|
|
117
|
-
event.method === 'GET' &&
|
|
44
|
+
event.node.req.method === 'GET' &&
|
|
118
45
|
// in the case of XML routes, we want to proxy the request so that nitro gets the correct headers
|
|
119
46
|
// and can render the XML correctly as a static asset
|
|
120
|
-
!event.
|
|
47
|
+
!event.node.req.url?.endsWith('.xml')
|
|
121
48
|
) {
|
|
122
|
-
return
|
|
123
|
-
headers: Object.fromEntries(event.req.headers.entries()),
|
|
124
|
-
});
|
|
49
|
+
return $fetch(reqUrl, { headers: event.node.req.headers });
|
|
125
50
|
}
|
|
126
51
|
|
|
127
|
-
return proxyRequest(event, reqUrl
|
|
52
|
+
return proxyRequest(event, reqUrl, {
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
fetch: $fetch.native,
|
|
55
|
+
});
|
|
128
56
|
}
|
|
129
57
|
});`;
|
|
130
58
|
//# sourceMappingURL=renderers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderers.js","sourceRoot":"","sources":["../../../../../../packages/vite-plugin-nitro/src/lib/utils/renderers.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"renderers.js","sourceRoot":"","sources":["../../../../../../packages/vite-plugin-nitro/src/lib/utils/renderers.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;IAoBvB,CAAC;AAEL,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;CAS7B,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;IAyBzB,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { build, createDevServer, createNitro } from '
|
|
2
|
-
import
|
|
1
|
+
import { build, createDevServer, createNitro } from 'nitropack';
|
|
2
|
+
import { toNodeListener } from 'h3';
|
|
3
3
|
import { mergeConfig, normalizePath } from 'vite';
|
|
4
|
-
import { relative, resolve } from 'node:path';
|
|
5
|
-
import {
|
|
4
|
+
import { dirname, relative, resolve } from 'node:path';
|
|
5
|
+
import { platform } from 'node:os';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
7
|
import { existsSync, readFileSync } from 'node:fs';
|
|
7
8
|
import { buildServer } from './build-server.js';
|
|
8
9
|
import { buildSSRApp } from './build-ssr.js';
|
|
@@ -10,115 +11,13 @@ import { pageEndpointsPlugin } from './plugins/page-endpoints.js';
|
|
|
10
11
|
import { getPageHandlers } from './utils/get-page-handlers.js';
|
|
11
12
|
import { buildSitemap } from './build-sitemap.js';
|
|
12
13
|
import { devServerPlugin } from './plugins/dev-server-plugin.js';
|
|
13
|
-
import { toWebRequest, writeWebResponseToNode, } from './utils/node-web-bridge.js';
|
|
14
14
|
import { getMatchingContentFilesWithFrontMatter } from './utils/get-content-files.js';
|
|
15
15
|
import { ssrRenderer, clientRenderer, apiMiddleware, } from './utils/renderers.js';
|
|
16
|
+
const isWindows = platform() === 'win32';
|
|
17
|
+
const filePrefix = isWindows ? 'file:///' : '';
|
|
16
18
|
let clientOutputPath = '';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
route: '/**',
|
|
21
|
-
handler,
|
|
22
|
-
middleware: true,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
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
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function appendNoExternals(noExternals, ...entries) {
|
|
48
|
-
if (!noExternals) {
|
|
49
|
-
return entries;
|
|
50
|
-
}
|
|
51
|
-
return Array.isArray(noExternals)
|
|
52
|
-
? [...noExternals, ...entries]
|
|
53
|
-
: noExternals;
|
|
54
|
-
}
|
|
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
|
-
}
|
|
91
|
-
}
|
|
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');
|
|
102
|
-
}
|
|
103
|
-
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);
|
|
109
|
-
}
|
|
110
|
-
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;
|
|
121
|
-
}
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = dirname(__filename);
|
|
122
21
|
export function nitro(options, nitroOptions) {
|
|
123
22
|
const workspaceRoot = options?.workspaceRoot ?? process.cwd();
|
|
124
23
|
const sourceRoot = options?.sourceRoot ?? 'src';
|
|
@@ -136,7 +35,6 @@ export function nitro(options, nitroOptions) {
|
|
|
136
35
|
let nitroConfig;
|
|
137
36
|
let environmentBuild = false;
|
|
138
37
|
let hasAPIDir = false;
|
|
139
|
-
const rollupExternalEntries = [];
|
|
140
38
|
const routeSitemaps = {};
|
|
141
39
|
const routeSourceFiles = {};
|
|
142
40
|
let rootDir = workspaceRoot;
|
|
@@ -159,8 +57,7 @@ export function nitro(options, nitroOptions) {
|
|
|
159
57
|
rootDir = relative(workspaceRoot, config.root || '.') || '.';
|
|
160
58
|
hasAPIDir = existsSync(resolve(workspaceRoot, rootDir, `${sourceRoot}/server/routes/${options?.apiPrefix || 'api'}`));
|
|
161
59
|
const buildPreset = process.env['BUILD_PRESET'] ??
|
|
162
|
-
nitroOptions?.preset
|
|
163
|
-
(process.env['VERCEL'] ? 'vercel' : undefined);
|
|
60
|
+
nitroOptions?.preset;
|
|
164
61
|
const pageHandlers = getPageHandlers({
|
|
165
62
|
workspaceRoot,
|
|
166
63
|
sourceRoot,
|
|
@@ -168,14 +65,12 @@ export function nitro(options, nitroOptions) {
|
|
|
168
65
|
additionalPagesDirs: options?.additionalPagesDirs,
|
|
169
66
|
hasAPIDir,
|
|
170
67
|
});
|
|
171
|
-
const resolvedClientOutputPath = resolveClientOutputPath(workspaceRoot, rootDir, config.build?.outDir, ssrBuild);
|
|
172
|
-
rendererIndexEntry = normalizePath(resolve(resolvedClientOutputPath, 'index.html'));
|
|
173
68
|
nitroConfig = {
|
|
174
|
-
rootDir
|
|
69
|
+
rootDir,
|
|
175
70
|
preset: buildPreset,
|
|
176
71
|
compatibilityDate: '2024-11-19',
|
|
177
72
|
logLevel: nitroOptions?.logLevel || 0,
|
|
178
|
-
|
|
73
|
+
srcDir: normalizePath(`${sourceRoot}/server`),
|
|
179
74
|
scanDirs: [
|
|
180
75
|
normalizePath(`${rootDir}/${sourceRoot}/server`),
|
|
181
76
|
...(options?.additionalAPIDirs || []).map((dir) => normalizePath(`${workspaceRoot}${dir}`)),
|
|
@@ -192,15 +87,10 @@ export function nitro(options, nitroOptions) {
|
|
|
192
87
|
apiPrefix: apiPrefix.substring(1),
|
|
193
88
|
prefix,
|
|
194
89
|
},
|
|
195
|
-
//
|
|
196
|
-
// auto-detecting index.html in rootDir and adding a conflicting one.
|
|
197
|
-
renderer: false,
|
|
90
|
+
// Fixes support for Rolldown
|
|
198
91
|
imports: {
|
|
199
92
|
autoImport: false,
|
|
200
93
|
},
|
|
201
|
-
hooks: {
|
|
202
|
-
'rollup:before': createRollupBeforeHook(rollupExternalEntries),
|
|
203
|
-
},
|
|
204
94
|
rollupConfig: {
|
|
205
95
|
onwarn(warning) {
|
|
206
96
|
if (warning.message.includes('empty chunk') &&
|
|
@@ -214,7 +104,12 @@ export function nitro(options, nitroOptions) {
|
|
|
214
104
|
...(hasAPIDir
|
|
215
105
|
? []
|
|
216
106
|
: useAPIMiddleware
|
|
217
|
-
? [
|
|
107
|
+
? [
|
|
108
|
+
{
|
|
109
|
+
handler: '#ANALOG_API_MIDDLEWARE',
|
|
110
|
+
middleware: true,
|
|
111
|
+
},
|
|
112
|
+
]
|
|
218
113
|
: []),
|
|
219
114
|
...pageHandlers,
|
|
220
115
|
],
|
|
@@ -228,13 +123,13 @@ export function nitro(options, nitroOptions) {
|
|
|
228
123
|
},
|
|
229
124
|
},
|
|
230
125
|
virtual: {
|
|
231
|
-
'#ANALOG_SSR_RENDERER': ssrRenderer
|
|
232
|
-
'#ANALOG_CLIENT_RENDERER': clientRenderer
|
|
126
|
+
'#ANALOG_SSR_RENDERER': ssrRenderer,
|
|
127
|
+
'#ANALOG_CLIENT_RENDERER': clientRenderer,
|
|
233
128
|
...(hasAPIDir ? {} : { '#ANALOG_API_MIDDLEWARE': apiMiddleware }),
|
|
234
129
|
},
|
|
235
130
|
};
|
|
236
131
|
if (isVercelPreset(buildPreset)) {
|
|
237
|
-
nitroConfig = withVercelOutputAPI(nitroConfig, workspaceRoot
|
|
132
|
+
nitroConfig = withVercelOutputAPI(nitroConfig, workspaceRoot);
|
|
238
133
|
}
|
|
239
134
|
if (isCloudflarePreset(buildPreset)) {
|
|
240
135
|
nitroConfig = withCloudflareOutput(nitroConfig);
|
|
@@ -249,30 +144,17 @@ export function nitro(options, nitroOptions) {
|
|
|
249
144
|
}
|
|
250
145
|
if (!ssrBuild && !isTest) {
|
|
251
146
|
// store the client output path for the SSR build config
|
|
252
|
-
clientOutputPath =
|
|
147
|
+
clientOutputPath = resolve(workspaceRoot, rootDir, config.build?.outDir || 'dist/client');
|
|
253
148
|
}
|
|
149
|
+
const indexEntry = normalizePath(resolve(clientOutputPath, 'index.html'));
|
|
150
|
+
nitroConfig.alias = {
|
|
151
|
+
'#analog/index': indexEntry,
|
|
152
|
+
};
|
|
254
153
|
if (isBuild) {
|
|
255
|
-
nitroConfig.publicAssets = [
|
|
256
|
-
|
|
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
|
|
154
|
+
nitroConfig.publicAssets = [{ dir: clientOutputPath }];
|
|
155
|
+
nitroConfig.renderer = options?.ssr
|
|
266
156
|
? '#ANALOG_SSR_RENDERER'
|
|
267
157
|
: '#ANALOG_CLIENT_RENDERER';
|
|
268
|
-
nitroConfig.handlers = [
|
|
269
|
-
...(nitroConfig.handlers || []),
|
|
270
|
-
{
|
|
271
|
-
handler: rendererHandler,
|
|
272
|
-
route: '/**',
|
|
273
|
-
lazy: true,
|
|
274
|
-
},
|
|
275
|
-
];
|
|
276
158
|
if (isEmptyPrerenderRoutes(options)) {
|
|
277
159
|
nitroConfig.prerender = {};
|
|
278
160
|
nitroConfig.prerender.routes = ['/'];
|
|
@@ -338,26 +220,30 @@ export function nitro(options, nitroOptions) {
|
|
|
338
220
|
}, []);
|
|
339
221
|
}
|
|
340
222
|
if (ssrBuild) {
|
|
341
|
-
if (
|
|
342
|
-
nitroConfig.
|
|
223
|
+
if (isWindows) {
|
|
224
|
+
nitroConfig.externals = {
|
|
225
|
+
inline: ['std-env'],
|
|
226
|
+
};
|
|
343
227
|
}
|
|
344
|
-
rollupExternalEntries.push('rxjs', 'node-fetch-native/dist/polyfill');
|
|
345
228
|
nitroConfig = {
|
|
346
229
|
...nitroConfig,
|
|
230
|
+
externals: {
|
|
231
|
+
...nitroConfig.externals,
|
|
232
|
+
external: ['rxjs', 'node-fetch-native/dist/polyfill'],
|
|
233
|
+
},
|
|
347
234
|
moduleSideEffects: ['zone.js/node', 'zone.js/fesm2015/zone-node'],
|
|
348
235
|
handlers: [
|
|
349
236
|
...(hasAPIDir
|
|
350
237
|
? []
|
|
351
238
|
: useAPIMiddleware
|
|
352
|
-
? [
|
|
239
|
+
? [
|
|
240
|
+
{
|
|
241
|
+
handler: '#ANALOG_API_MIDDLEWARE',
|
|
242
|
+
middleware: true,
|
|
243
|
+
},
|
|
244
|
+
]
|
|
353
245
|
: []),
|
|
354
246
|
...pageHandlers,
|
|
355
|
-
// Preserve the renderer catch-all handler added above
|
|
356
|
-
{
|
|
357
|
-
handler: rendererHandler,
|
|
358
|
-
route: '/**',
|
|
359
|
-
lazy: true,
|
|
360
|
-
},
|
|
361
247
|
],
|
|
362
248
|
};
|
|
363
249
|
}
|
|
@@ -374,7 +260,7 @@ export function nitro(options, nitroOptions) {
|
|
|
374
260
|
ssr: {
|
|
375
261
|
build: {
|
|
376
262
|
ssr: true,
|
|
377
|
-
|
|
263
|
+
rollupOptions: {
|
|
378
264
|
input: options?.entryServer ||
|
|
379
265
|
resolve(workspaceRoot, rootDir, `${sourceRoot}/main.server.ts`),
|
|
380
266
|
},
|
|
@@ -392,16 +278,17 @@ export function nitro(options, nitroOptions) {
|
|
|
392
278
|
builds.push(builder.build(builder.environments['ssr']));
|
|
393
279
|
}
|
|
394
280
|
await Promise.all(builds);
|
|
395
|
-
|
|
396
|
-
resolve(workspaceRoot, 'dist', rootDir, `ssr`);
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
nitroConfig.alias = {
|
|
401
|
-
...nitroConfig.alias,
|
|
402
|
-
'#analog/ssr': ssrEntry,
|
|
403
|
-
};
|
|
281
|
+
let ssrEntryPath = resolve(options?.ssrBuildDir ||
|
|
282
|
+
resolve(workspaceRoot, 'dist', rootDir, `ssr`), `main.server${filePrefix ? '.js' : ''}`);
|
|
283
|
+
// add check for main.server.mjs fallback on Windows
|
|
284
|
+
if (isWindows && !existsSync(ssrEntryPath)) {
|
|
285
|
+
ssrEntryPath = ssrEntryPath.replace('.js', '.mjs');
|
|
404
286
|
}
|
|
287
|
+
const ssrEntry = normalizePath(filePrefix + ssrEntryPath);
|
|
288
|
+
nitroConfig.alias = {
|
|
289
|
+
...nitroConfig.alias,
|
|
290
|
+
'#analog/ssr': ssrEntry,
|
|
291
|
+
};
|
|
405
292
|
await buildServer(options, nitroConfig, routeSourceFiles);
|
|
406
293
|
if (nitroConfig.prerender?.routes?.length &&
|
|
407
294
|
options?.prerender?.sitemap) {
|
|
@@ -422,33 +309,22 @@ export function nitro(options, nitroOptions) {
|
|
|
422
309
|
if (isServe && !isTest) {
|
|
423
310
|
const nitro = await createNitro({
|
|
424
311
|
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
312
|
...nitroConfig,
|
|
430
313
|
});
|
|
431
314
|
const server = createDevServer(nitro);
|
|
432
315
|
await build(nitro);
|
|
433
|
-
const apiHandler =
|
|
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
|
-
};
|
|
316
|
+
const apiHandler = toNodeListener(server.app);
|
|
439
317
|
if (hasAPIDir) {
|
|
440
318
|
viteServer.middlewares.use((req, res, next) => {
|
|
441
319
|
if (req.url?.startsWith(`${prefix}${apiPrefix}`)) {
|
|
442
|
-
|
|
320
|
+
apiHandler(req, res);
|
|
443
321
|
return;
|
|
444
322
|
}
|
|
445
323
|
next();
|
|
446
324
|
});
|
|
447
325
|
}
|
|
448
326
|
else {
|
|
449
|
-
viteServer.middlewares.use(apiPrefix,
|
|
450
|
-
void apiHandler(req, res).catch((error) => next(error));
|
|
451
|
-
});
|
|
327
|
+
viteServer.middlewares.use(apiPrefix, apiHandler);
|
|
452
328
|
}
|
|
453
329
|
viteServer.httpServer?.once('listening', () => {
|
|
454
330
|
process.env['ANALOG_HOST'] = !viteServer.config.server.host
|
|
@@ -482,16 +358,17 @@ export function nitro(options, nitroOptions) {
|
|
|
482
358
|
// sitemap needs to be built after all directories are built
|
|
483
359
|
await buildSitemap(config, options.prerender.sitemap, nitroConfig.prerender.routes, clientOutputPath, routeSitemaps);
|
|
484
360
|
}
|
|
485
|
-
|
|
486
|
-
resolve(workspaceRoot, 'dist', rootDir, `ssr`);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
nitroConfig.alias = {
|
|
491
|
-
...nitroConfig.alias,
|
|
492
|
-
'#analog/ssr': ssrEntry,
|
|
493
|
-
};
|
|
361
|
+
let ssrEntryPath = resolve(options?.ssrBuildDir ||
|
|
362
|
+
resolve(workspaceRoot, 'dist', rootDir, `ssr`), `main.server${filePrefix ? '.js' : ''}`);
|
|
363
|
+
// add check for main.server.mjs fallback on Windows
|
|
364
|
+
if (isWindows && !existsSync(ssrEntryPath)) {
|
|
365
|
+
ssrEntryPath = ssrEntryPath.replace('.js', '.mjs');
|
|
494
366
|
}
|
|
367
|
+
const ssrEntry = normalizePath(filePrefix + ssrEntryPath);
|
|
368
|
+
nitroConfig.alias = {
|
|
369
|
+
...nitroConfig.alias,
|
|
370
|
+
'#analog/ssr': ssrEntry,
|
|
371
|
+
};
|
|
495
372
|
await buildServer(options, nitroConfig, routeSourceFiles);
|
|
496
373
|
console.log(`\n\nThe '@analogjs/platform' server has been successfully built.`);
|
|
497
374
|
}
|
|
@@ -520,24 +397,8 @@ function isArrayWithElements(arr) {
|
|
|
520
397
|
}
|
|
521
398
|
const isVercelPreset = (buildPreset) => process.env['VERCEL'] ||
|
|
522
399
|
(buildPreset && buildPreset.toLowerCase().includes('vercel'));
|
|
523
|
-
const withVercelOutputAPI = (nitroConfig, workspaceRoot
|
|
400
|
+
const withVercelOutputAPI = (nitroConfig, workspaceRoot) => ({
|
|
524
401
|
...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
402
|
output: {
|
|
542
403
|
...nitroConfig?.output,
|
|
543
404
|
dir: normalizePath(resolve(workspaceRoot, '.vercel', 'output')),
|