@antelopejs/dms-frontend 0.7.1 → 0.8.0
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 +4 -4
- package/dist/commands/build-action.d.ts +8 -5
- package/dist/commands/build-action.js +13 -41
- package/dist/commands/build.js +9 -15
- package/dist/commands/dev-action.js +5 -1
- package/dist/commands/start-action.d.ts +2 -0
- package/dist/commands/start-action.js +36 -49
- package/dist/commands/start.js +8 -6
- package/dist/config.d.ts +2 -0
- package/dist/config.js +6 -0
- package/dist/derived-outputs.js +2 -2
- package/dist/fs-sync.d.ts +1 -0
- package/dist/fs-sync.js +6 -0
- package/dist/help.js +8 -4
- package/dist/index.js +4 -6
- package/dist/layer-watch.js +4 -0
- package/dist/layers.d.ts +1 -3
- package/dist/layers.js +1 -95
- package/dist/manifest.d.ts +8 -8
- package/dist/manifest.js +15 -39
- package/dist/materialize.js +6 -0
- package/dist/module-set.d.ts +14 -12
- package/dist/module-set.js +39 -31
- package/dist/private-values.d.ts +2 -2
- package/dist/private-values.js +1 -6
- package/dist/project-modules.d.ts +46 -0
- package/dist/project-modules.js +233 -0
- package/dist/workspace-setup.d.ts +3 -7
- package/dist/workspace-setup.js +41 -62
- package/dist/workspace.d.ts +2 -4
- package/dist/workspace.js +1 -1
- package/package.json +5 -7
- package/skills/dms-frontend/SKILL.md +2 -2
- package/templates/vue/client-chunking.mjs +61 -0
- package/templates/vue/email-renderer.ts +6 -1
- package/templates/vue/frontend-build-loader.ts +1 -1
- package/templates/vue/frontend-module.ts +24 -0
- package/templates/vue/main.ts +11 -2
- package/templates/vue/package.json +2 -2
- package/templates/vue/prepare-types.mjs +2 -7
- package/templates/vue/public-options.ts +19 -0
- package/templates/vue/server/auth/backend.mjs +20 -3
- package/templates/vue/server/auth/client-ip.mjs +64 -22
- package/templates/vue/server/auth/session.mjs +4 -11
- package/templates/vue/server/backend-proxies.mjs +13 -2
- package/templates/vue/server/backend-response.mjs +2 -13
- package/templates/vue/server/cli-report.mjs +42 -18
- package/templates/vue/server/client-manifest.mjs +22 -58
- package/templates/vue/server/dev-private-files.mjs +1 -1
- package/templates/vue/server/dev-styles.mjs +16 -5
- package/templates/vue/server/homepage.mjs +4 -1
- package/templates/vue/server/module-event.mjs +23 -8
- package/templates/vue/server/module-server.mjs +4 -4
- package/templates/vue/server/module-testing.mjs +5 -3
- package/templates/vue/server/proxy-compression.mjs +15 -8
- package/templates/vue/server/proxy-headers.mjs +12 -1
- package/templates/vue/server/proxy-redirects.mjs +66 -0
- package/templates/vue/server/proxy-transfers.mjs +84 -0
- package/templates/vue/server/public-endpoints.mjs +2 -2
- package/templates/vue/server/public-options.mjs +49 -0
- package/templates/vue/server/request-routing.mjs +20 -0
- package/templates/vue/server/web-body.mjs +24 -0
- package/templates/vue/server-module.ts +19 -7
- package/templates/vue/server.mjs +59 -49
- package/templates/vue/ssr-renderer.ts +19 -1
- package/templates/vue/vite.config.ts +72 -46
- package/templates/vue/vite.email.config.ts +6 -3
- package/templates/vue/vite.server.config.ts +5 -2
- package/dist/commands/snapshot-action.d.ts +0 -6
- package/dist/commands/snapshot-action.js +0 -53
- package/dist/commands/snapshot.d.ts +0 -2
- package/dist/commands/snapshot.js +0 -55
- package/dist/snapshot.d.ts +0 -25
- package/dist/snapshot.js +0 -90
- package/templates/vue/server/backend-wake.mjs +0 -129
package/templates/vue/server.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import { extname, join, resolve, sep } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { ofetch } from "ofetch";
|
|
6
6
|
import {
|
|
7
|
+
CLIENT_HEADERS,
|
|
7
8
|
relayedHeaders,
|
|
8
9
|
RequestBodyError,
|
|
9
10
|
UpstreamError,
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
redirectAccessRefusal,
|
|
18
19
|
UNEXPECTED_ERROR_BODY,
|
|
19
20
|
} from "./server/backend-response.mjs";
|
|
20
|
-
import { fetchWaking } from "./server/backend-wake.mjs";
|
|
21
21
|
import { handleClientError } from "./server/client-error.mjs";
|
|
22
22
|
import {
|
|
23
23
|
reportListenError,
|
|
@@ -37,7 +37,11 @@ import { documentStyleTags } from "./server/dev-styles.mjs";
|
|
|
37
37
|
import { watchEmailBundle } from "./server/email.mjs";
|
|
38
38
|
import { withFaviconPlaceholder } from "./server/favicon.mjs";
|
|
39
39
|
import { DEV_FS_DENY, denyPrivateFiles } from "./server/dev-private-files.mjs";
|
|
40
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
ownerLabel,
|
|
42
|
+
reachesBackend,
|
|
43
|
+
requestOwner,
|
|
44
|
+
} from "./server/request-routing.mjs";
|
|
41
45
|
import { routingReport } from "./server/backend-proxies.mjs";
|
|
42
46
|
import { routeRuleFor, ruleHeaders } from "./server/route-rules.mjs";
|
|
43
47
|
import {
|
|
@@ -45,6 +49,7 @@ import {
|
|
|
45
49
|
loadServerModules,
|
|
46
50
|
} from "./server/module-server.mjs";
|
|
47
51
|
import { HOMEPAGE } from "./server/homepage.mjs";
|
|
52
|
+
import { publicOptionsScript } from "./server/public-options.mjs";
|
|
48
53
|
import { loadPageProps } from "./server/page-props.mjs";
|
|
49
54
|
import { htmlTag } from "./server/html-tag.mjs";
|
|
50
55
|
import { listenHost } from "./server/listen-host.mjs";
|
|
@@ -55,6 +60,7 @@ import {
|
|
|
55
60
|
relayAnswer,
|
|
56
61
|
} from "./server/proxy-compression.mjs";
|
|
57
62
|
import { backendUrl, refuseForeignTarget } from "./server/request-target.mjs";
|
|
63
|
+
import { sendWithinLimit, SERVER_OPTIONS } from "./server/proxy-transfers.mjs";
|
|
58
64
|
import {
|
|
59
65
|
createInertiaPage,
|
|
60
66
|
htmlHeaders,
|
|
@@ -73,7 +79,12 @@ const SAFE_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
|
|
|
73
79
|
const LOCAL_ROUTES = [[icons.isIconRequest, icons.handleIcons]];
|
|
74
80
|
const CLIENT_ROOT = join(PROJECT_ROOT, "dist/client");
|
|
75
81
|
const SOURCE_TEMPLATE_PATH = join(PROJECT_ROOT, "index.html");
|
|
76
|
-
|
|
82
|
+
// A URL, not a path: on Windows, `import()` reads `C:\...` as a URL whose
|
|
83
|
+
// scheme is `c:` and refuses it.
|
|
84
|
+
const BUILT_SSR_RENDERER_URL = new URL(
|
|
85
|
+
"dist/ssr/ssr-renderer.js",
|
|
86
|
+
import.meta.url,
|
|
87
|
+
);
|
|
77
88
|
// The SSR bundle keeps vue-i18n external, so Node loads its esm-bundler build,
|
|
78
89
|
// which reads compile-time flags only a bundler replaces. Vite inlines them in
|
|
79
90
|
// the client bundle; without the same value here, installing vue-i18n under
|
|
@@ -94,8 +105,7 @@ async function developmentServer() {
|
|
|
94
105
|
// The generated secrets and the modules' server code, never served.
|
|
95
106
|
fs: { deny: DEV_FS_DENY },
|
|
96
107
|
};
|
|
97
|
-
if (frontendHttpServer)
|
|
98
|
-
serverOptions.hmr = { server: frontendHttpServer };
|
|
108
|
+
if (frontendHttpServer) serverOptions.ws = { server: frontendHttpServer };
|
|
99
109
|
return createViteServer({
|
|
100
110
|
server: serverOptions,
|
|
101
111
|
appType: "custom",
|
|
@@ -127,9 +137,7 @@ function backendHeaders(request, access = { anonymous: false, headers: [] }) {
|
|
|
127
137
|
"if-match",
|
|
128
138
|
"origin",
|
|
129
139
|
"referer",
|
|
130
|
-
|
|
131
|
-
"x-content-language",
|
|
132
|
-
"x-realtime-session",
|
|
140
|
+
...CLIENT_HEADERS,
|
|
133
141
|
...access.headers,
|
|
134
142
|
]),
|
|
135
143
|
...forwardedHeaders(request),
|
|
@@ -155,10 +163,9 @@ function serverComponentFetch(request) {
|
|
|
155
163
|
}
|
|
156
164
|
|
|
157
165
|
async function backendJson(path, request) {
|
|
158
|
-
const response = await
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
);
|
|
166
|
+
const response = await fetch(new URL(path, process.env.DMS_API_BASE_URL), {
|
|
167
|
+
headers: backendHeaders(request),
|
|
168
|
+
});
|
|
162
169
|
if (!response.ok) {
|
|
163
170
|
throw await backendResponseError(response);
|
|
164
171
|
}
|
|
@@ -202,25 +209,45 @@ function redirectSignedOutPrivatePage(request, response, props, auth) {
|
|
|
202
209
|
return true;
|
|
203
210
|
}
|
|
204
211
|
|
|
205
|
-
/**
|
|
206
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Sends a request to the backend through the proxy it reached.
|
|
214
|
+
* `isProxiedPath` says which backend paths a relayed `Location` may name on
|
|
215
|
+
* the frontend's origin.
|
|
216
|
+
*/
|
|
217
|
+
async function proxy(request, response, backendProxy, isProxiedPath) {
|
|
207
218
|
const access = proxyAccess(request, SAFE_METHODS, backendProxy);
|
|
208
219
|
if (access.isRefused) {
|
|
209
220
|
refuseCrossOrigin(response);
|
|
210
221
|
return true;
|
|
211
222
|
}
|
|
223
|
+
// A client that left while the request was routed closed the response
|
|
224
|
+
// already, and would never abort the request below.
|
|
225
|
+
if (response.closed) return;
|
|
212
226
|
// Cancelling the body alone misses a client that leaves before the backend
|
|
213
227
|
// answers: its stream, an SSE feed above all, then stayed open for good.
|
|
214
228
|
const abandoned = new AbortController();
|
|
215
229
|
response.once("close", () => abandoned.abort());
|
|
216
|
-
const
|
|
230
|
+
const init = {
|
|
217
231
|
signal: abandoned.signal,
|
|
218
232
|
method: request.method,
|
|
219
233
|
headers: { ...backendHeaders(request, access), ...PLAIN_ANSWER_HEADERS },
|
|
220
|
-
body: ["GET", "HEAD"].includes(request.method) ? undefined : request,
|
|
221
234
|
duplex: "half",
|
|
235
|
+
// A backend redirect is the browser's to follow: Media sends a file's
|
|
236
|
+
// link to the storage's signed URL, on the public origin the server
|
|
237
|
+
// itself may not reach, which turned every download into a 502.
|
|
238
|
+
redirect: "manual",
|
|
239
|
+
};
|
|
240
|
+
const upstream = await sendWithinLimit(
|
|
241
|
+
request,
|
|
242
|
+
response,
|
|
243
|
+
backendProxy.maxBodyBytes,
|
|
244
|
+
(body) => fetch(backendUrl(request.url), { ...init, body }),
|
|
245
|
+
);
|
|
246
|
+
if (!upstream) return true;
|
|
247
|
+
await relayAnswer(request, response, upstream, {
|
|
248
|
+
fetched: true,
|
|
249
|
+
isProxiedPath,
|
|
222
250
|
});
|
|
223
|
-
await relayAnswer(request, response, upstream, { fetched: true });
|
|
224
251
|
}
|
|
225
252
|
|
|
226
253
|
/**
|
|
@@ -240,7 +267,7 @@ function serveAsset(pathname, request, response) {
|
|
|
240
267
|
async function ssrRenderer(devServer) {
|
|
241
268
|
const renderer = devServer
|
|
242
269
|
? await devServer.ssrLoadModule("/ssr-renderer.ts")
|
|
243
|
-
: await (productionSsrRenderer ??= import(
|
|
270
|
+
: await (productionSsrRenderer ??= import(BUILT_SSR_RENDERER_URL.href));
|
|
244
271
|
await icons.provideIconCollections(renderer);
|
|
245
272
|
return renderer;
|
|
246
273
|
}
|
|
@@ -250,6 +277,7 @@ function clientRenderedShell(page) {
|
|
|
250
277
|
body: inertiaAppHtml(page),
|
|
251
278
|
head: { headTags: "", htmlAttrs: "", bodyAttrs: "" },
|
|
252
279
|
overlays: "",
|
|
280
|
+
modules: [],
|
|
253
281
|
};
|
|
254
282
|
}
|
|
255
283
|
|
|
@@ -290,7 +318,9 @@ export async function renderHtml(
|
|
|
290
318
|
: await serverRendered(page, serverFetch, requestCookies, devServer);
|
|
291
319
|
if (rendered.redirect)
|
|
292
320
|
return { html: "", status: 200, redirect: rendered.redirect };
|
|
293
|
-
const
|
|
321
|
+
const headEnd =
|
|
322
|
+
(await documentStyleTags(devServer, rendered.modules, template)) +
|
|
323
|
+
publicOptionsScript();
|
|
294
324
|
const html = template
|
|
295
325
|
.replace("<title>Antelope DMS</title>", () =>
|
|
296
326
|
withFaviconPlaceholder(rendered.head.headTags),
|
|
@@ -299,7 +329,7 @@ export async function renderHtml(
|
|
|
299
329
|
htmlTag(attributes, rendered.head.htmlAttrs),
|
|
300
330
|
)
|
|
301
331
|
.replace("<body", `<body ${rendered.head.bodyAttrs}`)
|
|
302
|
-
.replace("</head>", `${
|
|
332
|
+
.replace("</head>", `${headEnd}</head>`)
|
|
303
333
|
.replace(
|
|
304
334
|
'<div id="dms-overlays" class="isolate"></div>',
|
|
305
335
|
`<div id="dms-overlays" class="isolate">${rendered.overlays}</div>`,
|
|
@@ -332,9 +362,6 @@ async function writeBackendError(error, request, response) {
|
|
|
332
362
|
if (await redirectAccessRefusal(error, request, response, loadRenderer))
|
|
333
363
|
return;
|
|
334
364
|
console.error("DMS backend request failed", error);
|
|
335
|
-
const retryHeaders = error?.retryAfter
|
|
336
|
-
? { "retry-after": error.retryAfter }
|
|
337
|
-
: {};
|
|
338
365
|
if (isFrontendVisit(request)) {
|
|
339
366
|
const props = {
|
|
340
367
|
path: pathname,
|
|
@@ -348,24 +375,18 @@ async function writeBackendError(error, request, response) {
|
|
|
348
375
|
request,
|
|
349
376
|
response,
|
|
350
377
|
status,
|
|
351
|
-
|
|
378
|
+
inertiaHeaders(page.version),
|
|
352
379
|
JSON.stringify(page),
|
|
353
380
|
);
|
|
354
381
|
}
|
|
355
382
|
const { html } = await renderRequestHtml(page, request);
|
|
356
|
-
return writeContent(
|
|
357
|
-
request,
|
|
358
|
-
response,
|
|
359
|
-
status,
|
|
360
|
-
{ ...htmlHeaders(), ...retryHeaders },
|
|
361
|
-
html,
|
|
362
|
-
);
|
|
383
|
+
return writeContent(request, response, status, htmlHeaders(), html);
|
|
363
384
|
}
|
|
364
385
|
const payload =
|
|
365
386
|
error instanceof UpstreamError || error instanceof RequestBodyError
|
|
366
387
|
? { message: error.message }
|
|
367
388
|
: UNEXPECTED_ERROR_BODY;
|
|
368
|
-
response.writeHead(status, { "content-type": JSON_TYPE
|
|
389
|
+
response.writeHead(status, { "content-type": JSON_TYPE });
|
|
369
390
|
response.end(JSON.stringify(payload));
|
|
370
391
|
}
|
|
371
392
|
|
|
@@ -425,15 +446,16 @@ export async function handleRequest(request, response) {
|
|
|
425
446
|
if (localRoute) return localRoute[1](request, response);
|
|
426
447
|
const devServer = await developmentServer();
|
|
427
448
|
const modules = await loadServerModules(devServer);
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
);
|
|
449
|
+
const hasFile = (path) => hasRendererFile(devServer, path);
|
|
450
|
+
const owner = requestOwner(request.method, pathname, modules, hasFile);
|
|
431
451
|
if (devServer) response.setHeader("x-dms-route-owner", ownerLabel(owner));
|
|
432
452
|
if (owner.kind === "renderer")
|
|
433
453
|
return serveRendererFile(devServer, request, response, pathname);
|
|
434
454
|
if (owner.kind === "module")
|
|
435
455
|
return handleModuleRoute(request, response, pathname, modules);
|
|
436
|
-
|
|
456
|
+
const isProxiedPath = (path) => reachesBackend(path, modules, hasFile);
|
|
457
|
+
if (owner.kind === "backend")
|
|
458
|
+
return proxy(request, response, owner.proxy, isProxiedPath);
|
|
437
459
|
if (owner.kind === "not-found") return writeNotFound(response);
|
|
438
460
|
if (requestFailure.hasMalformedPath(request.url))
|
|
439
461
|
return requestFailure.writeBadRequest(response);
|
|
@@ -487,19 +509,7 @@ async function writeRequestFailure(error, request, response) {
|
|
|
487
509
|
await writeBackendError(error, request, response);
|
|
488
510
|
}
|
|
489
511
|
|
|
490
|
-
/**
|
|
491
|
-
* Aborted once the client is gone, ending a wait for a waking backend. An
|
|
492
|
-
* embedder's response that emits no events never aborts it.
|
|
493
|
-
*/
|
|
494
|
-
function abandonedSignal(response) {
|
|
495
|
-
const abandoned = new AbortController();
|
|
496
|
-
if (typeof response.once === "function")
|
|
497
|
-
response.once("close", () => abandoned.abort());
|
|
498
|
-
return abandoned.signal;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
512
|
export async function handleRequestSafely(request, response) {
|
|
502
|
-
request.dmsAbandoned = abandonedSignal(response);
|
|
503
513
|
try {
|
|
504
514
|
if (refuseForeignTarget(request, response)) return;
|
|
505
515
|
await handleRequest(request, response);
|
|
@@ -515,7 +525,7 @@ if (
|
|
|
515
525
|
process.argv[1] &&
|
|
516
526
|
import.meta.url === new URL(`file://${process.argv[1]}`).href
|
|
517
527
|
) {
|
|
518
|
-
frontendHttpServer = createServer(handleRequestSafely);
|
|
528
|
+
frontendHttpServer = createServer(SERVER_OPTIONS, handleRequestSafely);
|
|
519
529
|
frontendHttpServer.on("clientError", (error, socket) =>
|
|
520
530
|
handleClientError(error, socket, maxHeaderSize),
|
|
521
531
|
);
|
|
@@ -28,7 +28,9 @@ import {
|
|
|
28
28
|
setDmsServerRuntimeResolver,
|
|
29
29
|
setupFrontendModules,
|
|
30
30
|
trackDmsServerScopes,
|
|
31
|
+
withPublicOptions,
|
|
31
32
|
} from "./frontend-module";
|
|
33
|
+
import { parsePublicOptions } from "./public-options";
|
|
32
34
|
import { frontendModules } from "./frontend-modules.generated";
|
|
33
35
|
import {
|
|
34
36
|
SSR_ICONS_ID,
|
|
@@ -53,6 +55,12 @@ export interface DmsSsrResult {
|
|
|
53
55
|
body: string;
|
|
54
56
|
head: DmsSsrHead;
|
|
55
57
|
overlays: string;
|
|
58
|
+
/**
|
|
59
|
+
* The id of every single-file component the render created, its path from
|
|
60
|
+
* the workspace root as the client manifest keys it: the server links their
|
|
61
|
+
* stylesheets.
|
|
62
|
+
*/
|
|
63
|
+
modules: string[];
|
|
56
64
|
error?: DmsErrorData;
|
|
57
65
|
redirect?: string;
|
|
58
66
|
}
|
|
@@ -64,6 +72,8 @@ export interface DmsSsrHead {
|
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
interface DmsSsrContext {
|
|
75
|
+
/** Filled by `@vitejs/plugin-vue`: each component adds its id as it sets up. */
|
|
76
|
+
modules?: Set<string>;
|
|
67
77
|
teleports?: Record<string, string>;
|
|
68
78
|
}
|
|
69
79
|
|
|
@@ -122,7 +132,13 @@ function iconsScript(names: Set<string>): string {
|
|
|
122
132
|
return `<script id="${SSR_ICONS_ID}" type="application/json">${value}</script>`;
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
await setupFrontendModules(
|
|
135
|
+
await setupFrontendModules(
|
|
136
|
+
withPublicOptions(
|
|
137
|
+
frontendModules,
|
|
138
|
+
parsePublicOptions(process.env.DMS_PUBLIC_OPTIONS),
|
|
139
|
+
),
|
|
140
|
+
appConfigs,
|
|
141
|
+
);
|
|
126
142
|
|
|
127
143
|
export function isDmsFrontendPage(path: string): boolean {
|
|
128
144
|
return hasDmsPage(path);
|
|
@@ -208,6 +224,7 @@ async function renderDmsPageWithRuntime(
|
|
|
208
224
|
body: "",
|
|
209
225
|
head: { bodyAttrs: "", headTags: "", htmlAttrs: "" },
|
|
210
226
|
overlays: "",
|
|
227
|
+
modules: [],
|
|
211
228
|
redirect: runtime.serverRedirect,
|
|
212
229
|
};
|
|
213
230
|
}
|
|
@@ -238,6 +255,7 @@ async function renderDmsPageWithRuntime(
|
|
|
238
255
|
htmlAttrs: renderedHead.htmlAttrs,
|
|
239
256
|
},
|
|
240
257
|
overlays: ssrContext.teleports?.["#dms-overlays"] ?? "",
|
|
258
|
+
modules: [...(ssrContext.modules ?? [])],
|
|
241
259
|
};
|
|
242
260
|
} finally {
|
|
243
261
|
// Only once the head and the async data are serialized: both still read
|
|
@@ -9,11 +9,12 @@ import {
|
|
|
9
9
|
normalizePath,
|
|
10
10
|
type Plugin,
|
|
11
11
|
} from "vite";
|
|
12
|
+
import { clientCodeSplitting, onBuildLog } from "./client-chunking.mjs";
|
|
12
13
|
import { rejectServerSourcesInClient } from "./client-server-guard.mjs";
|
|
13
14
|
import { uiInertiaPage } from "./ui-inertia-page.mjs";
|
|
14
15
|
import { uiRequestState } from "./ui-request-state.mjs";
|
|
15
|
-
import { autoImportDirectories } from "./frontend-build-loader";
|
|
16
|
-
import { frontendBuilds } from "./frontend-builds.generated";
|
|
16
|
+
import { autoImportDirectories } from "./frontend-build-loader.ts";
|
|
17
|
+
import { frontendBuilds } from "./frontend-builds.generated.ts";
|
|
17
18
|
import { orderHeadForFirstPaint } from "./head-order.mjs";
|
|
18
19
|
import { iconScanGlobs } from "./icon-scan.mjs";
|
|
19
20
|
|
|
@@ -27,7 +28,10 @@ interface FrontendModuleRegistry {
|
|
|
27
28
|
modules: FrontendModuleRegistryEntry[];
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
const registryPath = resolve(
|
|
31
|
+
const registryPath = resolve(
|
|
32
|
+
import.meta.dirname,
|
|
33
|
+
"generated-frontend-modules.json",
|
|
34
|
+
);
|
|
31
35
|
const registry = JSON.parse(
|
|
32
36
|
readFileSync(registryPath, "utf8"),
|
|
33
37
|
) as FrontendModuleRegistry;
|
|
@@ -109,7 +113,7 @@ const optimizedDependencies = [
|
|
|
109
113
|
* `normalizePath` is Vite's own answer to this, the identity on POSIX.
|
|
110
114
|
*/
|
|
111
115
|
const optimizerEntries = [
|
|
112
|
-
resolve(
|
|
116
|
+
resolve(import.meta.dirname, "main.ts"),
|
|
113
117
|
...moduleRoots.map((root) => resolve(root, "dms.frontend.ts")),
|
|
114
118
|
...frontendSourceRoots.flatMap((root) => [
|
|
115
119
|
resolve(root, "app/**/*.vue"),
|
|
@@ -128,7 +132,7 @@ function paintBeforeHydrate(): Plugin {
|
|
|
128
132
|
|
|
129
133
|
const uiLinkImport = "@nuxt/ui/components/Link.vue";
|
|
130
134
|
const uiInertiaLinkImport = resolve(
|
|
131
|
-
|
|
135
|
+
import.meta.dirname,
|
|
132
136
|
"node_modules/@nuxt/ui/dist/runtime/vue/overrides/inertia/Link.vue",
|
|
133
137
|
);
|
|
134
138
|
/**
|
|
@@ -163,7 +167,12 @@ export default defineConfig({
|
|
|
163
167
|
router: "inertia",
|
|
164
168
|
icon: {
|
|
165
169
|
clientBundle: {
|
|
166
|
-
scan: {
|
|
170
|
+
scan: {
|
|
171
|
+
globInclude: iconScanGlobs(
|
|
172
|
+
import.meta.dirname,
|
|
173
|
+
frontendSourceRoots,
|
|
174
|
+
),
|
|
175
|
+
},
|
|
167
176
|
},
|
|
168
177
|
},
|
|
169
178
|
components: { dirs: [] },
|
|
@@ -179,42 +188,43 @@ export default defineConfig({
|
|
|
179
188
|
// backslashes intact, where `\U`, `\M` and `\f` are read as escape
|
|
180
189
|
// sequences: the specifier the bundler then resolves is a mangled
|
|
181
190
|
// path that cannot exist. Keep it POSIX.
|
|
182
|
-
[normalizePath(resolve(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
191
|
+
[normalizePath(resolve(import.meta.dirname, "frontend-module.ts"))]:
|
|
192
|
+
[
|
|
193
|
+
"$fetch",
|
|
194
|
+
"abortDmsNavigation",
|
|
195
|
+
"clearDmsError",
|
|
196
|
+
"createDmsError",
|
|
197
|
+
"dmsRequestKey",
|
|
198
|
+
"defineDmsAppConfig",
|
|
199
|
+
"defineDmsPlugin",
|
|
200
|
+
"defineDmsMiddleware",
|
|
201
|
+
"defineDmsPageMeta",
|
|
202
|
+
"navigateDms",
|
|
203
|
+
"preloadDmsComponents",
|
|
204
|
+
"refreshDmsData",
|
|
205
|
+
"refreshDmsPageData",
|
|
206
|
+
"setDmsAsyncDataScope",
|
|
207
|
+
"showDmsError",
|
|
208
|
+
"useDmsAsyncData",
|
|
209
|
+
"useDmsData",
|
|
210
|
+
"useDmsCookie",
|
|
211
|
+
"useDmsFetch",
|
|
212
|
+
"useHead",
|
|
213
|
+
"useI18n",
|
|
214
|
+
"useDmsError",
|
|
215
|
+
"useDmsPagedData",
|
|
216
|
+
"useDmsPageLoading",
|
|
217
|
+
"useDmsApp",
|
|
218
|
+
"useDmsRoute",
|
|
219
|
+
"useDmsRouter",
|
|
220
|
+
"useDmsRuntimeConfig",
|
|
221
|
+
"useSeoMeta",
|
|
222
|
+
"useDmsState",
|
|
223
|
+
"useDmsAppConfig",
|
|
224
|
+
"DmsClientOnly",
|
|
225
|
+
"DmsLink",
|
|
226
|
+
"useDmsUserSession",
|
|
227
|
+
],
|
|
218
228
|
},
|
|
219
229
|
],
|
|
220
230
|
dts: "auto-imports.d.ts",
|
|
@@ -228,13 +238,16 @@ export default defineConfig({
|
|
|
228
238
|
// Nuxt UI's `Icon` must share one copy for the same-origin provider to apply.
|
|
229
239
|
dedupe: ["vue", "reka-ui", "@nuxt/ui", "@vueuse/core", "@iconify/vue"],
|
|
230
240
|
alias: {
|
|
231
|
-
"#dms/frontend-module": resolve(
|
|
241
|
+
"#dms/frontend-module": resolve(
|
|
242
|
+
import.meta.dirname,
|
|
243
|
+
"frontend-module.ts",
|
|
244
|
+
),
|
|
232
245
|
// For the server's development loader only: no browser module imports
|
|
233
246
|
// a `dms.server.ts`.
|
|
234
|
-
"#dms/server": resolve(
|
|
247
|
+
"#dms/server": resolve(import.meta.dirname, "server-module.ts"),
|
|
235
248
|
"#build/nuxt-icon-client-bundle": "virtual:nuxt-ui-icons",
|
|
236
249
|
"#shortcuts-aggregated": resolve(
|
|
237
|
-
|
|
250
|
+
import.meta.dirname,
|
|
238
251
|
"shortcuts-aggregated.generated.ts",
|
|
239
252
|
),
|
|
240
253
|
...stableModuleAliases,
|
|
@@ -252,5 +265,18 @@ export default defineConfig({
|
|
|
252
265
|
},
|
|
253
266
|
ssr: { noExternal: ["@nuxt/icon", "@nuxt/ui"] },
|
|
254
267
|
server: { strictPort: true, allowedHosts: [".onamp.dev"] },
|
|
255
|
-
build: {
|
|
268
|
+
build: {
|
|
269
|
+
manifest: true,
|
|
270
|
+
outDir: "dist/client",
|
|
271
|
+
rolldownOptions: { onLog: onBuildLog },
|
|
272
|
+
},
|
|
273
|
+
// The browser bundle only: the server bundles are single Node programs, for
|
|
274
|
+
// which a file count means nothing.
|
|
275
|
+
environments: {
|
|
276
|
+
client: {
|
|
277
|
+
build: {
|
|
278
|
+
rolldownOptions: { output: { codeSplitting: clientCodeSplitting } },
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
},
|
|
256
282
|
});
|
|
@@ -14,7 +14,10 @@ interface FrontendModuleRegistry {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const registry = JSON.parse(
|
|
17
|
-
readFileSync(
|
|
17
|
+
readFileSync(
|
|
18
|
+
resolve(import.meta.dirname, "generated-frontend-modules.json"),
|
|
19
|
+
"utf8",
|
|
20
|
+
),
|
|
18
21
|
) as FrontendModuleRegistry;
|
|
19
22
|
const moduleAliases = Object.fromEntries(
|
|
20
23
|
registry.modules.map((module) => [`@frontend/${module.id}`, module.root]),
|
|
@@ -42,7 +45,7 @@ export default defineConfig({
|
|
|
42
45
|
{
|
|
43
46
|
name: "dms-email-locale-assets",
|
|
44
47
|
buildStart() {
|
|
45
|
-
const directory = resolve(
|
|
48
|
+
const directory = resolve(import.meta.dirname, "locales.generated");
|
|
46
49
|
for (const file of readdirSync(directory).filter((name) =>
|
|
47
50
|
name.endsWith(".json"),
|
|
48
51
|
)) {
|
|
@@ -66,7 +69,7 @@ export default defineConfig({
|
|
|
66
69
|
// Inlined verbatim as a module specifier in the generated import, so
|
|
67
70
|
// it has to be POSIX: a native Windows path would reach the parser
|
|
68
71
|
// with its backslashes read as string escapes. See vite.config.ts.
|
|
69
|
-
[normalizePath(resolve(
|
|
72
|
+
[normalizePath(resolve(import.meta.dirname, "email-runtime.ts"))]: [
|
|
70
73
|
"useDmsAppConfig",
|
|
71
74
|
"useDmsRuntimeConfig",
|
|
72
75
|
"defineDmsAppConfig",
|
|
@@ -12,7 +12,10 @@ interface FrontendModuleRegistry {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const registry = JSON.parse(
|
|
15
|
-
readFileSync(
|
|
15
|
+
readFileSync(
|
|
16
|
+
resolve(import.meta.dirname, "generated-frontend-modules.json"),
|
|
17
|
+
"utf8",
|
|
18
|
+
),
|
|
16
19
|
) as FrontendModuleRegistry;
|
|
17
20
|
const moduleAliases = Object.fromEntries(
|
|
18
21
|
registry.modules.map((module) => [`@frontend/${module.id}`, module.root]),
|
|
@@ -44,7 +47,7 @@ export default defineConfig({
|
|
|
44
47
|
logLevel,
|
|
45
48
|
resolve: {
|
|
46
49
|
alias: {
|
|
47
|
-
"#dms/server": resolve(
|
|
50
|
+
"#dms/server": resolve(import.meta.dirname, "server-module.ts"),
|
|
48
51
|
...stableModuleAliases,
|
|
49
52
|
...moduleAliases,
|
|
50
53
|
},
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runSnapshot = runSnapshot;
|
|
4
|
-
const node_fs_1 = require("node:fs");
|
|
5
|
-
const node_os_1 = require("node:os");
|
|
6
|
-
const node_path_1 = require("node:path");
|
|
7
|
-
const cli_1 = require("@antelopejs/core/cli");
|
|
8
|
-
const common_1 = require("../common");
|
|
9
|
-
const output_1 = require("../output");
|
|
10
|
-
const snapshot_1 = require("../snapshot");
|
|
11
|
-
async function runSnapshot(options) {
|
|
12
|
-
const startedAt = Date.now();
|
|
13
|
-
const backendUrl = (0, common_1.requireBackendUrl)(options.backendUrl);
|
|
14
|
-
const bootstrapSecret = (0, common_1.normalizeBootstrapSecret)(options.bootstrapSecret);
|
|
15
|
-
if (!bootstrapSecret) {
|
|
16
|
-
throw new common_1.UsageError({
|
|
17
|
-
title: "A snapshot needs the bootstrap credential",
|
|
18
|
-
reason: "Without it the backend withholds the modules' backend proxies, and a build from the snapshot would not route them.",
|
|
19
|
-
fixes: [
|
|
20
|
-
"Set DMS_BOOTSTRAP_SECRET to the backend's frontend.bootstrapSecret",
|
|
21
|
-
],
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
(0, output_1.writeHeader)("snapshot", [backendUrl]);
|
|
25
|
-
const task = (0, cli_1.getProcessTasks)().start("Fetching the manifest and layers");
|
|
26
|
-
const scratch = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "dms-snapshot-"));
|
|
27
|
-
try {
|
|
28
|
-
const manifest = await (0, common_1.fetchManifest)(backendUrl, undefined, bootstrapSecret);
|
|
29
|
-
const layers = (0, node_path_1.join)(scratch, snapshot_1.SNAPSHOT_LAYERS_DIR);
|
|
30
|
-
await (0, common_1.downloadAndExtractLayers)(backendUrl, manifest.pack, layers, true, bootstrapSecret);
|
|
31
|
-
const snapshot = (0, snapshot_1.writeSnapshot)(options.output, backendUrl, manifest, layers);
|
|
32
|
-
task.succeed(`Fetched ${manifest.modules.length} frontend module${manifest.modules.length === 1 ? "" : "s"}`);
|
|
33
|
-
(0, output_1.writeBlankLine)();
|
|
34
|
-
(0, cli_1.getProcessUi)().summary({
|
|
35
|
-
headline: `Took a snapshot of modules ${snapshot.digest}, without private values`,
|
|
36
|
-
artifact: options.output,
|
|
37
|
-
durationMs: Date.now() - startedAt,
|
|
38
|
-
nextSteps: [
|
|
39
|
-
{
|
|
40
|
-
command: `ajs dms build --from ${options.output} --workspace .dms-frontend`,
|
|
41
|
-
description: "without the backend or any secret",
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
(0, output_1.endInterruptedTask)(task, error, "Snapshot stopped");
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
finally {
|
|
51
|
-
(0, node_fs_1.rmSync)(scratch, { recursive: true, force: true });
|
|
52
|
-
}
|
|
53
|
-
}
|