@analogjs/platform 3.0.0-alpha.91 → 3.0.0-alpha.93
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/migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.d.ts +2 -0
- package/migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.js +203 -0
- package/migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.js.map +1 -0
- package/package.json +11 -7
- package/src/lib/clear-client-page-endpoint.js +1 -0
- package/src/lib/clear-client-page-endpoint.js.map +1 -1
- package/src/lib/deps-plugin.js +17 -6
- package/src/lib/deps-plugin.js.map +1 -1
- package/src/lib/nitro/analog-nitro-plugin.js +102 -45
- package/src/lib/nitro/analog-nitro-plugin.js.map +1 -1
- package/src/lib/nitro/get-server-fn-handlers.d.ts +29 -0
- package/src/lib/nitro/get-server-fn-handlers.js +66 -0
- package/src/lib/nitro/get-server-fn-handlers.js.map +1 -0
- package/src/lib/nitro/server-fn-endpoints.d.ts +41 -0
- package/src/lib/nitro/server-fn-endpoints.js +57 -0
- package/src/lib/nitro/server-fn-endpoints.js.map +1 -0
- package/src/lib/nx-plugin/src/generators/app/files/template-angular/src/server/routes/api/v1/hello.ts__template__ +2 -2
- package/src/lib/nx-plugin/src/generators/app/files/template-angular/vite.config.ts__template__ +4 -0
- package/src/lib/nx-plugin/src/generators/app/generator.js +5 -0
- package/src/lib/nx-plugin/src/generators/app/generator.js.map +1 -1
- package/src/lib/nx-plugin/src/generators/app/versions/nx_18_X/versions.d.ts +8 -6
- package/src/lib/nx-plugin/src/generators/app/versions/nx_18_X/versions.js.map +1 -1
- package/src/lib/nx-plugin/src/generators/init/lib/update-git-ignore.js +4 -7
- package/src/lib/nx-plugin/src/generators/init/lib/update-git-ignore.js.map +1 -1
- package/src/lib/nx-plugin/src/generators/preset/__snapshots__/generator.spec.ts.snap +3 -1
- package/src/lib/nx-plugin/src/utils/versions/ng_19_X/versions.d.ts +6 -6
- package/src/lib/nx-plugin/src/utils/versions/ng_19_X/versions.js +6 -6
- package/src/lib/nx-plugin/src/utils/versions/ng_19_X/versions.js.map +1 -1
- package/src/lib/options.d.ts +17 -1
- package/src/lib/platform-plugin.js +34 -3
- package/src/lib/platform-plugin.js.map +1 -1
- package/src/lib/ssr/defer-streaming-plugin.d.ts +3 -35
- package/src/lib/ssr/defer-streaming-plugin.js +103 -0
- package/src/lib/ssr/defer-streaming-plugin.js.map +1 -0
- package/src/lib/ssr/ssr-build-plugin.d.ts +1 -1
- package/src/lib/ssr/ssr-build-plugin.js.map +1 -1
- package/src/lib/utils/rolldown.js +1 -1
- package/src/server-mode-plugin.d.ts +1 -1
- package/src/server-mode-plugin.js +13 -1
- package/src/server-mode-plugin.js.map +1 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { NodePackageInstallTask } from "@angular-devkit/schematics/tasks/index.js";
|
|
2
|
+
import * as ts from "typescript";
|
|
3
|
+
//#region packages/platform/migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.ts
|
|
4
|
+
var ANALOG_PLATFORM_IMPORT = `from '@analogjs/platform'`;
|
|
5
|
+
var ANGULAR_PLUGIN_IMPORT = `from '@analogjs/vite-plugin-angular'`;
|
|
6
|
+
var NITRO_IMPORTS = [`from '@analogjs/vite-plugin-nitro'`, `from 'nitro/vite'`];
|
|
7
|
+
var ANGULAR_PLUGIN_PKG = "@analogjs/vite-plugin-angular";
|
|
8
|
+
var NITRO_PLUGIN_PKG = "@analogjs/vite-plugin-nitro";
|
|
9
|
+
var MIGRATION_DOC_URL = "https://analogjs.org/docs/guides/migrating-v2-to-v3#analog-angular-and-nitro-are-now-separate-plugins";
|
|
10
|
+
var VITE_CONFIG_EXTENSIONS = [
|
|
11
|
+
".ts",
|
|
12
|
+
".mts",
|
|
13
|
+
".js",
|
|
14
|
+
".mjs"
|
|
15
|
+
];
|
|
16
|
+
function isViteConfig(filePath) {
|
|
17
|
+
const file = filePath.slice(filePath.lastIndexOf("/") + 1);
|
|
18
|
+
if (!file.startsWith("vite.config.")) return false;
|
|
19
|
+
return VITE_CONFIG_EXTENSIONS.some((ext) => file.endsWith(ext));
|
|
20
|
+
}
|
|
21
|
+
function usesLegacyPluginShape(source) {
|
|
22
|
+
if (!source.includes(ANALOG_PLATFORM_IMPORT)) return false;
|
|
23
|
+
if (source.includes(ANGULAR_PLUGIN_IMPORT) && NITRO_IMPORTS.some((nitroImport) => source.includes(nitroImport))) return false;
|
|
24
|
+
return /\banalog\s*\(/.test(source);
|
|
25
|
+
}
|
|
26
|
+
function readPackageJson(tree) {
|
|
27
|
+
const content = tree.read("/package.json");
|
|
28
|
+
if (!content) return null;
|
|
29
|
+
const raw = content.toString("utf-8");
|
|
30
|
+
try {
|
|
31
|
+
return {
|
|
32
|
+
raw,
|
|
33
|
+
pkg: JSON.parse(raw)
|
|
34
|
+
};
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getDepVersion(pkg, name) {
|
|
40
|
+
const dev = pkg["devDependencies"] ?? {};
|
|
41
|
+
const reg = pkg["dependencies"] ?? {};
|
|
42
|
+
return dev[name] ?? reg[name];
|
|
43
|
+
}
|
|
44
|
+
function addDependencies(tree, context) {
|
|
45
|
+
const info = readPackageJson(tree);
|
|
46
|
+
if (!info) return false;
|
|
47
|
+
const { pkg, raw } = info;
|
|
48
|
+
const devDeps = { ...pkg["devDependencies"] ?? {} };
|
|
49
|
+
let changed = false;
|
|
50
|
+
const platformVersion = getDepVersion(pkg, "@analogjs/platform") ?? "*";
|
|
51
|
+
const missingPlugins = [ANGULAR_PLUGIN_PKG, NITRO_PLUGIN_PKG].filter((name) => !getDepVersion(pkg, name) && !(name === NITRO_PLUGIN_PKG && getDepVersion(pkg, "nitro")));
|
|
52
|
+
for (const name of missingPlugins) {
|
|
53
|
+
devDeps[name] = platformVersion;
|
|
54
|
+
changed = true;
|
|
55
|
+
context.logger.info(`Added '${name}': '${platformVersion}' to devDependencies.`);
|
|
56
|
+
}
|
|
57
|
+
if (!changed) return false;
|
|
58
|
+
pkg["devDependencies"] = devDeps;
|
|
59
|
+
const trailingNewline = raw.endsWith("\n") ? "\n" : "";
|
|
60
|
+
tree.overwrite("/package.json", JSON.stringify(pkg, null, 2) + trailingNewline);
|
|
61
|
+
context.addTask(new NodePackageInstallTask());
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
function applyEdits(source, edits) {
|
|
65
|
+
const sorted = [...edits].sort((a, b) => b.start - a.start);
|
|
66
|
+
let result = source;
|
|
67
|
+
for (const edit of sorted) result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
function getLineIndent(source, pos) {
|
|
71
|
+
let lineStart = pos;
|
|
72
|
+
while (lineStart > 0 && source[lineStart - 1] !== "\n") lineStart--;
|
|
73
|
+
let indent = "";
|
|
74
|
+
for (let i = lineStart; i < source.length; i++) {
|
|
75
|
+
const ch = source[i];
|
|
76
|
+
if (ch === " " || ch === " ") indent += ch;
|
|
77
|
+
else break;
|
|
78
|
+
}
|
|
79
|
+
return indent;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Tries to lift `vite: {...}` and `nitro: {...}` properties off the
|
|
83
|
+
* single `analog(...)` call into companion `angular(...)` / `nitro(...)`
|
|
84
|
+
* calls. Returns the rewritten source on success, or null if the file
|
|
85
|
+
* doesn't match the supported pattern (we then fall back to logging
|
|
86
|
+
* instructions rather than risking a corrupted file).
|
|
87
|
+
*
|
|
88
|
+
* Supported pattern: exactly one `analog(...)` call whose argument is
|
|
89
|
+
* an object literal. Properties named `vite` and `nitro` are recognized;
|
|
90
|
+
* everything else stays on `analog`.
|
|
91
|
+
*/
|
|
92
|
+
function tryTransformViteConfig(filePath, source) {
|
|
93
|
+
let sourceFile;
|
|
94
|
+
try {
|
|
95
|
+
sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
let analogImportEnd = -1;
|
|
100
|
+
let angularImported = false;
|
|
101
|
+
let nitroImported = false;
|
|
102
|
+
const analogCalls = [];
|
|
103
|
+
function visit(node) {
|
|
104
|
+
if (ts.isImportDeclaration(node)) {
|
|
105
|
+
const ml = node.moduleSpecifier;
|
|
106
|
+
if (ts.isStringLiteral(ml)) {
|
|
107
|
+
if (ml.text === "@analogjs/platform") analogImportEnd = node.end;
|
|
108
|
+
else if (ml.text === "@analogjs/vite-plugin-angular") angularImported = true;
|
|
109
|
+
else if (ml.text === "@analogjs/vite-plugin-nitro" || ml.text === "nitro/vite") nitroImported = true;
|
|
110
|
+
}
|
|
111
|
+
} else if (ts.isCallExpression(node)) {
|
|
112
|
+
if (ts.isIdentifier(node.expression) && node.expression.text === "analog") analogCalls.push(node);
|
|
113
|
+
}
|
|
114
|
+
ts.forEachChild(node, visit);
|
|
115
|
+
}
|
|
116
|
+
visit(sourceFile);
|
|
117
|
+
if (analogImportEnd === -1) return null;
|
|
118
|
+
if (analogCalls.length !== 1) return null;
|
|
119
|
+
const analogCall = analogCalls[0];
|
|
120
|
+
const callStart = analogCall.getStart(sourceFile);
|
|
121
|
+
const callEnd = analogCall.getEnd();
|
|
122
|
+
let viteValueText = null;
|
|
123
|
+
let nitroValueText = null;
|
|
124
|
+
let remainingPropsText = null;
|
|
125
|
+
const arg = analogCall.arguments[0];
|
|
126
|
+
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
127
|
+
const remaining = [];
|
|
128
|
+
for (const prop of arg.properties) if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && (prop.name.text === "vite" || prop.name.text === "nitro")) {
|
|
129
|
+
const value = prop.initializer;
|
|
130
|
+
const text = source.slice(value.getStart(sourceFile), value.getEnd());
|
|
131
|
+
if (prop.name.text === "vite") viteValueText = text;
|
|
132
|
+
else nitroValueText = text;
|
|
133
|
+
} else remaining.push(prop);
|
|
134
|
+
if (remaining.length > 0) {
|
|
135
|
+
const propTexts = remaining.map((p) => source.slice(p.getStart(sourceFile), p.getEnd()));
|
|
136
|
+
const indent = getLineIndent(source, arg.getStart(sourceFile));
|
|
137
|
+
const propIndent = indent + " ";
|
|
138
|
+
remainingPropsText = `{\n${propTexts.map((t) => `${propIndent}${t}`).join(",\n")},\n${indent}}`;
|
|
139
|
+
}
|
|
140
|
+
} else if (arg !== void 0) return null;
|
|
141
|
+
const indent = getLineIndent(source, callStart);
|
|
142
|
+
const parts = [remainingPropsText ? `analog(${remainingPropsText})` : `analog()`];
|
|
143
|
+
if (viteValueText !== null) parts.push(`angular(${viteValueText})`);
|
|
144
|
+
else parts.push("angular()");
|
|
145
|
+
if (nitroValueText !== null) parts.push(`nitro(${nitroValueText})`);
|
|
146
|
+
else parts.push("nitro()");
|
|
147
|
+
const edits = [{
|
|
148
|
+
start: callStart,
|
|
149
|
+
end: callEnd,
|
|
150
|
+
text: parts.join(`,\n${indent}`)
|
|
151
|
+
}];
|
|
152
|
+
const importsToAdd = [];
|
|
153
|
+
if (!angularImported) importsToAdd.push(`import angular from '@analogjs/vite-plugin-angular';`);
|
|
154
|
+
if (!nitroImported) importsToAdd.push(`import nitro from '@analogjs/vite-plugin-nitro';`);
|
|
155
|
+
if (importsToAdd.length > 0) edits.push({
|
|
156
|
+
start: analogImportEnd,
|
|
157
|
+
end: analogImportEnd,
|
|
158
|
+
text: `\n${importsToAdd.join("\n")}`
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
source: applyEdits(source, edits),
|
|
162
|
+
movedVite: viteValueText !== null,
|
|
163
|
+
movedNitro: nitroValueText !== null
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function migrateToSeparatedPlugins() {
|
|
167
|
+
return (tree, context) => {
|
|
168
|
+
const filesUsingLegacyShape = [];
|
|
169
|
+
const rewrittenFiles = [];
|
|
170
|
+
const unhandledFiles = [];
|
|
171
|
+
tree.visit((filePath) => {
|
|
172
|
+
if (filePath.includes("/node_modules/")) return;
|
|
173
|
+
if (!isViteConfig(filePath)) return;
|
|
174
|
+
const content = tree.read(filePath);
|
|
175
|
+
if (!content) return;
|
|
176
|
+
const source = content.toString("utf-8");
|
|
177
|
+
if (!usesLegacyPluginShape(source)) return;
|
|
178
|
+
filesUsingLegacyShape.push(filePath);
|
|
179
|
+
const transformed = tryTransformViteConfig(filePath, source);
|
|
180
|
+
if (transformed) {
|
|
181
|
+
tree.overwrite(filePath, transformed.source);
|
|
182
|
+
rewrittenFiles.push(filePath);
|
|
183
|
+
} else unhandledFiles.push(filePath);
|
|
184
|
+
});
|
|
185
|
+
if (filesUsingLegacyShape.length === 0) return tree;
|
|
186
|
+
if (rewrittenFiles.length > 0) {
|
|
187
|
+
context.logger.info(`Rewrote ${rewrittenFiles.length} vite.config file(s) to the separated \`analog() + angular() + nitro()\` shape:`);
|
|
188
|
+
for (const file of rewrittenFiles) context.logger.info(` - ${file}`);
|
|
189
|
+
context.logger.info(`Review the result — only \`vite\` and \`nitro\` were moved automatically. Other angular-passthrough options (\`liveReload\`, \`fastCompile\`, \`fileReplacements\`, etc.) still need to be relocated by hand.\nSee ${MIGRATION_DOC_URL}`);
|
|
190
|
+
}
|
|
191
|
+
if (unhandledFiles.length > 0) {
|
|
192
|
+
context.logger.info(`Could not safely rewrite ${unhandledFiles.length} vite.config file(s); migrate them by hand:`);
|
|
193
|
+
for (const file of unhandledFiles) context.logger.info(` - ${file}`);
|
|
194
|
+
context.logger.info(`Split \`analog()\` into \`analog() + angular() + nitro()\` and move each option to its owning plugin.\nSee ${MIGRATION_DOC_URL}`);
|
|
195
|
+
}
|
|
196
|
+
addDependencies(tree, context);
|
|
197
|
+
return tree;
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
//#endregion
|
|
201
|
+
export { migrateToSeparatedPlugins as default };
|
|
202
|
+
|
|
203
|
+
//# sourceMappingURL=migrate-to-separated-plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-to-separated-plugins.js","names":[],"sources":["../../../migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.ts"],"sourcesContent":["import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';\n// The explicit file path resolves when this runs as native ESM.\nimport { NodePackageInstallTask } from '@angular-devkit/schematics/tasks/index.js';\nimport * as ts from 'typescript';\n\nconst ANALOG_PLATFORM_IMPORT = `from '@analogjs/platform'`;\nconst ANGULAR_PLUGIN_IMPORT = `from '@analogjs/vite-plugin-angular'`;\nconst NITRO_IMPORTS = [\n `from '@analogjs/vite-plugin-nitro'`,\n `from 'nitro/vite'`,\n];\nconst ANGULAR_PLUGIN_PKG = '@analogjs/vite-plugin-angular';\nconst NITRO_PLUGIN_PKG = '@analogjs/vite-plugin-nitro';\nconst MIGRATION_DOC_URL =\n 'https://analogjs.org/docs/guides/migrating-v2-to-v3#analog-angular-and-nitro-are-now-separate-plugins';\n\nconst VITE_CONFIG_EXTENSIONS = ['.ts', '.mts', '.js', '.mjs'];\n\nfunction isViteConfig(filePath: string): boolean {\n const file = filePath.slice(filePath.lastIndexOf('/') + 1);\n if (!file.startsWith('vite.config.')) {\n return false;\n }\n return VITE_CONFIG_EXTENSIONS.some((ext) => file.endsWith(ext));\n}\n\nfunction usesLegacyPluginShape(source: string): boolean {\n if (!source.includes(ANALOG_PLATFORM_IMPORT)) {\n return false;\n }\n if (\n source.includes(ANGULAR_PLUGIN_IMPORT) &&\n NITRO_IMPORTS.some((nitroImport) => source.includes(nitroImport))\n ) {\n return false;\n }\n return /\\banalog\\s*\\(/.test(source);\n}\n\nfunction readPackageJson(\n tree: Tree,\n): { raw: string; pkg: Record<string, unknown> } | null {\n const content = tree.read('/package.json');\n if (!content) return null;\n const raw = content.toString('utf-8');\n try {\n return { raw, pkg: JSON.parse(raw) };\n } catch {\n return null;\n }\n}\n\nfunction getDepVersion(\n pkg: Record<string, unknown>,\n name: string,\n): string | undefined {\n const dev =\n (pkg['devDependencies'] as Record<string, string> | undefined) ?? {};\n const reg = (pkg['dependencies'] as Record<string, string> | undefined) ?? {};\n return dev[name] ?? reg[name];\n}\n\nfunction addDependencies(tree: Tree, context: SchematicContext): boolean {\n const info = readPackageJson(tree);\n if (!info) return false;\n\n const { pkg, raw } = info;\n const devDeps = {\n ...((pkg['devDependencies'] as Record<string, string> | undefined) ?? {}),\n };\n let changed = false;\n\n // Match the @analogjs/platform pin so the plugins stay aligned with the\n // rest of the Analog packages already in this workspace.\n const platformVersion = getDepVersion(pkg, '@analogjs/platform') ?? '*';\n const missingPlugins = [ANGULAR_PLUGIN_PKG, NITRO_PLUGIN_PKG].filter(\n (name) =>\n !getDepVersion(pkg, name) &&\n // Apps already on Nitro v3 keep `nitro()` from `nitro/vite`.\n !(name === NITRO_PLUGIN_PKG && getDepVersion(pkg, 'nitro')),\n );\n for (const name of missingPlugins) {\n devDeps[name] = platformVersion;\n changed = true;\n context.logger.info(\n `Added '${name}': '${platformVersion}' to devDependencies.`,\n );\n }\n\n if (!changed) return false;\n\n pkg['devDependencies'] = devDeps;\n const trailingNewline = raw.endsWith('\\n') ? '\\n' : '';\n tree.overwrite(\n '/package.json',\n JSON.stringify(pkg, null, 2) + trailingNewline,\n );\n context.addTask(new NodePackageInstallTask());\n return true;\n}\n\ninterface TransformResult {\n source: string;\n movedVite: boolean;\n movedNitro: boolean;\n}\n\ninterface Edit {\n start: number;\n end: number;\n text: string;\n}\n\nfunction applyEdits(source: string, edits: Edit[]): string {\n // Apply right-to-left so earlier offsets stay valid.\n const sorted = [...edits].sort((a, b) => b.start - a.start);\n let result = source;\n for (const edit of sorted) {\n result = result.slice(0, edit.start) + edit.text + result.slice(edit.end);\n }\n return result;\n}\n\nfunction getLineIndent(source: string, pos: number): string {\n let lineStart = pos;\n while (lineStart > 0 && source[lineStart - 1] !== '\\n') {\n lineStart--;\n }\n let indent = '';\n for (let i = lineStart; i < source.length; i++) {\n const ch = source[i];\n if (ch === ' ' || ch === '\\t') indent += ch;\n else break;\n }\n return indent;\n}\n\n/**\n * Tries to lift `vite: {...}` and `nitro: {...}` properties off the\n * single `analog(...)` call into companion `angular(...)` / `nitro(...)`\n * calls. Returns the rewritten source on success, or null if the file\n * doesn't match the supported pattern (we then fall back to logging\n * instructions rather than risking a corrupted file).\n *\n * Supported pattern: exactly one `analog(...)` call whose argument is\n * an object literal. Properties named `vite` and `nitro` are recognized;\n * everything else stays on `analog`.\n */\nfunction tryTransformViteConfig(\n filePath: string,\n source: string,\n): TransformResult | null {\n let sourceFile: ts.SourceFile;\n try {\n sourceFile = ts.createSourceFile(\n filePath,\n source,\n ts.ScriptTarget.Latest,\n true,\n ts.ScriptKind.TS,\n );\n } catch {\n return null;\n }\n\n let analogImportEnd = -1;\n let angularImported = false;\n let nitroImported = false;\n const analogCalls: ts.CallExpression[] = [];\n\n function visit(node: ts.Node): void {\n if (ts.isImportDeclaration(node)) {\n const ml = node.moduleSpecifier;\n if (ts.isStringLiteral(ml)) {\n if (ml.text === '@analogjs/platform') {\n analogImportEnd = node.end;\n } else if (ml.text === '@analogjs/vite-plugin-angular') {\n angularImported = true;\n } else if (\n ml.text === '@analogjs/vite-plugin-nitro' ||\n ml.text === 'nitro/vite'\n ) {\n nitroImported = true;\n }\n }\n } else if (ts.isCallExpression(node)) {\n if (\n ts.isIdentifier(node.expression) &&\n node.expression.text === 'analog'\n ) {\n analogCalls.push(node);\n }\n }\n ts.forEachChild(node, visit);\n }\n visit(sourceFile);\n\n if (analogImportEnd === -1) return null;\n if (analogCalls.length !== 1) return null;\n\n const analogCall = analogCalls[0];\n const callStart = analogCall.getStart(sourceFile);\n const callEnd = analogCall.getEnd();\n\n let viteValueText: string | null = null;\n let nitroValueText: string | null = null;\n let remainingPropsText: string | null = null;\n\n const arg = analogCall.arguments[0];\n if (arg && ts.isObjectLiteralExpression(arg)) {\n const remaining: ts.ObjectLiteralElementLike[] = [];\n for (const prop of arg.properties) {\n if (\n ts.isPropertyAssignment(prop) &&\n ts.isIdentifier(prop.name) &&\n (prop.name.text === 'vite' || prop.name.text === 'nitro')\n ) {\n const value = prop.initializer;\n const text = source.slice(value.getStart(sourceFile), value.getEnd());\n if (prop.name.text === 'vite') viteValueText = text;\n else nitroValueText = text;\n } else {\n remaining.push(prop);\n }\n }\n\n if (remaining.length > 0) {\n // Reconstruct the analog object literal from the remaining props,\n // preserving their original source text (comments, spacing).\n const propTexts = remaining.map((p) =>\n source.slice(p.getStart(sourceFile), p.getEnd()),\n );\n const objStart = arg.getStart(sourceFile);\n const indent = getLineIndent(source, objStart);\n const propIndent = indent + ' ';\n remainingPropsText = `{\\n${propTexts.map((t) => `${propIndent}${t}`).join(',\\n')},\\n${indent}}`;\n }\n } else if (arg !== undefined) {\n // analog(otherExpression) — can't statically split a variable or call\n // expression. Fall back to logging instructions.\n return null;\n }\n // analog() with no argument falls through to the rewrite below; we just\n // emit `analog(), angular(), nitro()` to scaffold the new plugin chain.\n\n const indent = getLineIndent(source, callStart);\n const newAnalogCall = remainingPropsText\n ? `analog(${remainingPropsText})`\n : `analog()`;\n const parts: string[] = [newAnalogCall];\n if (viteValueText !== null) parts.push(`angular(${viteValueText})`);\n else parts.push('angular()');\n if (nitroValueText !== null) parts.push(`nitro(${nitroValueText})`);\n else parts.push('nitro()');\n const replacement = parts.join(`,\\n${indent}`);\n\n const edits: Edit[] = [{ start: callStart, end: callEnd, text: replacement }];\n\n const importsToAdd: string[] = [];\n if (!angularImported) {\n importsToAdd.push(`import angular from '@analogjs/vite-plugin-angular';`);\n }\n if (!nitroImported) {\n importsToAdd.push(`import nitro from '@analogjs/vite-plugin-nitro';`);\n }\n if (importsToAdd.length > 0) {\n edits.push({\n start: analogImportEnd,\n end: analogImportEnd,\n text: `\\n${importsToAdd.join('\\n')}`,\n });\n }\n\n const rewritten = applyEdits(source, edits);\n\n return {\n source: rewritten,\n movedVite: viteValueText !== null,\n movedNitro: nitroValueText !== null,\n };\n}\n\nexport default function migrateToSeparatedPlugins(): Rule {\n return (tree: Tree, context: SchematicContext) => {\n const filesUsingLegacyShape: string[] = [];\n const rewrittenFiles: string[] = [];\n const unhandledFiles: string[] = [];\n\n tree.visit((filePath) => {\n if (filePath.includes('/node_modules/')) return;\n if (!isViteConfig(filePath)) return;\n\n const content = tree.read(filePath);\n if (!content) return;\n\n const source = content.toString('utf-8');\n if (!usesLegacyPluginShape(source)) return;\n\n filesUsingLegacyShape.push(filePath);\n\n const transformed = tryTransformViteConfig(filePath, source);\n if (transformed) {\n tree.overwrite(filePath, transformed.source);\n rewrittenFiles.push(filePath);\n } else {\n unhandledFiles.push(filePath);\n }\n });\n\n if (filesUsingLegacyShape.length === 0) {\n return tree;\n }\n\n if (rewrittenFiles.length > 0) {\n context.logger.info(\n `Rewrote ${rewrittenFiles.length} vite.config file(s) to the separated \\`analog() + angular() + nitro()\\` shape:`,\n );\n for (const file of rewrittenFiles) {\n context.logger.info(` - ${file}`);\n }\n context.logger.info(\n `Review the result — only \\`vite\\` and \\`nitro\\` were moved automatically. Other angular-passthrough options (\\`liveReload\\`, \\`fastCompile\\`, \\`fileReplacements\\`, etc.) still need to be relocated by hand.\\nSee ${MIGRATION_DOC_URL}`,\n );\n }\n\n if (unhandledFiles.length > 0) {\n context.logger.info(\n `Could not safely rewrite ${unhandledFiles.length} vite.config file(s); migrate them by hand:`,\n );\n for (const file of unhandledFiles) {\n context.logger.info(` - ${file}`);\n }\n context.logger.info(\n `Split \\`analog()\\` into \\`analog() + angular() + nitro()\\` and move each option to its owning plugin.\\nSee ${MIGRATION_DOC_URL}`,\n );\n }\n\n addDependencies(tree, context);\n\n return tree;\n };\n}\n"],"mappings":";;;AAKA,IAAM,yBAAyB;AAC/B,IAAM,wBAAwB;AAC9B,IAAM,gBAAgB,CACpB,sCACA,oBACD;AACD,IAAM,qBAAqB;AAC3B,IAAM,mBAAmB;AACzB,IAAM,oBACJ;AAEF,IAAM,yBAAyB;CAAC;CAAO;CAAQ;CAAO;CAAO;AAE7D,SAAS,aAAa,UAA2B;CAC/C,MAAM,OAAO,SAAS,MAAM,SAAS,YAAY,IAAI,GAAG,EAAE;AAC1D,KAAI,CAAC,KAAK,WAAW,eAAe,CAClC,QAAO;AAET,QAAO,uBAAuB,MAAM,QAAQ,KAAK,SAAS,IAAI,CAAC;;AAGjE,SAAS,sBAAsB,QAAyB;AACtD,KAAI,CAAC,OAAO,SAAS,uBAAuB,CAC1C,QAAO;AAET,KACE,OAAO,SAAS,sBAAsB,IACtC,cAAc,MAAM,gBAAgB,OAAO,SAAS,YAAY,CAAC,CAEjE,QAAO;AAET,QAAO,gBAAgB,KAAK,OAAO;;AAGrC,SAAS,gBACP,MACsD;CACtD,MAAM,UAAU,KAAK,KAAK,gBAAgB;AAC1C,KAAI,CAAC,QAAS,QAAO;CACrB,MAAM,MAAM,QAAQ,SAAS,QAAQ;AACrC,KAAI;AACF,SAAO;GAAE;GAAK,KAAK,KAAK,MAAM,IAAI;GAAE;SAC9B;AACN,SAAO;;;AAIX,SAAS,cACP,KACA,MACoB;CACpB,MAAM,MACH,IAAI,sBAA6D,EAAE;CACtE,MAAM,MAAO,IAAI,mBAA0D,EAAE;AAC7E,QAAO,IAAI,SAAS,IAAI;;AAG1B,SAAS,gBAAgB,MAAY,SAAoC;CACvE,MAAM,OAAO,gBAAgB,KAAK;AAClC,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,EAAE,KAAK,QAAQ;CACrB,MAAM,UAAU,EACd,GAAK,IAAI,sBAA6D,EAAE,EACzE;CACD,IAAI,UAAU;CAId,MAAM,kBAAkB,cAAc,KAAK,qBAAqB,IAAI;CACpE,MAAM,iBAAiB,CAAC,oBAAoB,iBAAiB,CAAC,QAC3D,SACC,CAAC,cAAc,KAAK,KAAK,IAEzB,EAAE,SAAS,oBAAoB,cAAc,KAAK,QAAQ,EAC7D;AACD,MAAK,MAAM,QAAQ,gBAAgB;AACjC,UAAQ,QAAQ;AAChB,YAAU;AACV,UAAQ,OAAO,KACb,UAAU,KAAK,MAAM,gBAAgB,uBACtC;;AAGH,KAAI,CAAC,QAAS,QAAO;AAErB,KAAI,qBAAqB;CACzB,MAAM,kBAAkB,IAAI,SAAS,KAAK,GAAG,OAAO;AACpD,MAAK,UACH,iBACA,KAAK,UAAU,KAAK,MAAM,EAAE,GAAG,gBAChC;AACD,SAAQ,QAAQ,IAAI,wBAAwB,CAAC;AAC7C,QAAO;;AAeT,SAAS,WAAW,QAAgB,OAAuB;CAEzD,MAAM,SAAS,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;CAC3D,IAAI,SAAS;AACb,MAAK,MAAM,QAAQ,OACjB,UAAS,OAAO,MAAM,GAAG,KAAK,MAAM,GAAG,KAAK,OAAO,OAAO,MAAM,KAAK,IAAI;AAE3E,QAAO;;AAGT,SAAS,cAAc,QAAgB,KAAqB;CAC1D,IAAI,YAAY;AAChB,QAAO,YAAY,KAAK,OAAO,YAAY,OAAO,KAChD;CAEF,IAAI,SAAS;AACb,MAAK,IAAI,IAAI,WAAW,IAAI,OAAO,QAAQ,KAAK;EAC9C,MAAM,KAAK,OAAO;AAClB,MAAI,OAAO,OAAO,OAAO,IAAM,WAAU;MACpC;;AAEP,QAAO;;;;;;;;;;;;;AAcT,SAAS,uBACP,UACA,QACwB;CACxB,IAAI;AACJ,KAAI;AACF,eAAa,GAAG,iBACd,UACA,QACA,GAAG,aAAa,QAChB,MACA,GAAG,WAAW,GACf;SACK;AACN,SAAO;;CAGT,IAAI,kBAAkB;CACtB,IAAI,kBAAkB;CACtB,IAAI,gBAAgB;CACpB,MAAM,cAAmC,EAAE;CAE3C,SAAS,MAAM,MAAqB;AAClC,MAAI,GAAG,oBAAoB,KAAK,EAAE;GAChC,MAAM,KAAK,KAAK;AAChB,OAAI,GAAG,gBAAgB,GAAG;QACpB,GAAG,SAAS,qBACd,mBAAkB,KAAK;aACd,GAAG,SAAS,gCACrB,mBAAkB;aAElB,GAAG,SAAS,iCACZ,GAAG,SAAS,aAEZ,iBAAgB;;aAGX,GAAG,iBAAiB,KAAK;OAEhC,GAAG,aAAa,KAAK,WAAW,IAChC,KAAK,WAAW,SAAS,SAEzB,aAAY,KAAK,KAAK;;AAG1B,KAAG,aAAa,MAAM,MAAM;;AAE9B,OAAM,WAAW;AAEjB,KAAI,oBAAoB,GAAI,QAAO;AACnC,KAAI,YAAY,WAAW,EAAG,QAAO;CAErC,MAAM,aAAa,YAAY;CAC/B,MAAM,YAAY,WAAW,SAAS,WAAW;CACjD,MAAM,UAAU,WAAW,QAAQ;CAEnC,IAAI,gBAA+B;CACnC,IAAI,iBAAgC;CACpC,IAAI,qBAAoC;CAExC,MAAM,MAAM,WAAW,UAAU;AACjC,KAAI,OAAO,GAAG,0BAA0B,IAAI,EAAE;EAC5C,MAAM,YAA2C,EAAE;AACnD,OAAK,MAAM,QAAQ,IAAI,WACrB,KACE,GAAG,qBAAqB,KAAK,IAC7B,GAAG,aAAa,KAAK,KAAK,KACzB,KAAK,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,UACjD;GACA,MAAM,QAAQ,KAAK;GACnB,MAAM,OAAO,OAAO,MAAM,MAAM,SAAS,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAI,KAAK,KAAK,SAAS,OAAQ,iBAAgB;OAC1C,kBAAiB;QAEtB,WAAU,KAAK,KAAK;AAIxB,MAAI,UAAU,SAAS,GAAG;GAGxB,MAAM,YAAY,UAAU,KAAK,MAC/B,OAAO,MAAM,EAAE,SAAS,WAAW,EAAE,EAAE,QAAQ,CAAC,CACjD;GAED,MAAM,SAAS,cAAc,QADZ,IAAI,SAAS,WAAW,CACK;GAC9C,MAAM,aAAa,SAAS;AAC5B,wBAAqB,MAAM,UAAU,KAAK,MAAM,GAAG,aAAa,IAAI,CAAC,KAAK,MAAM,CAAC,KAAK,OAAO;;YAEtF,QAAQ,KAAA,EAGjB,QAAO;CAKT,MAAM,SAAS,cAAc,QAAQ,UAAU;CAI/C,MAAM,QAAkB,CAHF,qBAClB,UAAU,mBAAmB,KAC7B,WACmC;AACvC,KAAI,kBAAkB,KAAM,OAAM,KAAK,WAAW,cAAc,GAAG;KAC9D,OAAM,KAAK,YAAY;AAC5B,KAAI,mBAAmB,KAAM,OAAM,KAAK,SAAS,eAAe,GAAG;KAC9D,OAAM,KAAK,UAAU;CAG1B,MAAM,QAAgB,CAAC;EAAE,OAAO;EAAW,KAAK;EAAS,MAFrC,MAAM,KAAK,MAAM,SAAS;EAE8B,CAAC;CAE7E,MAAM,eAAyB,EAAE;AACjC,KAAI,CAAC,gBACH,cAAa,KAAK,uDAAuD;AAE3E,KAAI,CAAC,cACH,cAAa,KAAK,mDAAmD;AAEvE,KAAI,aAAa,SAAS,EACxB,OAAM,KAAK;EACT,OAAO;EACP,KAAK;EACL,MAAM,KAAK,aAAa,KAAK,KAAK;EACnC,CAAC;AAKJ,QAAO;EACL,QAHgB,WAAW,QAAQ,MAAM;EAIzC,WAAW,kBAAkB;EAC7B,YAAY,mBAAmB;EAChC;;AAGH,SAAwB,4BAAkC;AACxD,SAAQ,MAAY,YAA8B;EAChD,MAAM,wBAAkC,EAAE;EAC1C,MAAM,iBAA2B,EAAE;EACnC,MAAM,iBAA2B,EAAE;AAEnC,OAAK,OAAO,aAAa;AACvB,OAAI,SAAS,SAAS,iBAAiB,CAAE;AACzC,OAAI,CAAC,aAAa,SAAS,CAAE;GAE7B,MAAM,UAAU,KAAK,KAAK,SAAS;AACnC,OAAI,CAAC,QAAS;GAEd,MAAM,SAAS,QAAQ,SAAS,QAAQ;AACxC,OAAI,CAAC,sBAAsB,OAAO,CAAE;AAEpC,yBAAsB,KAAK,SAAS;GAEpC,MAAM,cAAc,uBAAuB,UAAU,OAAO;AAC5D,OAAI,aAAa;AACf,SAAK,UAAU,UAAU,YAAY,OAAO;AAC5C,mBAAe,KAAK,SAAS;SAE7B,gBAAe,KAAK,SAAS;IAE/B;AAEF,MAAI,sBAAsB,WAAW,EACnC,QAAO;AAGT,MAAI,eAAe,SAAS,GAAG;AAC7B,WAAQ,OAAO,KACb,WAAW,eAAe,OAAO,iFAClC;AACD,QAAK,MAAM,QAAQ,eACjB,SAAQ,OAAO,KAAK,OAAO,OAAO;AAEpC,WAAQ,OAAO,KACb,sNAAsN,oBACvN;;AAGH,MAAI,eAAe,SAAS,GAAG;AAC7B,WAAQ,OAAO,KACb,4BAA4B,eAAe,OAAO,6CACnD;AACD,QAAK,MAAM,QAAQ,eACjB,SAAQ,OAAO,KAAK,OAAO,OAAO;AAEpC,WAAQ,OAAO,KACb,8GAA8G,oBAC/G;;AAGH,kBAAgB,MAAM,QAAQ;AAE9B,SAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analogjs/platform",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.93",
|
|
4
4
|
"description": "The fullstack meta-framework for Angular",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Brandon Roberts <robertsbt@gmail.com>",
|
|
@@ -31,12 +31,10 @@
|
|
|
31
31
|
"url": "https://github.com/sponsors/brandonroberts"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@analogjs/vite-plugin-angular": "3.0.0-alpha.
|
|
34
|
+
"@analogjs/vite-plugin-angular": "3.0.0-alpha.93",
|
|
35
35
|
"es-toolkit": "^1.45.1",
|
|
36
36
|
"front-matter": "^4.0.2",
|
|
37
|
-
"h3": "^2.0.1-rc.31",
|
|
38
37
|
"magic-string": "^0.30.21",
|
|
39
|
-
"nitro": "3.0.260903-beta",
|
|
40
38
|
"obug": "^2.1.1",
|
|
41
39
|
"ofetch": "2.0.0-alpha.3",
|
|
42
40
|
"oxc-parser": "^0.124.0",
|
|
@@ -46,7 +44,9 @@
|
|
|
46
44
|
"xmlbuilder2": "^4.0.3"
|
|
47
45
|
},
|
|
48
46
|
"devDependencies": {
|
|
49
|
-
"@babel/core": "^8.0.0"
|
|
47
|
+
"@babel/core": "^8.0.0",
|
|
48
|
+
"h3": "^2.0.1-rc.31",
|
|
49
|
+
"nitro": "3.0.260903-beta"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"@nx/angular": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0 || ^23.0.0 || ^23",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"marked-highlight": "^2.2.3",
|
|
58
58
|
"marked-mangle": "^1.1.12",
|
|
59
59
|
"marked-shiki": "^1.2.1",
|
|
60
|
+
"nitro": "3.0.260903-beta",
|
|
60
61
|
"shiki": "^1.29.2 || ^4.0.2",
|
|
61
62
|
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
62
63
|
},
|
|
@@ -70,16 +71,19 @@
|
|
|
70
71
|
"@nx/vite": {
|
|
71
72
|
"optional": true
|
|
72
73
|
},
|
|
73
|
-
"
|
|
74
|
+
"marked-highlight": {
|
|
74
75
|
"optional": true
|
|
75
76
|
},
|
|
76
77
|
"marked-shiki": {
|
|
77
78
|
"optional": true
|
|
78
79
|
},
|
|
80
|
+
"nitro": {
|
|
81
|
+
"optional": true
|
|
82
|
+
},
|
|
79
83
|
"prismjs": {
|
|
80
84
|
"optional": true
|
|
81
85
|
},
|
|
82
|
-
"
|
|
86
|
+
"shiki": {
|
|
83
87
|
"optional": true
|
|
84
88
|
}
|
|
85
89
|
},
|
|
@@ -8,6 +8,7 @@ function clearClientPageEndpointsPlugin() {
|
|
|
8
8
|
let isBuild = true;
|
|
9
9
|
return {
|
|
10
10
|
name: "analogjs-platform-clear-client-page-endpoint",
|
|
11
|
+
enforce: "post",
|
|
11
12
|
config() {
|
|
12
13
|
return { build: { rollupOptions: { onwarn(warning) {
|
|
13
14
|
if (warning.message.includes("empty chunk") && warning.message.endsWith(".server")) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clear-client-page-endpoint.js","names":[],"sources":["../../../src/lib/clear-client-page-endpoint.ts"],"sourcesContent":["import { Plugin, normalizePath } from 'vite';\nimport { injectServerFnIds } from './inject-server-fn-ids.js';\nimport { serverFnFileId } from './server-fn-id.js';\n\nimport { scrubServerFnModule } from './server-fn-client-transform.js';\n\nexport function clearClientPageEndpointsPlugin(): Plugin {\n let projectRoot = process.cwd();\n let isBuild = true;\n\n return {\n name: 'analogjs-platform-clear-client-page-endpoint',\n config() {\n return {\n build: {\n rollupOptions: {\n onwarn(warning) {\n if (\n warning.message.includes('empty chunk') &&\n warning.message.endsWith('.server')\n ) {\n return;\n }\n },\n },\n },\n };\n },\n configResolved(config) {\n projectRoot = config.root;\n isBuild = config.command === 'build';\n },\n transform(code, id, options) {\n if (!id.endsWith('.server.ts')) {\n return;\n }\n\n // Server-function ids are derived from the project-root-relative path so\n // the client proxy and the server registration always resolve to the same\n // opaque, collision-free route.\n const fileId = serverFnFileId(id, projectRoot);\n\n if (options?.ssr) {\n // SSR build keeps the real handlers but stamps the derived id into each\n // serverFn config so it registers under the route the client calls.\n const injected = injectServerFnIds(code, fileId);\n return injected ? { code: injected.code, map: null } : undefined;\n }\n\n // Client build: a `.server.ts` defining server functions is rewritten to\n // client-safe proxies (the `{ id, url, method }` refs the browser\n // dispatches through); handlers and server imports are dropped so they\n // tree-shake away.\n const scrubbed = scrubServerFnModule(code, fileId);\n if (scrubbed) {\n // An empty mapping, not `null`: a null map lets the original module —\n // handlers and all — survive in `sourcesContent` further down the\n // pipeline, which would ship the server code to the browser after the\n // scrub went to the trouble of removing it.\n return { code: scrubbed.code, map: { mappings: '' } };\n }\n\n // Page load/action endpoints carry no client-consumable exports. Only the\n // client build empties them; the dev server never pulls them into the\n // browser graph, and emptying them there would break the SSR request.\n if (isBuild && id.includes(normalizePath('src/app/pages'))) {\n return {\n code: 'export default undefined;',\n map: null,\n };\n }\n\n return;\n },\n };\n}\n"],"mappings":";;;;;AAMA,SAAgB,iCAAyC;CACvD,IAAI,cAAc,QAAQ,KAAK;CAC/B,IAAI,UAAU;AAEd,QAAO;EACL,MAAM;
|
|
1
|
+
{"version":3,"file":"clear-client-page-endpoint.js","names":[],"sources":["../../../src/lib/clear-client-page-endpoint.ts"],"sourcesContent":["import { Plugin, normalizePath } from 'vite';\nimport { injectServerFnIds } from './inject-server-fn-ids.js';\nimport { serverFnFileId } from './server-fn-id.js';\n\nimport { scrubServerFnModule } from './server-fn-client-transform.js';\n\nexport function clearClientPageEndpointsPlugin(): Plugin {\n let projectRoot = process.cwd();\n let isBuild = true;\n\n return {\n name: 'analogjs-platform-clear-client-page-endpoint',\n // After Angular compilation, which re-emits `.server.ts` files from its own\n // program and would otherwise drop this transform's output.\n enforce: 'post',\n config() {\n return {\n build: {\n rollupOptions: {\n onwarn(warning) {\n if (\n warning.message.includes('empty chunk') &&\n warning.message.endsWith('.server')\n ) {\n return;\n }\n },\n },\n },\n };\n },\n configResolved(config) {\n projectRoot = config.root;\n isBuild = config.command === 'build';\n },\n transform(code, id, options) {\n if (!id.endsWith('.server.ts')) {\n return;\n }\n\n // Server-function ids are derived from the project-root-relative path so\n // the client proxy and the server registration always resolve to the same\n // opaque, collision-free route.\n const fileId = serverFnFileId(id, projectRoot);\n\n if (options?.ssr) {\n // SSR build keeps the real handlers but stamps the derived id into each\n // serverFn config so it registers under the route the client calls.\n const injected = injectServerFnIds(code, fileId);\n return injected ? { code: injected.code, map: null } : undefined;\n }\n\n // Client build: a `.server.ts` defining server functions is rewritten to\n // client-safe proxies (the `{ id, url, method }` refs the browser\n // dispatches through); handlers and server imports are dropped so they\n // tree-shake away.\n const scrubbed = scrubServerFnModule(code, fileId);\n if (scrubbed) {\n // An empty mapping, not `null`: a null map lets the original module —\n // handlers and all — survive in `sourcesContent` further down the\n // pipeline, which would ship the server code to the browser after the\n // scrub went to the trouble of removing it.\n return { code: scrubbed.code, map: { mappings: '' } };\n }\n\n // Page load/action endpoints carry no client-consumable exports. Only the\n // client build empties them; the dev server never pulls them into the\n // browser graph, and emptying them there would break the SSR request.\n if (isBuild && id.includes(normalizePath('src/app/pages'))) {\n return {\n code: 'export default undefined;',\n map: null,\n };\n }\n\n return;\n },\n };\n}\n"],"mappings":";;;;;AAMA,SAAgB,iCAAyC;CACvD,IAAI,cAAc,QAAQ,KAAK;CAC/B,IAAI,UAAU;AAEd,QAAO;EACL,MAAM;EAGN,SAAS;EACT,SAAS;AACP,UAAO,EACL,OAAO,EACL,eAAe,EACb,OAAO,SAAS;AACd,QACE,QAAQ,QAAQ,SAAS,cAAc,IACvC,QAAQ,QAAQ,SAAS,UAAU,CAEnC;MAGL,EACF,EACF;;EAEH,eAAe,QAAQ;AACrB,iBAAc,OAAO;AACrB,aAAU,OAAO,YAAY;;EAE/B,UAAU,MAAM,IAAI,SAAS;AAC3B,OAAI,CAAC,GAAG,SAAS,aAAa,CAC5B;GAMF,MAAM,SAAS,eAAe,IAAI,YAAY;AAE9C,OAAI,SAAS,KAAK;IAGhB,MAAM,WAAW,kBAAkB,MAAM,OAAO;AAChD,WAAO,WAAW;KAAE,MAAM,SAAS;KAAM,KAAK;KAAM,GAAG,KAAA;;GAOzD,MAAM,WAAW,oBAAoB,MAAM,OAAO;AAClD,OAAI,SAKF,QAAO;IAAE,MAAM,SAAS;IAAM,KAAK,EAAE,UAAU,IAAI;IAAE;AAMvD,OAAI,WAAW,GAAG,SAAS,cAAc,gBAAgB,CAAC,CACxD,QAAO;IACL,MAAM;IACN,KAAK;IACN;;EAKN"}
|
package/src/lib/deps-plugin.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { debugPlatform } from "./utils/debug.js";
|
|
2
|
-
import { getJsTransformConfigKey } from "./utils/rolldown.js";
|
|
2
|
+
import { getJsTransformConfigKey, isRolldown } from "./utils/rolldown.js";
|
|
3
|
+
import { angularLinkerPlugin } from "./nitro/angular-linker-plugin.js";
|
|
3
4
|
import { VERSION } from "@angular/compiler-cli";
|
|
4
5
|
import { crawlFrameworkPkgs } from "vitefu";
|
|
5
6
|
//#region packages/platform/src/lib/deps-plugin.ts
|
|
7
|
+
var ANGULAR_LINKED_SSR_DEPS = [
|
|
8
|
+
"@angular/compiler",
|
|
9
|
+
"@angular/core",
|
|
10
|
+
"@angular/platform-browser",
|
|
11
|
+
"@angular/platform-server"
|
|
12
|
+
];
|
|
6
13
|
function depsPlugin(options) {
|
|
7
14
|
const workspaceRoot = options?.workspaceRoot ?? process.env["NX_WORKSPACE_ROOT"] ?? process.cwd();
|
|
8
15
|
return [{
|
|
@@ -26,11 +33,15 @@ function depsPlugin(options) {
|
|
|
26
33
|
"@taiga-ui/**",
|
|
27
34
|
"@tanstack/angular-query-experimental"
|
|
28
35
|
],
|
|
29
|
-
optimizeDeps: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
optimizeDeps: {
|
|
37
|
+
include: [
|
|
38
|
+
...isRolldown() ? ANGULAR_LINKED_SSR_DEPS : [],
|
|
39
|
+
"@angular/common",
|
|
40
|
+
"@angular/common/http",
|
|
41
|
+
...Number(VERSION.major) > 15 ? ["@angular/core/rxjs-interop"] : []
|
|
42
|
+
],
|
|
43
|
+
...isRolldown() ? { rolldownOptions: { plugins: [angularLinkerPlugin()] } } : {}
|
|
44
|
+
}
|
|
34
45
|
},
|
|
35
46
|
optimizeDeps: {
|
|
36
47
|
include: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps-plugin.js","names":[],"sources":["../../../src/lib/deps-plugin.ts"],"sourcesContent":["import { VERSION } from '@angular/compiler-cli';\nimport type { Plugin } from 'vite';\nimport { crawlFrameworkPkgs } from 'vitefu';\n\nimport { Options } from './options.js';\nimport { debugPlatform } from './utils/debug.js';\nimport { getJsTransformConfigKey } from './utils/rolldown.js';\n\nexport function depsPlugin(options?: Options): Plugin[] {\n const workspaceRoot =\n options?.workspaceRoot ?? process.env['NX_WORKSPACE_ROOT'] ?? process.cwd();\n\n return [\n {\n name: 'analogjs-deps-plugin',\n config() {\n // Skip Vite's built-in ts/js transform so `@analogjs/vite-plugin-angular`\n // (when the user includes it) owns Angular file compilation. Users who\n // run an alternative compiler or compile through Angular's own\n // compilation API can override this in their own Vite config.\n const transformConfig = { exclude: ['**/*.ts', '**/*.js'] };\n debugPlatform('deps transform config', {\n jsTransformKey: getJsTransformConfigKey(),\n transformExcluded: true,\n });\n\n return {\n [getJsTransformConfigKey()]: transformConfig,\n ssr: {\n noExternal: [\n '@analogjs/**',\n 'es-toolkit',\n 'firebase/**',\n 'firebase-admin/**',\n 'rxfire',\n '@ng-web-apis/**',\n '@taiga-ui/**',\n '@tanstack/angular-query-experimental',\n ],\n // The server pre-bundle is resolved separately from the client\n // one, so a secondary entry point left out of it loads its own\n // copy of `@angular/core`. `inject()` then runs against a runtime\n // with no active injection context and SSR fails with NG0203.\n optimizeDeps: {\n include: [\n '@angular/common',\n '@angular/common/http',\n ...(Number(VERSION.major) > 15\n ? ['@angular/core/rxjs-interop']\n : []),\n ],\n },\n },\n optimizeDeps: {\n include: [\n '@angular/common',\n '@angular/common/http',\n ...(Number(VERSION.major) > 15\n ? ['@angular/core/rxjs-interop']\n : []),\n 'front-matter',\n ],\n exclude: [\n '@angular/platform-server',\n '@analogjs/content',\n '@analogjs/router',\n '@nx/angular',\n '@nx/vite',\n '@nx/devkit',\n '@nx/js',\n '@nx/devkit',\n '@nx/cypress',\n '@nx/jest',\n '@nx/js',\n '@nx/eslint',\n '@nx/webpack',\n '@nx/web',\n '@nx/workspace',\n '@nx/eslint',\n '@nx/module-federation',\n '@nx/rspack',\n 'webpack',\n 'fsevents',\n 'nx',\n ],\n },\n };\n },\n },\n {\n name: 'analogjs-auto-discover-deps',\n async config(config, { command }) {\n const pkgConfig = await crawlFrameworkPkgs({\n root: workspaceRoot,\n isBuild: command === 'build',\n viteUserConfig: config,\n isSemiFrameworkPkgByJson(pkgJson) {\n return pkgJson['module'] && pkgJson['module'].includes('fesm');\n },\n });\n return pkgConfig;\n },\n },\n ];\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"deps-plugin.js","names":[],"sources":["../../../src/lib/deps-plugin.ts"],"sourcesContent":["import { VERSION } from '@angular/compiler-cli';\nimport type { Plugin } from 'vite';\nimport { crawlFrameworkPkgs } from 'vitefu';\n\nimport { angularLinkerPlugin } from './nitro/angular-linker-plugin.js';\nimport { Options } from './options.js';\nimport { debugPlatform } from './utils/debug.js';\nimport { getJsTransformConfigKey, isRolldown } from './utils/rolldown.js';\n\nconst ANGULAR_LINKED_SSR_DEPS = [\n '@angular/compiler',\n '@angular/core',\n '@angular/platform-browser',\n '@angular/platform-server',\n];\n\nexport function depsPlugin(options?: Options): Plugin[] {\n const workspaceRoot =\n options?.workspaceRoot ?? process.env['NX_WORKSPACE_ROOT'] ?? process.cwd();\n\n return [\n {\n name: 'analogjs-deps-plugin',\n config() {\n // Skip Vite's built-in ts/js transform so `@analogjs/vite-plugin-angular`\n // (when the user includes it) owns Angular file compilation. Users who\n // run an alternative compiler or compile through Angular's own\n // compilation API can override this in their own Vite config.\n const transformConfig = { exclude: ['**/*.ts', '**/*.js'] };\n debugPlatform('deps transform config', {\n jsTransformKey: getJsTransformConfigKey(),\n transformExcluded: true,\n });\n\n return {\n [getJsTransformConfigKey()]: transformConfig,\n ssr: {\n noExternal: [\n '@analogjs/**',\n 'es-toolkit',\n 'firebase/**',\n 'firebase-admin/**',\n 'rxfire',\n '@ng-web-apis/**',\n '@taiga-ui/**',\n '@tanstack/angular-query-experimental',\n ],\n // The server pre-bundle is resolved separately from the client\n // one, so a secondary entry point left out of it loads its own\n // copy of `@angular/core`. `inject()` then runs against a runtime\n // with no active injection context and SSR fails with NG0203.\n // With Rolldown, the rest of Angular is pre-bundled too and the\n // partial-compilation packages are linked, so the server needs no JIT.\n optimizeDeps: {\n include: [\n ...(isRolldown() ? ANGULAR_LINKED_SSR_DEPS : []),\n '@angular/common',\n '@angular/common/http',\n ...(Number(VERSION.major) > 15\n ? ['@angular/core/rxjs-interop']\n : []),\n ],\n ...(isRolldown()\n ? { rolldownOptions: { plugins: [angularLinkerPlugin()] } }\n : {}),\n },\n },\n optimizeDeps: {\n include: [\n '@angular/common',\n '@angular/common/http',\n ...(Number(VERSION.major) > 15\n ? ['@angular/core/rxjs-interop']\n : []),\n 'front-matter',\n ],\n exclude: [\n '@angular/platform-server',\n '@analogjs/content',\n '@analogjs/router',\n '@nx/angular',\n '@nx/vite',\n '@nx/devkit',\n '@nx/js',\n '@nx/devkit',\n '@nx/cypress',\n '@nx/jest',\n '@nx/js',\n '@nx/eslint',\n '@nx/webpack',\n '@nx/web',\n '@nx/workspace',\n '@nx/eslint',\n '@nx/module-federation',\n '@nx/rspack',\n 'webpack',\n 'fsevents',\n 'nx',\n ],\n },\n };\n },\n },\n {\n name: 'analogjs-auto-discover-deps',\n async config(config, { command }) {\n const pkgConfig = await crawlFrameworkPkgs({\n root: workspaceRoot,\n isBuild: command === 'build',\n viteUserConfig: config,\n isSemiFrameworkPkgByJson(pkgJson) {\n return pkgJson['module'] && pkgJson['module'].includes('fesm');\n },\n });\n return pkgConfig;\n },\n },\n ];\n}\n"],"mappings":";;;;;;AASA,IAAM,0BAA0B;CAC9B;CACA;CACA;CACA;CACD;AAED,SAAgB,WAAW,SAA6B;CACtD,MAAM,gBACJ,SAAS,iBAAiB,QAAQ,IAAI,wBAAwB,QAAQ,KAAK;AAE7E,QAAO,CACL;EACE,MAAM;EACN,SAAS;GAKP,MAAM,kBAAkB,EAAE,SAAS,CAAC,WAAW,UAAU,EAAE;AAC3D,iBAAc,yBAAyB;IACrC,gBAAgB,yBAAyB;IACzC,mBAAmB;IACpB,CAAC;AAEF,UAAO;KACJ,yBAAyB,GAAG;IAC7B,KAAK;KACH,YAAY;MACV;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACD;KAOD,cAAc;MACZ,SAAS;OACP,GAAI,YAAY,GAAG,0BAA0B,EAAE;OAC/C;OACA;OACA,GAAI,OAAO,QAAQ,MAAM,GAAG,KACxB,CAAC,6BAA6B,GAC9B,EAAE;OACP;MACD,GAAI,YAAY,GACZ,EAAE,iBAAiB,EAAE,SAAS,CAAC,qBAAqB,CAAC,EAAE,EAAE,GACzD,EAAE;MACP;KACF;IACD,cAAc;KACZ,SAAS;MACP;MACA;MACA,GAAI,OAAO,QAAQ,MAAM,GAAG,KACxB,CAAC,6BAA6B,GAC9B,EAAE;MACN;MACD;KACD,SAAS;MACP;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACD;KACF;IACF;;EAEJ,EACD;EACE,MAAM;EACN,MAAM,OAAO,QAAQ,EAAE,WAAW;AAShC,UARkB,MAAM,mBAAmB;IACzC,MAAM;IACN,SAAS,YAAY;IACrB,gBAAgB;IAChB,yBAAyB,SAAS;AAChC,YAAO,QAAQ,aAAa,QAAQ,UAAU,SAAS,OAAO;;IAEjE,CAAC;;EAGL,CACF"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { serverFnFileId } from "../server-fn-id.js";
|
|
2
|
+
import { injectServerFnIds } from "../inject-server-fn-ids.js";
|
|
1
3
|
import { SERVER_MODE_ID } from "../../server-mode-plugin.js";
|
|
2
4
|
import { getPageHandlers } from "./get-page-handlers.js";
|
|
3
5
|
import { pageEndpointsPlugin } from "./page-endpoints-plugin.js";
|
|
@@ -5,25 +7,15 @@ import { getMatchingContentFilesWithFrontMatter } from "./get-content-files.js";
|
|
|
5
7
|
import { buildSitemap } from "./build-sitemap.js";
|
|
6
8
|
import { addPostRenderingHooks } from "./post-rendering-hook.js";
|
|
7
9
|
import { createI18nPostRenderingHook, expandRoutesWithLocales } from "./i18n-prerender.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
+
import { getServerFnHandlers } from "./get-server-fn-handlers.js";
|
|
11
|
+
import { SERVER_FN_DISPATCH_VIRTUAL, buildServerFnDispatchModule, getServerFnDispatchHandler } from "./server-fn-endpoints.js";
|
|
12
|
+
import { createRequire } from "node:module";
|
|
13
|
+
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
10
14
|
import { existsSync, readFileSync, readdirSync, unlinkSync } from "node:fs";
|
|
11
15
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
12
16
|
//#region packages/platform/src/lib/nitro/analog-nitro-plugin.ts
|
|
13
17
|
var SSR_ENTRY_VIRTUAL_ID = "\0virtual:@analogjs/nitro/ssr-entry";
|
|
14
18
|
/**
|
|
15
|
-
* Angular packages that ship in partial-compilation form and must pass
|
|
16
|
-
* through the linker before the SSR / nitro bundle can execute without
|
|
17
|
-
* JIT. Wired into `ssr.optimizeDeps.rolldownOptions.plugins`.
|
|
18
|
-
*/
|
|
19
|
-
var ANGULAR_SSR_DEPS = [
|
|
20
|
-
"@angular/compiler",
|
|
21
|
-
"@angular/core",
|
|
22
|
-
"@angular/common",
|
|
23
|
-
"@angular/platform-browser",
|
|
24
|
-
"@angular/platform-server"
|
|
25
|
-
];
|
|
26
|
-
/**
|
|
27
19
|
* Analog's NitroModule. Plug it into the Vite plugin chain alongside
|
|
28
20
|
* `nitro()` from `nitro/vite`; nitro/vite picks up the `.nitro` property
|
|
29
21
|
* and runs `setup(nitro)` once the Nitro instance is ready.
|
|
@@ -41,6 +33,8 @@ function analogNitroPlugin(options = {}) {
|
|
|
41
33
|
let ssrEntryMarkerPath = "";
|
|
42
34
|
let userPublicDir;
|
|
43
35
|
let isBuild = false;
|
|
36
|
+
let enabled = false;
|
|
37
|
+
let nitroH3Resolver;
|
|
44
38
|
const ssrDepsReady = /* @__PURE__ */ new WeakMap();
|
|
45
39
|
let builtIndexHtml;
|
|
46
40
|
function waitForSsrDeps(environment) {
|
|
@@ -77,8 +71,11 @@ function analogNitroPlugin(options = {}) {
|
|
|
77
71
|
name: "@analogjs/nitro",
|
|
78
72
|
enforce: "pre",
|
|
79
73
|
config(userConfig, configEnv) {
|
|
74
|
+
enabled = hasNitroVitePlugin(userConfig);
|
|
75
|
+
if (!enabled) return;
|
|
80
76
|
refreshContext(userConfig.root);
|
|
81
77
|
isBuild = configEnv?.command === "build";
|
|
78
|
+
nitroH3Resolver = nitroH3Plugin(resolve(context.workspaceRoot, context.rootDir));
|
|
82
79
|
if (userConfig.publicDir !== false) userPublicDir = resolve(context.workspaceRoot, context.rootDir, userConfig.publicDir ?? "public");
|
|
83
80
|
if (!process.env["NITRO_PRESET"]) {
|
|
84
81
|
if (process.env["BUILD_PRESET"]) process.env["NITRO_PRESET"] = process.env["BUILD_PRESET"];
|
|
@@ -92,24 +89,19 @@ function analogNitroPlugin(options = {}) {
|
|
|
92
89
|
};
|
|
93
90
|
if (ssr) {
|
|
94
91
|
overrides.experimental = { vite: { services: { ssr: { entry: ssrEntryMarkerPath } } } };
|
|
95
|
-
overrides.environments["ssr"] = {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
},
|
|
100
|
-
optimizeDeps: {
|
|
101
|
-
include: ANGULAR_SSR_DEPS,
|
|
102
|
-
rolldownOptions: { plugins: [angularLinkerPlugin()] }
|
|
103
|
-
}
|
|
104
|
-
};
|
|
92
|
+
overrides.environments["ssr"] = { build: {
|
|
93
|
+
outDir: resolve(context.workspaceRoot, "dist", context.rootDir, "ssr"),
|
|
94
|
+
rollupOptions: { input: { index: ssrEntryMarkerPath } }
|
|
95
|
+
} };
|
|
105
96
|
}
|
|
106
97
|
return overrides;
|
|
107
98
|
},
|
|
108
99
|
configureServer(server) {
|
|
109
100
|
const environment = server.environments["ssr"];
|
|
110
|
-
if (ssr && environment) waitForSsrDeps(environment).catch(() => void 0);
|
|
101
|
+
if (enabled && ssr && environment) waitForSsrDeps(environment).catch(() => void 0);
|
|
111
102
|
},
|
|
112
|
-
resolveId(id) {
|
|
103
|
+
resolveId(id, importer, resolveOptions) {
|
|
104
|
+
if (enabled && id === "h3") return nitroH3Resolver.resolveId.call(this, id, importer, resolveOptions);
|
|
113
105
|
if (id === ssrEntryMarkerPath || id === SSR_ENTRY_VIRTUAL_ID) {
|
|
114
106
|
if (ssr && !isBuild && this.environment.name === "ssr") return waitForSsrDeps(this.environment).then(() => SSR_ENTRY_VIRTUAL_ID);
|
|
115
107
|
return SSR_ENTRY_VIRTUAL_ID;
|
|
@@ -121,7 +113,7 @@ function analogNitroPlugin(options = {}) {
|
|
|
121
113
|
return generateSsrEntryWrapper(resolveEntryServer(), readIndexHtml());
|
|
122
114
|
},
|
|
123
115
|
writeBundle(_outputOptions, bundle) {
|
|
124
|
-
if (this.environment?.name !== "client") return;
|
|
116
|
+
if (!enabled || this.environment?.name !== "client") return;
|
|
125
117
|
const emitted = bundle[basename(indexHtmlPath())];
|
|
126
118
|
if (emitted?.type === "asset") {
|
|
127
119
|
const { source } = emitted;
|
|
@@ -215,10 +207,12 @@ function analogNitroPlugin(options = {}) {
|
|
|
215
207
|
additionalPagesDirs: options.additionalPagesDirs
|
|
216
208
|
});
|
|
217
209
|
nitro.options.handlers.push(...pageHandlers);
|
|
210
|
+
registerServerFns(nitro, context);
|
|
218
211
|
const serverDir = resolve(context.workspaceRoot, context.rootDir, `${context.sourceRoot}/server`);
|
|
219
|
-
|
|
212
|
+
const apiDirs = (options.additionalAPIDirs ?? []).map((dir) => resolve(context.workspaceRoot, `.${dir}`));
|
|
213
|
+
for (const dir of [serverDir, ...apiDirs]) if (existsSync(dir) && !nitro.options.scanDirs.includes(dir)) nitro.options.scanDirs.push(dir);
|
|
220
214
|
nitro.hooks.hook("rollup:before", (_n, rollupConfig) => {
|
|
221
|
-
if (Array.isArray(rollupConfig.plugins)) rollupConfig.plugins.push(pageEndpointsPlugin());
|
|
215
|
+
if (Array.isArray(rollupConfig.plugins)) rollupConfig.plugins.push(nitroH3Resolver, pageEndpointsPlugin(), serverFnIdPlugin(resolve(context.workspaceRoot, context.rootDir)));
|
|
222
216
|
applyAnalogNitroExternals(rollupConfig);
|
|
223
217
|
sanitizeNitroBundlerConfig(rollupConfig);
|
|
224
218
|
});
|
|
@@ -230,10 +224,22 @@ function analogNitroPlugin(options = {}) {
|
|
|
230
224
|
delete nitro.options.renderer.template;
|
|
231
225
|
nitro.hooks.hook("prerender:config", (prerendererConfig) => {
|
|
232
226
|
prerendererConfig.renderer = false;
|
|
227
|
+
prerendererConfig.routeRules = nitro.options.routeRules;
|
|
233
228
|
});
|
|
234
229
|
nitro.hooks.hook("prerender:init", (prerenderer) => {
|
|
235
230
|
prerenderer.options.renderer = { handler: "#analog/ssr-renderer" };
|
|
236
231
|
});
|
|
232
|
+
nitro.hooks.hook("prerender:routes", () => {
|
|
233
|
+
const publicDir = resolve(nitro.options.output.publicDir);
|
|
234
|
+
for (const extension of [
|
|
235
|
+
"",
|
|
236
|
+
".br",
|
|
237
|
+
".gz"
|
|
238
|
+
]) {
|
|
239
|
+
const indexFile = resolve(publicDir, `index.html${extension}`);
|
|
240
|
+
if (existsSync(indexFile)) unlinkSync(indexFile);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
237
243
|
}
|
|
238
244
|
injectAnalogRouteRuleHeaders(nitro);
|
|
239
245
|
await wirePrerender(nitro, options, context, apiPrefix);
|
|
@@ -244,6 +250,59 @@ function analogNitroPlugin(options = {}) {
|
|
|
244
250
|
} }
|
|
245
251
|
};
|
|
246
252
|
}
|
|
253
|
+
function hasNitroVitePlugin(userConfig) {
|
|
254
|
+
return (userConfig.plugins ?? []).flat(Infinity).some((plugin) => plugin?.name === "nitro:main");
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Resolves `h3` from Nitro's own package, so server code always uses the h3
|
|
258
|
+
* version the server runs on.
|
|
259
|
+
*/
|
|
260
|
+
function nitroH3Plugin(root) {
|
|
261
|
+
let nitroPackageJson;
|
|
262
|
+
return {
|
|
263
|
+
name: "analogjs-nitro-h3",
|
|
264
|
+
resolveId(id, _importer, resolveOptions) {
|
|
265
|
+
if (id !== "h3") return null;
|
|
266
|
+
nitroPackageJson ??= createRequire(join(root, "noop.js")).resolve("nitro/package.json");
|
|
267
|
+
return this.resolve(id, nitroPackageJson, {
|
|
268
|
+
...resolveOptions,
|
|
269
|
+
skipSelf: true
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Registers the `/_analog/fn/:id` dispatch handler when the app defines server
|
|
276
|
+
* functions in `*.server.ts` files.
|
|
277
|
+
*/
|
|
278
|
+
function registerServerFns(nitro, context) {
|
|
279
|
+
const modules = getServerFnHandlers(context);
|
|
280
|
+
if (!modules.length) return;
|
|
281
|
+
const root = resolve(context.workspaceRoot, context.rootDir);
|
|
282
|
+
const appConfigModule = [`${root}/${context.sourceRoot}/app/app.config.server.ts`, `${root}/${context.sourceRoot}/app.config.server.ts`].find((candidate) => existsSync(candidate));
|
|
283
|
+
nitro.options.handlers.push(getServerFnDispatchHandler());
|
|
284
|
+
nitro.options.virtual[SERVER_FN_DISPATCH_VIRTUAL] = buildServerFnDispatchModule({
|
|
285
|
+
modules,
|
|
286
|
+
appConfigModule
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Stamps the derived id into each `serverFn` in the Nitro server bundle, so it
|
|
291
|
+
* registers under the route the client calls.
|
|
292
|
+
*/
|
|
293
|
+
function serverFnIdPlugin(projectRoot) {
|
|
294
|
+
return {
|
|
295
|
+
name: "analogjs-server-fn-id",
|
|
296
|
+
transform(code, id) {
|
|
297
|
+
if (!id.endsWith(".server.ts")) return;
|
|
298
|
+
const injected = injectServerFnIds(code, serverFnFileId(id, projectRoot));
|
|
299
|
+
return injected ? {
|
|
300
|
+
code: injected.code,
|
|
301
|
+
map: null
|
|
302
|
+
} : void 0;
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
247
306
|
/**
|
|
248
307
|
* Builds the h3 handler installed as Nitro's `renderer.handler`. Short-circuits
|
|
249
308
|
* `ssr: false` routes to the raw client template; otherwise dispatches the
|
|
@@ -254,20 +313,30 @@ function analogNitroPlugin(options = {}) {
|
|
|
254
313
|
function generateSsrRendererVirtual(template) {
|
|
255
314
|
return `
|
|
256
315
|
import { defineHandler } from 'nitro/h3';
|
|
316
|
+
import { getRouteRules } from 'nitro/app';
|
|
257
317
|
import ssr from '#analog/ssr';
|
|
258
318
|
|
|
259
319
|
const TEMPLATE = ${JSON.stringify(template)};
|
|
260
320
|
|
|
261
321
|
export default defineHandler(async (event) => {
|
|
262
322
|
event.res.headers.set('content-type', 'text/html; charset=utf-8');
|
|
263
|
-
// 'x-analog-no-ssr' is stamped on
|
|
323
|
+
// 'x-analog-no-ssr' is stamped on the route rule headers by
|
|
264
324
|
// injectAnalogRouteRuleHeaders for routeRules with \`ssr: false\`. Nitro
|
|
265
|
-
//
|
|
266
|
-
|
|
267
|
-
if (
|
|
325
|
+
// writes those headers after the handler runs, so read the matched rules.
|
|
326
|
+
const { routeRules } = getRouteRules(event.req.method, event.url.pathname);
|
|
327
|
+
if (routeRules?.headers?.['x-analog-no-ssr'] === 'true') {
|
|
268
328
|
return TEMPLATE;
|
|
269
329
|
}
|
|
270
330
|
const service = ssr.default ?? ssr;
|
|
331
|
+
// The SSR service renders without a Node response, so forward the
|
|
332
|
+
// \`streaming: false\` rule on the request for the renderer to read.
|
|
333
|
+
if (routeRules?.headers?.['x-analog-no-streaming'] === 'true') {
|
|
334
|
+
const headers = new Headers(event.req.headers);
|
|
335
|
+
headers.set('x-analog-no-streaming', 'true');
|
|
336
|
+
return service.fetch(
|
|
337
|
+
new Request(event.req.url, { method: event.req.method, headers }),
|
|
338
|
+
);
|
|
339
|
+
}
|
|
271
340
|
return service.fetch(event.req);
|
|
272
341
|
});
|
|
273
342
|
`;
|
|
@@ -496,18 +565,6 @@ async function wirePrerender(nitro, options, context, apiPrefix) {
|
|
|
496
565
|
nitroPrerender.routes ??= [];
|
|
497
566
|
nitroPrerender.routes.push(...expanded);
|
|
498
567
|
if (prerender?.discover ?? false) nitroPrerender.crawlLinks = true;
|
|
499
|
-
const prerendersRoot = nitroPrerender.routes.some((route) => route === "/");
|
|
500
|
-
if ((options.ssr ?? true) && prerendersRoot) nitro.hooks.hook("prerender:init", () => {
|
|
501
|
-
const publicDir = resolve(nitro.options.output.publicDir);
|
|
502
|
-
for (const extension of [
|
|
503
|
-
"",
|
|
504
|
-
".br",
|
|
505
|
-
".gz"
|
|
506
|
-
]) {
|
|
507
|
-
const indexFile = resolve(publicDir, `index.html${extension}`);
|
|
508
|
-
if (existsSync(indexFile)) unlinkSync(indexFile);
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
568
|
if (prerender?.postRenderingHooks?.length) addPostRenderingHooks(nitro, prerender.postRenderingHooks);
|
|
512
569
|
if (Object.keys(routeSourceFiles).length > 0) nitro.hooks.hook("prerender:done", async () => {
|
|
513
570
|
const publicDir = resolve(nitro.options.output.publicDir);
|