@fulgurjs/federation 4.1.0 → 4.2.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/CHANGELOG.md +32 -0
- package/README.md +115 -75
- package/dist/{chunk-75PP6EAK.js → chunk-XIO5Y2IM.js} +1 -1
- package/dist/cli.js +625 -141
- package/dist/config.cjs +3 -2
- package/dist/config.js +3 -2
- package/dist/index.cjs +2 -2
- package/dist/index.js +2 -2
- package/dist/runtime.js +1 -1
- package/docs//350/277/201/347/247/273/346/214/207/345/215/227.md +9 -9
- package/examples/fulgurjs.config.example.ts +29 -37
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -156,8 +156,8 @@ var init_manifest = __esm({
|
|
|
156
156
|
|
|
157
157
|
// src/config.ts
|
|
158
158
|
async function loadRepoConfig(configPath) {
|
|
159
|
-
const { pathToFileURL, fileURLToPath } = await import("node:url");
|
|
160
|
-
const { createRequire } = await import("node:module");
|
|
159
|
+
const { pathToFileURL: pathToFileURL2, fileURLToPath } = await import("node:url");
|
|
160
|
+
const { createRequire: createRequire2 } = await import("node:module");
|
|
161
161
|
const fs3 = await import("node:fs");
|
|
162
162
|
const os = await import("node:os");
|
|
163
163
|
const path3 = await import("node:path");
|
|
@@ -173,43 +173,44 @@ async function loadRepoConfig(configPath) {
|
|
|
173
173
|
return "";
|
|
174
174
|
})();
|
|
175
175
|
const selfConfigJs = selfDir ? path3.join(selfDir, "config.js") : "";
|
|
176
|
-
const SELF_SPEC = selfConfigJs && fs3.existsSync(selfConfigJs) ?
|
|
176
|
+
const SELF_SPEC = selfConfigJs && fs3.existsSync(selfConfigJs) ? pathToFileURL2(selfConfigJs).href : "@fulgurjs-federation-config-unavailable";
|
|
177
177
|
const rewriteSelfImports = (source) => source.replace(/(['"])@fulgurjs\/federation\/config\1/g, (_m, q) => `${q}${SELF_SPEC}${q}`);
|
|
178
|
+
let cacheBust = 0;
|
|
178
179
|
const importConfigs = async (cacheKey) => {
|
|
179
|
-
return await import(`${cacheKey}?t=${Date.now()}`);
|
|
180
|
+
return await import(`${cacheKey}?t=${Date.now()}-${++cacheBust}`);
|
|
180
181
|
};
|
|
181
182
|
let mod;
|
|
182
183
|
if (configPath.endsWith(".json")) {
|
|
183
184
|
mod = { default: JSON.parse(fs3.readFileSync(configPath, "utf8")) };
|
|
184
185
|
} else {
|
|
185
186
|
const source = rewriteSelfImports(fs3.readFileSync(configPath, "utf8"));
|
|
186
|
-
const tmpBase = path3.join(os.tmpdir(), `fulgurjs-config-${Date.now()}`);
|
|
187
|
+
const tmpBase = path3.join(os.tmpdir(), `fulgurjs-config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
|
|
187
188
|
if (/\.(ts|mts|cts)$/.test(configPath)) {
|
|
188
189
|
try {
|
|
189
190
|
const tmpTs = `${tmpBase}.ts`;
|
|
190
191
|
fs3.writeFileSync(tmpTs, source);
|
|
191
|
-
mod = await importConfigs(
|
|
192
|
+
mod = await importConfigs(pathToFileURL2(tmpTs).href);
|
|
192
193
|
} catch (e) {
|
|
193
194
|
if (!/Unexpected|SyntaxError|ERR_UNSUPPORTED_NODE_MODULES|ERR_UNKNOWN_FILE_EXTENSION|ERR_IMPORT_ATTRIBUTE/.test(String(e)) && process.version.startsWith("v2")) {
|
|
194
195
|
throw e;
|
|
195
196
|
}
|
|
196
|
-
const requireFromConfig =
|
|
197
|
+
const requireFromConfig = createRequire2(configPath);
|
|
197
198
|
let esbuild;
|
|
198
199
|
try {
|
|
199
200
|
esbuild = requireFromConfig("esbuild");
|
|
200
201
|
} catch {
|
|
201
|
-
const requireFromSelf =
|
|
202
|
+
const requireFromSelf = createRequire2(import.meta.url);
|
|
202
203
|
esbuild = requireFromSelf("esbuild");
|
|
203
204
|
}
|
|
204
205
|
const out = esbuild.buildSync({ entryPoints: [configPath], bundle: false, write: false, format: "esm", target: "node18" });
|
|
205
206
|
const jsFile = `${tmpBase}.mjs`;
|
|
206
207
|
fs3.writeFileSync(jsFile, rewriteSelfImports(out.outputFiles[0].text));
|
|
207
|
-
mod = await importConfigs(
|
|
208
|
+
mod = await importConfigs(pathToFileURL2(jsFile).href);
|
|
208
209
|
}
|
|
209
210
|
} else {
|
|
210
211
|
const jsFile = `${tmpBase}.mjs`;
|
|
211
212
|
fs3.writeFileSync(jsFile, source);
|
|
212
|
-
mod = await importConfigs(
|
|
213
|
+
mod = await importConfigs(pathToFileURL2(jsFile).href);
|
|
213
214
|
}
|
|
214
215
|
}
|
|
215
216
|
const cfg = mod.default;
|
|
@@ -287,6 +288,219 @@ var init_config = __esm({
|
|
|
287
288
|
}
|
|
288
289
|
});
|
|
289
290
|
|
|
291
|
+
// src/app-config.ts
|
|
292
|
+
import { createRequire } from "node:module";
|
|
293
|
+
import { pathToFileURL } from "node:url";
|
|
294
|
+
function appConfigError(what, cause, fix) {
|
|
295
|
+
throw new Error(`[fulgurjs:config] ${what}
|
|
296
|
+
\u6839\u56E0\uFF1A${cause}
|
|
297
|
+
\u4FEE\u6CD5\uFF1A${fix}`);
|
|
298
|
+
}
|
|
299
|
+
function isAggregateShape(value) {
|
|
300
|
+
return !!value && typeof value === "object" && Array.isArray(value.apps);
|
|
301
|
+
}
|
|
302
|
+
function fieldError(field, got, expect, example) {
|
|
303
|
+
appConfigError(
|
|
304
|
+
`fulgurjs.config.ts \u7684 ${field} \u5F62\u72B6\u4E0D\u5408\u6CD5\uFF08\u5B9E\u9645 ${JSON.stringify(got)}\uFF09`,
|
|
305
|
+
`CLI \u6309\u5355\u9879\u76EE\u5951\u7EA6\u8BFB\u53D6\uFF1A\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879\u5BF9\u8C61`,
|
|
306
|
+
`\u671F\u671B ${expect}\u3002\u793A\u4F8B\uFF1A
|
|
307
|
+
${example}`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
function validateAppOptions(options) {
|
|
311
|
+
if (typeof options.name !== "string" || options.name.trim() === "") {
|
|
312
|
+
fieldError(
|
|
313
|
+
"\u9ED8\u8BA4\u5BFC\u51FA name",
|
|
314
|
+
options.name,
|
|
315
|
+
"\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u8054\u90A6\u5BB9\u5668\u540D\uFF09",
|
|
316
|
+
`export default { name: 'my-app', exposes: { './pages/home': './src/views/Home.vue' } } satisfies FederationOptions`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
for (const legacyField of ["root", "apps", "deploy", "host", "remote"]) {
|
|
320
|
+
if (options[legacyField] !== void 0) {
|
|
321
|
+
appConfigError(
|
|
322
|
+
`\u9ED8\u8BA4\u5BFC\u51FA\u5305\u542B\u65E7\u805A\u5408/\u89D2\u8272\u58F3\u5B57\u6BB5 "${legacyField}"`,
|
|
323
|
+
"\u5355\u9879\u76EE\u5951\u7EA6\u7684\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879\uFF08name/exposes/setup/remotes/shared/\u2026\uFF09\uFF0C\u4E0D\u5305 host/remote \u89D2\u8272\u58F3\uFF0C\u4E5F\u6CA1\u6709 root/apps[]",
|
|
324
|
+
legacyField === "host" || legacyField === "remote" ? "\u628A host/remote \u5185\u7684\u5B57\u6BB5\u62CD\u5E73\u5230\u9876\u5C42\uFF1Ahost.remotes \u2192 remotes\uFF1Bremote.exposes \u2192 exposes\uFF1Bremote.setup \u2192 setup\uFF1Bhost.pages/remotePrefixes/deriveSpec \u2192 \u5177\u540D\u5BFC\u51FA hostPages" : `${legacyField} \u5C5E\u4E8E\u65E7\u805A\u5408\u914D\u7F6E\uFF08root + apps[]\uFF0C\u517C\u5BB9\u671F\u4FDD\u7559\uFF09\u3002\u5355\u9879\u76EE\u5F62\u6001\u8BF7\u5220\u9664\u8BE5\u5B57\u6BB5\uFF1B\u805A\u5408\u7528\u6CD5\u89C1 README\u300C\u5386\u53F2\u517C\u5BB9\u300D\u7AE0\u8282`
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function validateHostPages(value) {
|
|
330
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
331
|
+
fieldError("\u5177\u540D\u5BFC\u51FA hostPages", value, "\u5BF9\u8C61 { pages, remotePrefixes, deriveSpec? }", `export const hostPages = { pages, remotePrefixes, deriveSpec }`);
|
|
332
|
+
}
|
|
333
|
+
const hp = value;
|
|
334
|
+
if (!Array.isArray(hp.pages)) {
|
|
335
|
+
fieldError("hostPages.pages", hp.pages, "PageEntry[]\uFF08\u8DEF\u7531\u8868\u6570\u7EC4\uFF09", `export const hostPages = { pages: [{ route: '/remote-a/home', name: 'Home', title: '\u9996\u9875' }], remotePrefixes: { '/remote-a/': 'remote-a' } }`);
|
|
336
|
+
}
|
|
337
|
+
if (!hp.remotePrefixes || typeof hp.remotePrefixes !== "object") {
|
|
338
|
+
fieldError("hostPages.remotePrefixes", hp.remotePrefixes, "Record<\u8DEF\u7531\u524D\u7F00, \u8FDC\u7A0B\u5BB9\u5668\u540D>", `remotePrefixes: { '/remote-a/': 'remote-a' }`);
|
|
339
|
+
}
|
|
340
|
+
if (hp.deriveSpec !== void 0 && typeof hp.deriveSpec !== "function") {
|
|
341
|
+
fieldError("hostPages.deriveSpec", hp.deriveSpec, "\u51FD\u6570 (route) => spec \u6216\u7701\u7565", `deriveSpec: (route) => 'pages/' + route.split('/').filter((s) => !s.startsWith(':')).join('/')`);
|
|
342
|
+
}
|
|
343
|
+
return hp;
|
|
344
|
+
}
|
|
345
|
+
function validatePathsInsideApp(options, appRoot, fs3, path3) {
|
|
346
|
+
const checkModule = (field, value) => {
|
|
347
|
+
if (typeof value !== "string" || value.trim() === "") return;
|
|
348
|
+
if (/^(https?:)?\/\//.test(value) || path3.isAbsolute(value)) {
|
|
349
|
+
appConfigError(
|
|
350
|
+
`${field} "${value}" \u4E0D\u662F\u672C\u9879\u76EE\u5185\u7684\u6A21\u5757\u8DEF\u5F84`,
|
|
351
|
+
"exposes/setup \u7684\u503C\u662F\u76F8\u5BF9\u672C\u5E94\u7528\u6839\u76EE\u5F55\u7684\u6E90\u6587\u4EF6\u8DEF\u5F84\uFF08URL/\u7EDD\u5BF9\u8DEF\u5F84\u65E0\u6CD5\u5728\u72EC\u7ACB\u4ED3\u5E93\u95F4\u79FB\u690D\uFF09",
|
|
352
|
+
`\u6539\u4E3A\u76F8\u5BF9\u8DEF\u5F84\uFF0C\u5982 './src/views/Home.vue'\uFF08\u914D\u7F6E\u6587\u4EF6\u76EE\u5F55 = \u5E94\u7528\u6839 ${appRoot}\uFF09`
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
const abs = path3.resolve(appRoot, value);
|
|
356
|
+
if (!fs3.existsSync(abs)) {
|
|
357
|
+
appConfigError(
|
|
358
|
+
`${field} \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${value}`,
|
|
359
|
+
`\u6309\u5E94\u7528\u6839 ${appRoot} \u89E3\u6790\u540E\u672A\u627E\u5230\u8BE5\u6587\u4EF6`,
|
|
360
|
+
`\u6838\u5BF9\u76F8\u5BF9\u8DEF\u5F84\uFF08\u4EE5\u914D\u7F6E\u6587\u4EF6\u6240\u5728\u76EE\u5F55\u4E3A\u57FA\u51C6\uFF09\uFF1B\u6587\u4EF6\u88AB\u79FB\u52A8/\u5220\u9664\u65F6\u540C\u6B65\u66F4\u65B0 ${field}`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
const exposes = options.exposes;
|
|
365
|
+
if (exposes !== void 0 && (typeof exposes !== "object" || exposes === null || Array.isArray(exposes))) {
|
|
366
|
+
fieldError("exposes", exposes, 'Record<"./\u952E", "./\u6E90\u6587\u4EF6">', `exposes: { './pages/home': './src/views/Home.vue' }`);
|
|
367
|
+
}
|
|
368
|
+
for (const target of Object.values(exposes ?? {})) {
|
|
369
|
+
checkModule("exposes \u6761\u76EE", typeof target === "string" ? target : target?.import);
|
|
370
|
+
}
|
|
371
|
+
checkModule("setup", options.setup);
|
|
372
|
+
}
|
|
373
|
+
function resolveSelfEntry(configPath, spec) {
|
|
374
|
+
const tries = [() => createRequire(configPath).resolve(spec), () => createRequire(import.meta.url).resolve(spec)];
|
|
375
|
+
for (const t of tries) {
|
|
376
|
+
try {
|
|
377
|
+
return t();
|
|
378
|
+
} catch {
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return void 0;
|
|
382
|
+
}
|
|
383
|
+
function resolveSpec(spec, from) {
|
|
384
|
+
try {
|
|
385
|
+
return createRequire(from).resolve(spec);
|
|
386
|
+
} catch {
|
|
387
|
+
return void 0;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function resolveEsbuild(configPath) {
|
|
391
|
+
const esbuildOf = (base) => {
|
|
392
|
+
const direct = resolveSpec("esbuild", base);
|
|
393
|
+
if (direct) return createRequire(direct)("esbuild");
|
|
394
|
+
const viteEntry = resolveSpec("vite", base);
|
|
395
|
+
if (viteEntry) {
|
|
396
|
+
const viaVite = resolveSpec("esbuild", viteEntry);
|
|
397
|
+
if (viaVite) return createRequire(viaVite)("esbuild");
|
|
398
|
+
}
|
|
399
|
+
return void 0;
|
|
400
|
+
};
|
|
401
|
+
for (const base of [configPath, import.meta.url]) {
|
|
402
|
+
const got = esbuildOf(base);
|
|
403
|
+
if (got) return got;
|
|
404
|
+
}
|
|
405
|
+
appConfigError(
|
|
406
|
+
"\u65E0\u6CD5\u52A0\u8F7D esbuild\uFF08\u5355\u9879\u76EE\u914D\u7F6E\u52A0\u8F7D\u9700\u8981\u5B83\u8F6C\u8BD1 TS \u4E0E\u76F8\u5BF9\u5BFC\u5165\uFF09",
|
|
407
|
+
"\u914D\u7F6E\u5DE5\u7A0B\uFF08\u542B\u5176 vite \u4F9D\u8D56\u6811\uFF09\u4E0E CLI \u4F9D\u8D56\u6811\u4E2D\u90FD\u89E3\u6790\u4E0D\u5230 esbuild",
|
|
408
|
+
"\u9879\u76EE\u5185\u6709 vite \u4F9D\u8D56\u5373\u53EF\uFF08\u7ECF\u5176\u4F9D\u8D56\u6811\u89E3\u6790\uFF09\uFF1B\u786E\u5B9E\u7F3A\u5931\u65F6 npm i -D esbuild \u540E\u91CD\u8BD5"
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
async function loadAppConfig(configPath) {
|
|
412
|
+
const fs3 = await import("node:fs");
|
|
413
|
+
const os = await import("node:os");
|
|
414
|
+
const path3 = await import("node:path");
|
|
415
|
+
const abs = path3.resolve(configPath);
|
|
416
|
+
if (!fs3.existsSync(abs)) {
|
|
417
|
+
appConfigError(
|
|
418
|
+
`\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${abs}`,
|
|
419
|
+
"--config \u6307\u5411\u7684\u8DEF\u5F84\u5728\u672C\u673A\u4E0D\u5B58\u5728\uFF08\u76F8\u5BF9\u8DEF\u5F84\u4EE5 CLI \u8FDB\u7A0B cwd \u89E3\u6790\uFF09",
|
|
420
|
+
"\u6838\u5BF9\u8DEF\u5F84\uFF1B\u4ECE\u5E94\u7528\u6839\u76EE\u5F55\u8FD0\u884C\u65F6\u76F4\u63A5\u7528 fulgurjs.config.ts"
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
if (abs.endsWith(".json")) {
|
|
424
|
+
const parsed = JSON.parse(fs3.readFileSync(abs, "utf8"));
|
|
425
|
+
if (isAggregateShape(parsed)) {
|
|
426
|
+
const repo = await loadRepoConfig(abs);
|
|
427
|
+
return { kind: "repo", configPath: abs, appRoot: path3.dirname(abs), repo };
|
|
428
|
+
}
|
|
429
|
+
return finishAppShape(parsed, {}, abs, path3.dirname(abs), fs3, path3);
|
|
430
|
+
}
|
|
431
|
+
const esbuild = resolveEsbuild(abs);
|
|
432
|
+
const selfRedirect = {
|
|
433
|
+
name: "fulgurjs-self-redirect",
|
|
434
|
+
setup(build) {
|
|
435
|
+
build.onResolve({ filter: /^@fulgurjs\/federation(\/|$)/ }, (args) => {
|
|
436
|
+
const resolved = resolveSelfEntry(abs, args.path);
|
|
437
|
+
if (!resolved) {
|
|
438
|
+
return { errors: [{ text: `cannot resolve "${args.path}" from the config project or the CLI itself` }] };
|
|
439
|
+
}
|
|
440
|
+
return { path: resolved };
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
const out = await esbuild.build({
|
|
445
|
+
entryPoints: [abs],
|
|
446
|
+
bundle: true,
|
|
447
|
+
write: false,
|
|
448
|
+
format: "esm",
|
|
449
|
+
target: "node18",
|
|
450
|
+
platform: "node",
|
|
451
|
+
plugins: [selfRedirect],
|
|
452
|
+
logLevel: "silent"
|
|
453
|
+
});
|
|
454
|
+
const tmpDir = fs3.mkdtempSync(path3.join(os.tmpdir(), "fulgurjs-appcfg-"));
|
|
455
|
+
try {
|
|
456
|
+
const bundleFile = path3.join(tmpDir, "fulgurjs.config.bundle.mjs");
|
|
457
|
+
fs3.writeFileSync(bundleFile, out.outputFiles[0].text);
|
|
458
|
+
const mod = await import(`${pathToFileURL(bundleFile).href}?t=${Date.now()}`);
|
|
459
|
+
if (isAggregateShape(mod.default)) {
|
|
460
|
+
const repo = await loadRepoConfig(abs);
|
|
461
|
+
return { kind: "repo", configPath: abs, appRoot: path3.dirname(abs), repo };
|
|
462
|
+
}
|
|
463
|
+
return finishAppShape(mod.default, { hostPages: mod.hostPages }, abs, path3.dirname(abs), fs3, path3);
|
|
464
|
+
} finally {
|
|
465
|
+
fs3.rmSync(tmpDir, { recursive: true, force: true });
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
function finishAppShape(def, named, configPath, appRoot, fs3, path3) {
|
|
469
|
+
if (def === void 0 || def === null) {
|
|
470
|
+
appConfigError(
|
|
471
|
+
"fulgurjs.config.ts \u6CA1\u6709\u53EF\u7528\u7684\u9ED8\u8BA4\u5BFC\u51FA",
|
|
472
|
+
"\u5355\u9879\u76EE\u5951\u7EA6\uFF1A\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879\u5BF9\u8C61\uFF08satisfies FederationOptions\uFF09",
|
|
473
|
+
`export default { name: 'my-app', ... } satisfies FederationOptions`
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
if (typeof def !== "object" || Array.isArray(def)) {
|
|
477
|
+
fieldError("\u9ED8\u8BA4\u5BFC\u51FA", def, "\u5BF9\u8C61\uFF08federation() \u9009\u9879\uFF09", `export default { name: 'my-app', exposes: { /* \u2026 */ } } satisfies FederationOptions`);
|
|
478
|
+
}
|
|
479
|
+
const options = def;
|
|
480
|
+
validateAppOptions(options);
|
|
481
|
+
validatePathsInsideApp(options, appRoot, fs3, path3);
|
|
482
|
+
const hostPages = named.hostPages !== void 0 ? validateHostPages(named.hostPages) : void 0;
|
|
483
|
+
return {
|
|
484
|
+
kind: "app",
|
|
485
|
+
configPath,
|
|
486
|
+
appRoot,
|
|
487
|
+
options,
|
|
488
|
+
hostPages
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function roleOfOptions(options) {
|
|
492
|
+
const hasRemotes = Object.keys(options.remotes ?? {}).length > 0;
|
|
493
|
+
const hasProvides = Object.keys(options.exposes ?? {}).length > 0 || !!options.setup;
|
|
494
|
+
if (hasRemotes && hasProvides) return "dual";
|
|
495
|
+
return hasRemotes ? "host" : "remote";
|
|
496
|
+
}
|
|
497
|
+
var init_app_config = __esm({
|
|
498
|
+
"src/app-config.ts"() {
|
|
499
|
+
"use strict";
|
|
500
|
+
init_config();
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
290
504
|
// src/init.ts
|
|
291
505
|
var init_exports = {};
|
|
292
506
|
__export(init_exports, {
|
|
@@ -329,12 +543,23 @@ ${Object.entries(app.shared).map(([k, v]) => {
|
|
|
329
543
|
return ` '${k}': { ${opts.join(", ")} },`;
|
|
330
544
|
}).join("\n")}
|
|
331
545
|
},
|
|
332
|
-
` :
|
|
333
|
-
`;
|
|
546
|
+
` : "";
|
|
334
547
|
return `federation({
|
|
335
548
|
name: '${app.name}',
|
|
336
549
|
${remotesBlock}${exposesBlock}${setupBlock}${sharedBlock}})`;
|
|
337
550
|
}
|
|
551
|
+
function viteSnippetForAppMode(appRoot) {
|
|
552
|
+
return `// ${appRoot}/vite.config.ts\uFF08\u8054\u90A6\u76F8\u5173\u884C\uFF1B\u5176\u4F59 Vite \u914D\u7F6E\u539F\u6837\u4FDD\u7559\uFF09
|
|
553
|
+
import federation from '@fulgurjs/federation'
|
|
554
|
+
import fulgurjsConfig from './fulgurjs.config'
|
|
555
|
+
|
|
556
|
+
export default defineConfig({
|
|
557
|
+
plugins: [
|
|
558
|
+
// ...\u539F\u6709\u63D2\u4EF6,
|
|
559
|
+
federation(fulgurjsConfig),
|
|
560
|
+
],
|
|
561
|
+
})`;
|
|
562
|
+
}
|
|
338
563
|
function nginxSnippetFor(cfg) {
|
|
339
564
|
const listen = cfg.deploy?.listen ?? 8080;
|
|
340
565
|
const webRoot = cfg.deploy?.webRoot ?? "/var/www/your-site";
|
|
@@ -360,7 +585,7 @@ function nginxSnippetFor(cfg) {
|
|
|
360
585
|
}`;
|
|
361
586
|
}
|
|
362
587
|
).join("\n\n");
|
|
363
|
-
return `# \u8054\u90A6\u7AD9\u70B9\
|
|
588
|
+
return `# \u8054\u90A6\u7AD9\u70B9\u6837\u677F\uFF08\u6253\u5370\u6837\u677F\uFF0C\u4E0D\u5199\u6587\u4EF6\u3002\u8981\u70B9\uFF1AremoteEntry/manifest/index.html \u5FC5\u987B no-cache\u2014\u2014
|
|
364
589
|
# \u6587\u4EF6\u540D\u56FA\u5B9A\u800C\u5185\u5BB9\u6BCF\u6B21\u6784\u5EFA\u53D8\u5316\uFF0Cimmutable \u957F\u7F13\u5B58\u4F1A\u8BA9\u6D4F\u89C8\u5668\u6301\u65E7\u5165\u53E3\u3001\u91CD\u90E8\u7F72\u540E\u5168 404\uFF1B
|
|
365
590
|
# \u5E26 hash \u7684 assets \u624D\u914D\u957F\u7F13\u5B58\uFF1B\u8DE8\u6E90\u90E8\u7F72\u65F6\u4FDD\u7559 Access-Control-Allow-Origin\uFF09
|
|
366
591
|
server {
|
|
@@ -393,99 +618,123 @@ function appSummary(app) {
|
|
|
393
618
|
}
|
|
394
619
|
return lines.join("\n");
|
|
395
620
|
}
|
|
621
|
+
function appModeSummary(loaded) {
|
|
622
|
+
const options = loaded.options;
|
|
623
|
+
const roleText = { host: "\u5BBF\u4E3B", remote: "\u8FDC\u7A0B", dual: "\u5BBF\u4E3B+\u8FDC\u7A0B\uFF08\u53CC\u89D2\u8272\uFF09" }[Object.keys(options.remotes ?? {}).length > 0 && (Object.keys(options.exposes ?? {}).length > 0 || !!options.setup) ? "dual" : Object.keys(options.remotes ?? {}).length > 0 ? "host" : "remote"];
|
|
624
|
+
const lines = [];
|
|
625
|
+
lines.push(` ${options.name}\uFF08${roleText}\uFF0C\u5355\u9879\u76EE\u914D\u7F6E\uFF0C\u76EE\u5F55 ${loaded.appRoot}\uFF1Bbase/dev \u7AEF\u53E3\u7531 vite.config.ts \u7BA1\u7406\uFF09`);
|
|
626
|
+
for (const [k, v] of Object.entries(options.remotes ?? {})) {
|
|
627
|
+
const cfg = typeof v === "string" ? { dev: v, prod: v } : v;
|
|
628
|
+
lines.push(` \u6D88\u8D39\u8FDC\u7A0B ${k} \u2192 dev ${cfg.dev ?? ""} / prod ${cfg.prod ?? ""}`);
|
|
629
|
+
}
|
|
630
|
+
if (options.exposes) {
|
|
631
|
+
lines.push(` exposes\uFF08${Object.keys(options.exposes).length}\uFF09\uFF1A${Object.keys(options.exposes).join("\u3001")}`);
|
|
632
|
+
}
|
|
633
|
+
if (options.setup) {
|
|
634
|
+
lines.push(` setup\uFF08\u53EF\u9009\u8FDC\u7A0B\u521D\u59CB\u5316\uFF09\uFF1A${options.setup}`);
|
|
635
|
+
}
|
|
636
|
+
if (loaded.hostPages) {
|
|
637
|
+
lines.push(` \u9875\u9762\u8DEF\u7531\u8868\uFF08hostPages \u5177\u540D\u5BFC\u51FA\uFF09\uFF1A${loaded.hostPages.pages.length} \u6761`);
|
|
638
|
+
} else {
|
|
639
|
+
lines.push(" \u9875\u9762\u8DEF\u7531\u8868\uFF1A\uFF08\u65E0 hostPages \u5BFC\u51FA\u2014\u2014\u7EAF\u8FDC\u7A0B\u5E94\u7528\u65E0\u9700\uFF1B\u5BBF\u4E3B\u5EFA\u8BAE\u63D0\u4F9B\uFF09");
|
|
640
|
+
}
|
|
641
|
+
return lines;
|
|
642
|
+
}
|
|
396
643
|
async function inspectConfig(configPath) {
|
|
397
|
-
const
|
|
644
|
+
const loaded = await loadAppConfig(configPath);
|
|
398
645
|
const out = [];
|
|
399
|
-
|
|
646
|
+
if (loaded.kind === "app") {
|
|
647
|
+
out.push(`${MARK} \u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\uFF1A\u5355\u9879\u76EE\u5F62\u6001\uFF08\u9ED8\u8BA4\u5BFC\u51FA = federation() \u9009\u9879\uFF09`);
|
|
648
|
+
out.push("\u5E94\u7528\u6458\u8981\uFF1A");
|
|
649
|
+
out.push(...appModeSummary(loaded));
|
|
650
|
+
out.push("\n\u2500\u2500 vite.config.ts plugins \u63A5\u5165\u5757\uFF08\u8FD9\u5C31\u662F\u5168\u90E8\u8054\u90A6\u63A5\u5165\u4EE3\u7801\uFF09 \u2500\u2500");
|
|
651
|
+
out.push(viteSnippetForAppMode(loaded.appRoot));
|
|
652
|
+
out.push("\n\u2500\u2500 \u63A5\u5165\u6838\u5BF9\u6E05\u5355\uFF08\u8054\u90A6\u901A\u7528\u9879\uFF0C\u4E0E\u5177\u4F53\u9879\u76EE\u65E0\u5173\uFF09 \u2500\u2500");
|
|
653
|
+
out.push(...COMMON_CHECKLIST);
|
|
654
|
+
return out.join("\n");
|
|
655
|
+
}
|
|
656
|
+
const cfg = loaded.repo ?? await loadRepoConfig(loaded.configPath);
|
|
657
|
+
out.push(`${MARK} \u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\uFF1Aroot=${cfg.root}\uFF0Capps=${cfg.apps.length}\u3010\u65E7\u805A\u5408\u914D\u7F6E\u5F62\u6001\uFF08root+apps[]\uFF09\uFF0C\u517C\u5BB9\u671F\u4FDD\u7559\uFF1B\u65B0\u9879\u76EE\u63A8\u8350\u6BCF\u9879\u76EE\u4E00\u4EFD\u5355\u9879\u76EE\u914D\u7F6E\uFF0C\u89C1 README\u3011`);
|
|
400
658
|
out.push("\u5E94\u7528\u6458\u8981\uFF1A");
|
|
401
659
|
for (const app of cfg.apps) out.push(appSummary(app));
|
|
402
|
-
out.push("\n\u2500\u2500 \u5404\u5E94\u7528 vite.config.ts plugins \u7C98\u8D34\u5757 \u2500\u2500");
|
|
660
|
+
out.push("\n\u2500\u2500 \u5404\u5E94\u7528 vite.config.ts plugins \u7C98\u8D34\u5757\uFF08\u65E7\u805A\u5408\u5F62\u6001\u9700\u7ECF loadRepoConfig/federationOptionsForApp \u8F6C\u6362\uFF09 \u2500\u2500");
|
|
403
661
|
for (const app of cfg.apps) {
|
|
404
662
|
out.push(`
|
|
405
663
|
# ${app.path}\uFF08${app.name}\uFF09`);
|
|
406
664
|
out.push(viteSnippetFor(app));
|
|
407
665
|
}
|
|
408
|
-
out.push("\n\u2500\u2500 NGINX \u7AD9\u70B9\
|
|
666
|
+
out.push("\n\u2500\u2500 NGINX \u7AD9\u70B9\u6837\u677F\uFF08\u6253\u5370\u6837\u677F\uFF0C\u4E0D\u5199\u6587\u4EF6\uFF09 \u2500\u2500");
|
|
409
667
|
out.push(nginxSnippetFor(cfg));
|
|
410
668
|
out.push("\n\u2500\u2500 \u63A5\u5165\u6838\u5BF9\u6E05\u5355\uFF08\u8054\u90A6\u901A\u7528\u9879\uFF0C\u4E0E\u5177\u4F53\u9879\u76EE\u65E0\u5173\uFF09 \u2500\u2500");
|
|
411
|
-
out.push(
|
|
412
|
-
out.push("2. expose \u4E00\u5F8B\u6307\u5411\u72EC\u7ACB\u9875\uFF08\u9875\u9762\u4ECE\u8DEF\u7531\u53D6\u53C2\uFF09\uFF1B\u7EC4\u4EF6\u9700\u8981\u5FC5\u586B props \u65F6\u7ED9\u9ED8\u8BA4\u503C\uFF08BLD-003\uFF09");
|
|
413
|
-
out.push("3. shared \u91CC vue / vue-router / pinia \u5EFA\u8BAE singleton: true\u2014\u2014\u8DE8\u5E94\u7528\u5FC5\u987B\u540C\u5B9E\u4F8B\uFF08\u5168\u5C40\u54CD\u5E94\u6027\u3001getActivePinia\u3001\u8DEF\u7531\u6CE8\u5165\uFF09");
|
|
414
|
-
out.push("4. \u8FDC\u7A0B\u9700\u8981\u542F\u52A8\u671F\u521D\u59CB\u5316\uFF08\u5168\u5C40\u7EC4\u4EF6/\u6837\u5F0F/locale \u7B49\uFF09\u65F6\uFF0C\u5728 federation({ setup }) \u58F0\u660E\u5165\u53E3\u6587\u4EF6\uFF1A");
|
|
415
|
-
out.push(" \u9ED8\u8BA4\u5BFC\u51FA setup(context) \u5E94\u7528\u7EA7\u6267\u884C\u4E00\u6B21\uFF08\u5BB9\u5668\u9996\u6B21\u88AB\u52A0\u8F7D\u4E1A\u52A1\u6A21\u5757\u524D\uFF09\uFF1B\u53EF\u9009\u5177\u540D\u5BFC\u51FA onSession(context)");
|
|
416
|
-
out.push(" \u6309\u5BBF\u4E3B sessionKey \u53BB\u91CD\u6267\u884C\uFF08\u6362\u8D26\u53F7/\u91CD\u767B\u81EA\u52A8\u91CD\u8DD1\uFF09\u3002\u5BBF\u4E3B\u65E0\u9700\u518D\u624B\u5199\u300CloadRemote \u542F\u52A8\u5668\u5E76\u8C03\u7528\u300D\uFF1B");
|
|
417
|
-
out.push(" \u8DE8\u5E94\u7528\u4F20\u503C\u7EDF\u4E00\u8D70 @fulgurjs/federation/runtime \u7684 context \u51FD\u6570\uFF1A\u5BBF\u4E3B provideAppContext \u5199\u5165");
|
|
418
|
-
out.push(" \uFF08\u9000\u51FA\u65F6 clearAppContext \u6E05\u7406\uFF09\uFF0C\u8FDC\u7A0B setup/onSession \u7528 getAppContext / requireAppContext \u6D88\u8D39");
|
|
419
|
-
out.push("5. \u5E94\u7528\u4EE3\u7801\u552F\u4E00 API \u5165\u53E3\uFF1Aimport { loadRemote, provideAppContext, getAppContext, clearAppContext, definePages, createHostPages, remoteSchema, remoteComponent } from '@fulgurjs/federation/runtime'");
|
|
420
|
-
out.push('6. dev \u51B7\u542F\u52A8\u9996\u8F6E 30~60s \u6709\u9884\u6784\u5EFA\u7A97\u53E3\uFF08\u77AC\u65F6 504/"ce"\uFF0CDEV-010\uFF09\uFF1A\u5148\u771F\u5B9E\u6253\u5F00\u9875\u9762\u9884\u70ED\u518D\u505A\u65AD\u8A00');
|
|
421
|
-
out.push("7. \u90E8\u7F72\u540E\u4F53\u68C0\uFF1Afulgurjs doctor --base <URL> --apps <\u5E94\u7528...>\uFF08\u7F13\u5B58\u5934/\u8D44\u6E90\u5F62\u6001/CORS/chunk \u53EF\u8FBE/\u7248\u672C skew\uFF09\uFF1B");
|
|
422
|
-
out.push(" \u914D\u7F6E\u89E3\u91CA\uFF1Afulgurjs explain --config fulgurjs.config.ts --app <\u5E94\u7528>\uFF1B\u9875\u9762\u5951\u7EA6\u6838\u5BF9\uFF1Afulgurjs check-pages --config <...> --app <\u5BBF\u4E3B>");
|
|
423
|
-
out.push("8. \u90E8\u7F72\u8BED\u4E49\uFF1AremoteEntry/manifest/index.html \u5FC5\u987B no-cache\uFF08\u4E25\u7981 immutable\uFF09\uFF1B\u5E26 hash \u7684 assets \u957F\u7F13\u5B58");
|
|
669
|
+
out.push(...COMMON_CHECKLIST);
|
|
424
670
|
return out.join("\n");
|
|
425
671
|
}
|
|
426
|
-
var MARK, STARTER_CONFIG,
|
|
672
|
+
var MARK, STARTER_CONFIG, COMMON_CHECKLIST;
|
|
427
673
|
var init_init = __esm({
|
|
428
674
|
"src/init.ts"() {
|
|
429
675
|
"use strict";
|
|
676
|
+
init_app_config();
|
|
430
677
|
init_config();
|
|
431
678
|
MARK = "[fulgurjs:init]";
|
|
432
|
-
STARTER_CONFIG = `// fulgurjs.config.ts \u2014\u2014 @fulgurjs/federation \u63A5\u5165\u914D\u7F6E\uFF08\
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
import
|
|
679
|
+
STARTER_CONFIG = `// fulgurjs.config.ts \u2014\u2014 @fulgurjs/federation \u5355\u9879\u76EE\u63A5\u5165\u914D\u7F6E\uFF08\u4E00\u9879\u76EE\u4E00\u4EFD\uFF0C\u53EF\u5165\u5E93\u3001\u53EF\u590D\u8DD1\uFF09
|
|
680
|
+
//
|
|
681
|
+
// Vite \u63A5\u5165\uFF08\u672C\u9879\u76EE vite.config.ts \u53EA\u9700\u4E24\u884C\u8054\u90A6\u76F8\u5173\u4EE3\u7801\uFF09\uFF1A
|
|
682
|
+
// import federation from '@fulgurjs/federation'
|
|
683
|
+
// import fulgurjsConfig from './fulgurjs.config'
|
|
684
|
+
// // plugins: [ ...\u539F\u6709\u63D2\u4EF6, federation(fulgurjsConfig) ]
|
|
685
|
+
//
|
|
686
|
+
// CLI\uFF08\u7EAF\u672C\u5730\uFF0C\u65E0\u7F51\u7EDC\uFF09\uFF1A
|
|
687
|
+
// npx fulgurjs explain # \u89E3\u91CA\u672C\u5E94\u7528\u6709\u6548\u5F62\u6001\u4E0E\u52A0\u8F7D\u94FE
|
|
688
|
+
// npx fulgurjs check-pages # \u5BBF\u4E3B\u9875\u9762\u8868 \u2194 \u8FDC\u7A0B manifest \u5951\u7EA6\u6838\u5BF9
|
|
689
|
+
// npx fulgurjs doctor --base http://<\u7AD9\u70B9> --apps <\u5BB9\u5668\u540D> # \u90E8\u7F72\u4F53\u68C0
|
|
690
|
+
import type { FederationOptions } from '@fulgurjs/federation'
|
|
436
691
|
|
|
437
|
-
export default
|
|
438
|
-
// \
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
base: '/remote-a',
|
|
468
|
-
remote: {
|
|
469
|
-
exposes: {
|
|
470
|
-
'./pages/remote-a/home': './src/views/Home.vue',
|
|
471
|
-
'./pages/remote-a/detail': './src/views/Detail.vue',
|
|
472
|
-
},
|
|
473
|
-
// \u53EF\u9009\uFF1A\u8FDC\u7A0B\u9700\u8981\u542F\u52A8\u671F\u521D\u59CB\u5316\uFF08\u5168\u5C40\u7EC4\u4EF6/\u6837\u5F0F/locale\uFF09\u65F6\u58F0\u660E\u5165\u53E3\u6587\u4EF6\u2014\u2014
|
|
474
|
-
// \u9ED8\u8BA4\u5BFC\u51FA setup(context) \u5E94\u7528\u7EA7\u6267\u884C\u4E00\u6B21\uFF1B\u53EF\u9009\u5177\u540D\u5BFC\u51FA onSession(context)
|
|
475
|
-
// \u6309\u5BBF\u4E3B sessionKey \u53BB\u91CD\u6267\u884C\u3002\u7F3A\u7701 = \u65E0\u521D\u59CB\u5316\u884C\u4E3A\uFF08\u666E\u901A expose \u8BED\u4E49\u4E0D\u53D8\uFF09
|
|
476
|
-
// setup: './src/fulgurjs/setup.ts',
|
|
477
|
-
},
|
|
478
|
-
},
|
|
479
|
-
],
|
|
480
|
-
// \u90E8\u7F72\u4FE1\u606F\uFF08\u53EF\u9009\uFF09\uFF1A\u4EC5\u4F9B init \u8F93\u51FA NGINX \u6837\u677F\u65F6\u4F7F\u7528
|
|
481
|
-
deploy: { webRoot: '/var/www/your-site', listen: 8080 },
|
|
482
|
-
})
|
|
692
|
+
export default {
|
|
693
|
+
// \u8054\u90A6\u5BB9\u5668\u540D\uFF08\u8FDC\u7A0B\u5F15\u7528\u5B83\u65F6\u7528\u8FD9\u4E2A\u540D\uFF1B\u540C\u4E00\u9875\u9762\u5185\u552F\u4E00\uFF09
|
|
694
|
+
name: 'my-app',
|
|
695
|
+
// \u672C\u5E94\u7528\u5BF9\u5916\u66B4\u9732\u7684\u6A21\u5757\uFF1A'./\u952E' \u2192 \u76F8\u5BF9\u672C\u9879\u76EE\u6839\u7684\u6E90\u6587\u4EF6\u8DEF\u5F84
|
|
696
|
+
exposes: {
|
|
697
|
+
'./pages/home': './src/views/Home.vue',
|
|
698
|
+
},
|
|
699
|
+
// \u672C\u5E94\u7528\u6D88\u8D39\u7684\u8FDC\u7A0B\uFF08\u952E = import \u524D\u7F00\uFF1Bdev/prod \u5730\u5740\u4E8C\u6BB5\u5F0F\uFF0C\u5355\u5730\u5740\u5B57\u7B26\u4E32\u4E5F\u884C\uFF09
|
|
700
|
+
remotes: {
|
|
701
|
+
'remote-a': { dev: 'http://localhost:5174/remote-a', prod: '/remote-a' },
|
|
702
|
+
},
|
|
703
|
+
// \u53EF\u9009\uFF1A\u8FDC\u7A0B\u9700\u8981\u542F\u52A8\u671F\u521D\u59CB\u5316\uFF08\u5168\u5C40\u6837\u5F0F/\u7EC4\u4EF6/locale\uFF09\u65F6\u58F0\u660E\u5165\u53E3\u6587\u4EF6\u2014\u2014
|
|
704
|
+
// \u9ED8\u8BA4\u5BFC\u51FA setup(context) \u5E94\u7528\u7EA7\u6267\u884C\u4E00\u6B21\uFF1B\u53EF\u9009\u5177\u540D\u5BFC\u51FA onSession(context)
|
|
705
|
+
// \u6309\u5BBF\u4E3B sessionKey \u53BB\u91CD\u6267\u884C\u3002\u7F3A\u7701 = \u65E0\u521D\u59CB\u5316\u884C\u4E3A\uFF08\u666E\u901A expose \u8BED\u4E49\u4E0D\u53D8\uFF09
|
|
706
|
+
// setup: './src/fulgurjs/setup.ts',
|
|
707
|
+
shared: {
|
|
708
|
+
vue: { singleton: true, requiredVersion: '^3.4.0' },
|
|
709
|
+
'vue-router': { singleton: true, requiredVersion: '^4.4.5' },
|
|
710
|
+
pinia: { singleton: true, requiredVersion: '^2.1.7' },
|
|
711
|
+
},
|
|
712
|
+
} satisfies FederationOptions
|
|
713
|
+
|
|
714
|
+
// \u2500\u2500 \u4EE5\u4E0B\u4EC5\u4F9B CLI explain/check-pages \u8BFB\u53D6\uFF08\u4E0D\u662F federation() \u7684\u53C2\u6570\uFF09\u2500\u2500
|
|
715
|
+
// \u5BBF\u4E3B\u5E94\u7528\uFF1A\u628A\u9875\u9762\u8DEF\u7531\u8868\u4EE5\u5177\u540D\u5BFC\u51FA hostPages \u63D0\u4F9B\u7ED9 CLI\uFF0C\u4E0E\u8FD0\u884C\u65F6 createHostPages
|
|
716
|
+
// \u6D88\u8D39\u540C\u4E00\u4EFD\u6570\u636E\u6A21\u5757\uFF08\u552F\u4E00\u624B\u5DE5\u7EF4\u62A4\u4F4D\u7F6E\uFF1B\u7EAF\u8FDC\u7A0B\u5E94\u7528\u5220\u9664\u672C\u6BB5\u5373\u53EF\uFF09\u3002
|
|
717
|
+
// \u7EAF\u6570\u636E\u6A21\u5757\u793A\u4F8B src/fulgurjs/host/pages.data.ts\uFF1A
|
|
718
|
+
// export const remotePrefixes = { '/remote-a/': 'remote-a' }
|
|
719
|
+
// export const pages = [{ route: '/remote-a/home', name: 'Home', title: '\u9996\u9875' }]
|
|
720
|
+
// import { pages, remotePrefixes } from './src/fulgurjs/host/pages.data'
|
|
721
|
+
// export const hostPages = { pages, remotePrefixes }
|
|
483
722
|
`;
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
723
|
+
COMMON_CHECKLIST = [
|
|
724
|
+
"1. \u5B89\u88C5\u4F9D\u8D56\uFF1Anpm/pnpm add @fulgurjs/federation",
|
|
725
|
+
"2. expose \u4E00\u5F8B\u6307\u5411\u72EC\u7ACB\u9875\uFF08\u9875\u9762\u4ECE\u8DEF\u7531\u53D6\u53C2\uFF09\uFF1B\u7EC4\u4EF6\u9700\u8981\u5FC5\u586B props \u65F6\u7ED9\u9ED8\u8BA4\u503C\uFF08BLD-003\uFF09",
|
|
726
|
+
"3. shared \u91CC vue / vue-router / pinia \u5EFA\u8BAE singleton: true\u2014\u2014\u8DE8\u5E94\u7528\u5FC5\u987B\u540C\u5B9E\u4F8B\uFF08\u5168\u5C40\u54CD\u5E94\u6027\u3001getActivePinia\u3001\u8DEF\u7531\u6CE8\u5165\uFF09",
|
|
727
|
+
"4. \u8FDC\u7A0B\u9700\u8981\u542F\u52A8\u671F\u521D\u59CB\u5316\uFF08\u5168\u5C40\u7EC4\u4EF6/\u6837\u5F0F/locale \u7B49\uFF09\u65F6\uFF0C\u5728 fulgurjs.config.ts \u7684 setup \u58F0\u660E\u5165\u53E3\u6587\u4EF6\uFF1A",
|
|
728
|
+
" \u9ED8\u8BA4\u5BFC\u51FA setup(context) \u5E94\u7528\u7EA7\u6267\u884C\u4E00\u6B21\uFF08\u5BB9\u5668\u9996\u6B21\u88AB\u52A0\u8F7D\u4E1A\u52A1\u6A21\u5757\u524D\uFF09\uFF1B\u53EF\u9009\u5177\u540D\u5BFC\u51FA onSession(context)",
|
|
729
|
+
" \u6309\u5BBF\u4E3B sessionKey \u53BB\u91CD\u6267\u884C\uFF08\u6362\u8D26\u53F7/\u91CD\u767B\u81EA\u52A8\u91CD\u8DD1\uFF09\u3002\u5BBF\u4E3B\u65E0\u9700\u518D\u624B\u5199\u300CloadRemote \u542F\u52A8\u5668\u5E76\u8C03\u7528\u300D\uFF1B",
|
|
730
|
+
" \u8DE8\u5E94\u7528\u4F20\u503C\u7EDF\u4E00\u8D70 @fulgurjs/federation/runtime \u7684 context \u51FD\u6570\uFF1A\u5BBF\u4E3B provideAppContext \u5199\u5165",
|
|
731
|
+
" \uFF08\u9000\u51FA\u65F6 clearAppContext \u6E05\u7406\uFF09\uFF0C\u8FDC\u7A0B setup/onSession \u7528 getAppContext / requireAppContext \u6D88\u8D39",
|
|
732
|
+
"5. \u5E94\u7528\u4EE3\u7801\u552F\u4E00 API \u5165\u53E3\uFF1Aimport { loadRemote, provideAppContext, getAppContext, clearAppContext, definePages, createHostPages, remoteSchema, remoteComponent } from '@fulgurjs/federation/runtime'",
|
|
733
|
+
'6. dev \u51B7\u542F\u52A8\u9996\u8F6E 30~60s \u6709\u9884\u6784\u5EFA\u7A97\u53E3\uFF08\u77AC\u65F6 504/"ce"\uFF0CDEV-010\uFF09\uFF1A\u5148\u771F\u5B9E\u6253\u5F00\u9875\u9762\u9884\u70ED\u518D\u505A\u65AD\u8A00',
|
|
734
|
+
"7. \u914D\u7F6E\u89E3\u91CA\uFF1Afulgurjs explain\uFF08\u5355\u9879\u76EE\u5F62\u6001\u514D --app\uFF09\uFF1B\u9875\u9762\u5951\u7EA6\u6838\u5BF9\uFF1Afulgurjs check-pages\uFF08\u5BBF\u4E3B\u9879\u76EE\u8FD0\u884C\uFF0C--manifest/--site \u6307\u5B9A\u8FDC\u7A0B manifest \u6765\u6E90\uFF09\uFF1B",
|
|
735
|
+
" \u90E8\u7F72\u4F53\u68C0\uFF1Afulgurjs doctor --base <URL> --apps <\u5BB9\u5668\u540D...>",
|
|
736
|
+
"8. \u90E8\u7F72\u8BED\u4E49\uFF1AremoteEntry/manifest/index.html \u5FC5\u987B no-cache\uFF08\u4E25\u7981 immutable\uFF09\uFF1B\u5E26 hash \u7684 assets \u957F\u7F13\u5B58"
|
|
737
|
+
];
|
|
489
738
|
}
|
|
490
739
|
});
|
|
491
740
|
|
|
@@ -633,6 +882,19 @@ function pageMappings(app) {
|
|
|
633
882
|
return null;
|
|
634
883
|
};
|
|
635
884
|
const derive = app.host?.deriveSpec ?? ((route) => route.split("/").filter(Boolean).slice(1).filter((s) => !s.startsWith(":")).join("/"));
|
|
885
|
+
return mappingsOf({ pages, remotePrefixes: app.host?.remotePrefixes ?? {}, deriveSpec: app.host?.deriveSpec }, derive);
|
|
886
|
+
}
|
|
887
|
+
function mappingsOf(hp, deriveFallback) {
|
|
888
|
+
const pages = hp.pages ?? [];
|
|
889
|
+
const prefixes = Object.entries(hp.remotePrefixes ?? {}).sort((a, b) => b[0].length - a[0].length);
|
|
890
|
+
const remoteOf = (route) => {
|
|
891
|
+
for (const [prefix, name] of prefixes) {
|
|
892
|
+
const p = prefix.endsWith("/") ? prefix : `${prefix}/`;
|
|
893
|
+
if (route.startsWith(p) || `${route}/` === p) return name;
|
|
894
|
+
}
|
|
895
|
+
return null;
|
|
896
|
+
};
|
|
897
|
+
const derive = hp.deriveSpec ?? deriveFallback;
|
|
636
898
|
const out = [];
|
|
637
899
|
for (const page of pages) {
|
|
638
900
|
const remote = remoteOf(page.route);
|
|
@@ -642,8 +904,65 @@ function pageMappings(app) {
|
|
|
642
904
|
}
|
|
643
905
|
return out;
|
|
644
906
|
}
|
|
645
|
-
|
|
646
|
-
|
|
907
|
+
function remotesOfOptions(options) {
|
|
908
|
+
return Object.entries(options.remotes ?? {}).map(([key, v]) => {
|
|
909
|
+
const cfg = typeof v === "string" ? { external: v } : v;
|
|
910
|
+
return { key, dev: String(cfg.dev ?? cfg.external ?? ""), prod: String(cfg.prod ?? cfg.external ?? "") };
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
function sharedOfOptions(options) {
|
|
914
|
+
const shared = options.shared;
|
|
915
|
+
if (!shared) return [];
|
|
916
|
+
if (Array.isArray(shared)) {
|
|
917
|
+
return shared.map((name) => ({ name, singleton: false, requiredVersion: false }));
|
|
918
|
+
}
|
|
919
|
+
return Object.entries(shared).map(([name, v]) => {
|
|
920
|
+
const hint = typeof v === "string" ? { requiredVersion: v } : v ?? {};
|
|
921
|
+
return {
|
|
922
|
+
name,
|
|
923
|
+
singleton: !!hint.singleton,
|
|
924
|
+
requiredVersion: hint.requiredVersion ?? false
|
|
925
|
+
};
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
function chainLines(options, role) {
|
|
929
|
+
const chain = [];
|
|
930
|
+
chain.push(role === "remote" ? "\u88AB\u5BBF\u4E3B\u6D88\u8D39\uFF1AremoteEntry/\u5171\u4EAB\u4F9D\u8D56\u52A0\u8F7D \u2192 \u5BBF\u4E3B\u9996\u6B21 loadRemote \u672C\u5E94\u7528\u6A21\u5757\u65F6\u6267\u884C\u53EF\u9009 setup/onSession \u2192 \u9875\u9762\u6A21\u5757\u5728\u5BBF\u4E3B\u5E03\u5C40\u5185\u6E32\u67D3" : "\u5BBF\u4E3B\u63D0\u4F9B AppContext\uFF08provideAppContext\uFF0C\u542B sessionKey\uFF09\u2192 \u52A0\u8F7D remoteEntry/\u5171\u4EAB\u4F9D\u8D56 \u2192 \u9996\u6B21 loadRemote \u6267\u884C\u8BE5\u8FDC\u7A0B\u53EF\u9009 setup/onSession \u2192 \u53D6\u5F97\u9875\u9762\u6A21\u5757 \u2192 \u5BBF\u4E3B\u5E03\u5C40\u6E32\u67D3");
|
|
931
|
+
if (options.setup) {
|
|
932
|
+
chain.push(`setup \u5165\u53E3 ${options.setup}\uFF1A\u9ED8\u8BA4\u5BFC\u51FA\u5E94\u7528\u7EA7\u6267\u884C\u4E00\u6B21\uFF1BonSession \u6309\u5BBF\u4E3B sessionKey \u53BB\u91CD\uFF08\u7F3A sessionKey \u65F6\u62A5 MFU-013\uFF09`);
|
|
933
|
+
} else {
|
|
934
|
+
chain.push("\u672C\u5E94\u7528\u672A\u914D\u7F6E setup\uFF1A\u65E0\u521D\u59CB\u5316\u751F\u547D\u5468\u671F\uFF0CloadRemote \u76F4\u63A5\u8FD4\u56DE\u6A21\u5757\uFF08\u666E\u901A expose \u8BED\u4E49\uFF09");
|
|
935
|
+
}
|
|
936
|
+
return chain;
|
|
937
|
+
}
|
|
938
|
+
function explainAppMode(loaded, appName) {
|
|
939
|
+
const options = loaded.options;
|
|
940
|
+
if (appName && appName !== options.name) {
|
|
941
|
+
throw new Error(
|
|
942
|
+
`[fulgurjs:explain] \u5355\u9879\u76EE\u914D\u7F6E\u53EA\u63CF\u8FF0\u672C\u5E94\u7528\uFF08name: "${options.name}"\uFF09\uFF0C\u4E0E --app "${appName}" \u4E0D\u4E00\u81F4
|
|
943
|
+
\u4FEE\u6CD5: \u53BB\u6389 --app\uFF0C\u6216\u6539\u4E3A --app ${options.name}`
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
const role = roleOfOptions(options);
|
|
947
|
+
const devSharedSelfExplicit = options.devSharedSelf !== void 0;
|
|
948
|
+
const devSharedSelfValue = devSharedSelfExplicit ? options.devSharedSelf === true : role !== "host";
|
|
949
|
+
const hp = loaded.hostPages;
|
|
950
|
+
return {
|
|
951
|
+
app: options.name,
|
|
952
|
+
role,
|
|
953
|
+
mode: "app",
|
|
954
|
+
path: loaded.appRoot,
|
|
955
|
+
remotes: remotesOfOptions(options),
|
|
956
|
+
exposes: Object.keys(options.exposes ?? {}),
|
|
957
|
+
setup: options.setup,
|
|
958
|
+
shared: sharedOfOptions(options),
|
|
959
|
+
devSharedSelf: { value: devSharedSelfValue, source: devSharedSelfExplicit ? "explicit" : "inferred" },
|
|
960
|
+
pages: hp ? mappingsOf(hp, DEFAULT_DERIVE) : [],
|
|
961
|
+
pagesSource: hp ? `fulgurjs.config.ts \u7684 hostPages \u5177\u540D\u5BFC\u51FA\uFF08${hp.pages.length} \u6761\uFF1B\u8FD0\u884C\u65F6\u771F\u6E90\u4E3A\u5E94\u7528\u5185\u540C\u4E00\u6570\u636E\u6A21\u5757\uFF09` : "\u672A\u627E\u5230 hostPages \u5177\u540D\u5BFC\u51FA\uFF08\u7EAF\u8FDC\u7A0B\u5E94\u7528\u65E0\u9700\u9875\u9762\u8868\uFF1B\u5BBF\u4E3B\u82E5\u8981\u8DD1 check-pages \u8BF7\u5728 fulgurjs.config.ts \u8865\u5177\u540D\u5BFC\u51FA hostPages\uFF09",
|
|
962
|
+
chain: chainLines(options, role)
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function explainRepoMode(cfg, appPathOrName) {
|
|
647
966
|
const app = cfg.apps.find((a) => a.path === appPathOrName || a.name === appPathOrName);
|
|
648
967
|
if (!app) {
|
|
649
968
|
throw new Error(
|
|
@@ -667,6 +986,7 @@ async function explainApp(configPath, appPathOrName) {
|
|
|
667
986
|
return {
|
|
668
987
|
app: app.name,
|
|
669
988
|
role: roleOf(app),
|
|
989
|
+
mode: "repo",
|
|
670
990
|
path: app.path,
|
|
671
991
|
base: app.base,
|
|
672
992
|
port: app.port,
|
|
@@ -679,13 +999,28 @@ async function explainApp(configPath, appPathOrName) {
|
|
|
679
999
|
source: app.devSharedSelf === void 0 ? "inferred" : "explicit"
|
|
680
1000
|
},
|
|
681
1001
|
pages: pageMappings(app),
|
|
1002
|
+
pagesSource: app.host?.pages ? "\u4ED3\u5E93\u914D\u7F6E host.pages \u526F\u672C\uFF08\u517C\u5BB9\u5F62\u6001\uFF1B\u5355\u9879\u76EE\u5F62\u6001\u8BF7\u6539\u7528 hostPages \u5177\u540D\u5BFC\u51FA\uFF09" : "\u4ED3\u5E93\u914D\u7F6E\u672A\u63D0\u4F9B\u9875\u9762\u8868\u2014\u2014\u5E94\u7528\u4EE3\u7801\u9875\u9762\u8868\u4E3A\u8FD0\u884C\u65F6\u771F\u6E90",
|
|
682
1003
|
chain
|
|
683
1004
|
};
|
|
684
1005
|
}
|
|
1006
|
+
async function explainApp(configPath, appName) {
|
|
1007
|
+
const loaded = await loadAppConfig(configPath);
|
|
1008
|
+
if (loaded.kind === "repo") {
|
|
1009
|
+
if (!appName) {
|
|
1010
|
+
throw new Error("[fulgurjs:explain] \u805A\u5408\u914D\u7F6E\u9700 --app <\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D>\uFF08\u5355\u9879\u76EE\u914D\u7F6E\u53EF\u7701\u7565\uFF09");
|
|
1011
|
+
}
|
|
1012
|
+
return explainRepoMode(loaded.repo, appName);
|
|
1013
|
+
}
|
|
1014
|
+
return explainAppMode(loaded, appName);
|
|
1015
|
+
}
|
|
685
1016
|
function formatExplain(r) {
|
|
686
1017
|
const roleText = r.role === "dual" ? "\u5BBF\u4E3B+\u8FDC\u7A0B\uFF08\u53CC\u89D2\u8272\uFF09" : r.role === "host" ? "\u5BBF\u4E3B" : "\u8FDC\u7A0B";
|
|
687
1018
|
const L = [];
|
|
688
|
-
|
|
1019
|
+
if (r.mode === "app") {
|
|
1020
|
+
L.push(`\u5E94\u7528 ${r.app}\uFF08${roleText}\uFF0C\u5355\u9879\u76EE\u914D\u7F6E\uFF0C\u76EE\u5F55 ${r.path}\uFF1Bbase/dev \u7AEF\u53E3\u7531 vite.config.ts \u7BA1\u7406\uFF09`);
|
|
1021
|
+
} else {
|
|
1022
|
+
L.push(`\u5E94\u7528 ${r.app}\uFF08${roleText}\uFF0C\u76EE\u5F55 ${r.path}\uFF0Cdev \u7AEF\u53E3 ${r.port}\uFF0Cbase ${r.base}\uFF09\u3010\u65E7\u805A\u5408\u914D\u7F6E\u5F62\u6001\uFF0C\u517C\u5BB9\u671F\u3011`);
|
|
1023
|
+
}
|
|
689
1024
|
if (r.remotes.length) {
|
|
690
1025
|
L.push("\u6D88\u8D39\u8FDC\u7A0B\uFF1A");
|
|
691
1026
|
for (const x of r.remotes) L.push(` ${x.key} \u2192 dev ${x.dev} / prod ${x.prod}`);
|
|
@@ -702,41 +1037,147 @@ function formatExplain(r) {
|
|
|
702
1037
|
}
|
|
703
1038
|
L.push(`devSharedSelf\uFF1A${r.devSharedSelf.value}\uFF08\u6765\u6E90\uFF1A${r.devSharedSelf.source === "explicit" ? "\u663E\u5F0F\u914D\u7F6E" : "\u6309\u89D2\u8272\u63A8\u65AD\u2014\u2014\u63D0\u4F9B exposes/setup \u7684\u5E94\u7528\u4E3A true\uFF0C\u7EAF\u5BBF\u4E3B\u4E3A false"}\uFF09`);
|
|
704
1039
|
if (r.pages.length) {
|
|
705
|
-
L.push(`\u9875\u9762 spec \u6620\u5C04\uFF08${r.pages.length}\uFF09\uFF1A`);
|
|
1040
|
+
L.push(`\u9875\u9762 spec \u6620\u5C04\uFF08${r.pages.length}\uFF09\u2014\u2014\u6765\u6E90\uFF1A${r.pagesSource}\uFF1A`);
|
|
706
1041
|
for (const p of r.pages) L.push(` ${p.route} \u2192 ${p.spec}${p.title ? `\uFF08${p.title}\uFF09` : ""}`);
|
|
707
1042
|
} else {
|
|
708
|
-
L.push(
|
|
1043
|
+
L.push(`\u9875\u9762 spec \u6620\u5C04\uFF1A\uFF08\u65E0\uFF09\u2014\u2014\u6765\u6E90\uFF1A${r.pagesSource}`);
|
|
709
1044
|
}
|
|
710
1045
|
L.push("\u52A0\u8F7D\u94FE\uFF1A");
|
|
711
1046
|
for (const c of r.chain) L.push(` \xB7 ${c}`);
|
|
712
1047
|
return L.join("\n");
|
|
713
1048
|
}
|
|
714
|
-
|
|
1049
|
+
function manifestFromFile(p) {
|
|
1050
|
+
try {
|
|
1051
|
+
const parsed = parseManifest(JSON.parse(fs2.readFileSync(p, "utf8")));
|
|
1052
|
+
if (parsed.manifest && !parsed.unsupportedVersion) return parsed.manifest;
|
|
1053
|
+
} catch {
|
|
1054
|
+
}
|
|
1055
|
+
return void 0;
|
|
1056
|
+
}
|
|
1057
|
+
async function manifestFromUrl(url) {
|
|
1058
|
+
try {
|
|
1059
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(5e3) });
|
|
1060
|
+
if (res.ok) {
|
|
1061
|
+
const parsed = parseManifest(await res.json());
|
|
1062
|
+
if (parsed.manifest && !parsed.unsupportedVersion) return parsed.manifest;
|
|
1063
|
+
}
|
|
1064
|
+
} catch {
|
|
1065
|
+
}
|
|
1066
|
+
return void 0;
|
|
1067
|
+
}
|
|
1068
|
+
async function fetchRemoteManifestRepo(cfg, app, opts) {
|
|
1069
|
+
const explicit = opts.manifests?.[app.name] ?? opts.manifests?.[app.path];
|
|
1070
|
+
if (explicit) {
|
|
1071
|
+
const fromUrl = /^https?:\/\//.test(explicit);
|
|
1072
|
+
const got = fromUrl ? await manifestFromUrl(explicit) : manifestFromFile(explicit);
|
|
1073
|
+
if (got) return { manifest: got, from: explicit };
|
|
1074
|
+
return void 0;
|
|
1075
|
+
}
|
|
715
1076
|
const candidates = [app.deployDir || app.base.replace(/^\/|\/$/g, ""), "dist"];
|
|
716
1077
|
for (const dir of candidates) {
|
|
717
1078
|
const p = path2.join(cfg.root, app.path, dir, "fulgurjs-manifest.json");
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
if (parsed.manifest && !parsed.unsupportedVersion) return { manifest: parsed.manifest, from: p };
|
|
721
|
-
} catch {
|
|
722
|
-
}
|
|
1079
|
+
const got = manifestFromFile(p);
|
|
1080
|
+
if (got) return { manifest: got, from: p };
|
|
723
1081
|
}
|
|
724
1082
|
if (opts.site) {
|
|
725
1083
|
const base = app.base === "/" ? "" : app.base.replace(/\/$/, "");
|
|
726
1084
|
const url = `${opts.site.replace(/\/$/, "")}${base}/fulgurjs-manifest.json`;
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
if (res.ok) {
|
|
730
|
-
const parsed = parseManifest(await res.json());
|
|
731
|
-
if (parsed.manifest && !parsed.unsupportedVersion) return { manifest: parsed.manifest, from: url };
|
|
732
|
-
}
|
|
733
|
-
} catch {
|
|
734
|
-
}
|
|
1085
|
+
const got = await manifestFromUrl(url);
|
|
1086
|
+
if (got) return { manifest: got, from: url };
|
|
735
1087
|
}
|
|
736
1088
|
return void 0;
|
|
737
1089
|
}
|
|
738
|
-
async function
|
|
739
|
-
const
|
|
1090
|
+
async function fetchRemoteManifestApp(loaded, options, remoteName, opts) {
|
|
1091
|
+
const explicit = opts.manifests?.[remoteName];
|
|
1092
|
+
if (explicit) {
|
|
1093
|
+
const fromUrl = /^https?:\/\//.test(explicit);
|
|
1094
|
+
const got = fromUrl ? await manifestFromUrl(explicit) : manifestFromFile(explicit);
|
|
1095
|
+
if (got) return { manifest: got, from: explicit };
|
|
1096
|
+
return void 0;
|
|
1097
|
+
}
|
|
1098
|
+
const remoteCfg = (options.remotes ?? {})[remoteName];
|
|
1099
|
+
if (!remoteCfg) return void 0;
|
|
1100
|
+
const cfg = typeof remoteCfg === "string" ? { external: remoteCfg } : remoteCfg;
|
|
1101
|
+
const prodBase = cfg.prod ?? cfg.external ?? "";
|
|
1102
|
+
if (!prodBase) return void 0;
|
|
1103
|
+
if (/^https?:\/\//.test(prodBase)) {
|
|
1104
|
+
const url = `${prodBase.replace(/\/$/, "")}/fulgurjs-manifest.json`;
|
|
1105
|
+
const got = await manifestFromUrl(url);
|
|
1106
|
+
if (got) return { manifest: got, from: url };
|
|
1107
|
+
return void 0;
|
|
1108
|
+
}
|
|
1109
|
+
if (opts.site) {
|
|
1110
|
+
const url = `${opts.site.replace(/\/$/, "")}${prodBase.startsWith("/") ? prodBase : `/${prodBase}`}/fulgurjs-manifest.json`;
|
|
1111
|
+
const got = await manifestFromUrl(url);
|
|
1112
|
+
if (got) return { manifest: got, from: url };
|
|
1113
|
+
}
|
|
1114
|
+
return void 0;
|
|
1115
|
+
}
|
|
1116
|
+
async function checkPagesApp(loaded, opts) {
|
|
1117
|
+
const options = loaded.options;
|
|
1118
|
+
const issues = [];
|
|
1119
|
+
const hp = loaded.hostPages;
|
|
1120
|
+
const pages = hp?.pages ?? [];
|
|
1121
|
+
const prefixes = hp?.remotePrefixes ?? {};
|
|
1122
|
+
if (pages.length === 0) {
|
|
1123
|
+
issues.push({
|
|
1124
|
+
level: "unverified",
|
|
1125
|
+
message: "fulgurjs.config.ts \u672A\u63D0\u4F9B hostPages \u5177\u540D\u5BFC\u51FA\u2014\u2014\u65E0\u4ECE\u6838\u5BF9\u9875\u9762\u5951\u7EA6\uFF08\u7EAF\u8FDC\u7A0B\u5E94\u7528\u5C5E\u6B63\u5E38\uFF0C\u65E0\u9700\u9875\u9762\u8868\uFF09\u3002\n \u4FEE\u6CD5: \u5BBF\u4E3B\u5E94\u7528\u5728 fulgurjs.config.ts \u52A0\u5177\u540D\u5BFC\u51FA hostPages = { pages, remotePrefixes, deriveSpec? }\uFF08\u4E0E\u8FD0\u884C\u65F6 createHostPages \u6D88\u8D39\u540C\u4E00\u4EFD\u6570\u636E\u6A21\u5757\uFF09"
|
|
1126
|
+
});
|
|
1127
|
+
return { app: options.name, checked: 0, issues, failed: false, unverifiedFailed: !!opts.requireVerified, manifestSources: [] };
|
|
1128
|
+
}
|
|
1129
|
+
const violations = validatePages(pages, { remotes: prefixes });
|
|
1130
|
+
for (const v of violations) {
|
|
1131
|
+
issues.push({ level: v.level === "error" ? "error" : "warn", message: v.message });
|
|
1132
|
+
}
|
|
1133
|
+
const remoteNames = [...new Set(Object.values(prefixes))];
|
|
1134
|
+
const manifests = /* @__PURE__ */ new Map();
|
|
1135
|
+
const sources = [];
|
|
1136
|
+
for (const name of remoteNames) {
|
|
1137
|
+
if (!options.remotes || !(name in options.remotes)) {
|
|
1138
|
+
issues.push({ level: "error", message: `\u8DEF\u7531\u524D\u7F00\u6620\u5C04\u5230\u8FDC\u7A0B "${name}"\uFF0C\u4F46\u672C\u5E94\u7528 federation({ remotes }) \u672A\u6D88\u8D39\u5B83\u2014\u2014\u5BBF\u4E3B\u53EA\u6838\u5BF9\u5B83\u5B9E\u9645\u6D88\u8D39\u7684\u8FDC\u7A0B` });
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
const got = await fetchRemoteManifestApp(loaded, options, name, opts);
|
|
1142
|
+
if (!got) {
|
|
1143
|
+
const how = opts.manifests?.[name] ? `--manifest ${name}=${opts.manifests[name]} \u4E0D\u53EF\u8FBE\u6216\u975E\u6709\u6548 manifest` : opts.site ? `\u6309 remotes prod \u5730\u5740\u4E0E --site ${opts.site} \u63A8\u5BFC\u7684 manifest URL \u4E0D\u53EF\u8FBE` : "\u672A\u63D0\u4F9B manifest \u6765\u6E90";
|
|
1144
|
+
issues.push({
|
|
1145
|
+
level: "unverified",
|
|
1146
|
+
message: `\u8FDC\u7A0B "${name}" \u7684 manifest \u4E0D\u53EF\u5F97\uFF08${how}\uFF09\u2014\u2014\u8BE5\u8FDC\u7A0B\u7684 spec \u5B58\u5728\u6027\u65E0\u6CD5\u6838\u5BF9\u3002
|
|
1147
|
+
\u4FEE\u6CD5: --manifest ${name}=<\u5DF2\u6784\u5EFA\u4EA7\u7269\u8DEF\u5F84\u6216 https://\u2026/fulgurjs-manifest.json>\uFF0C\u6216 --site <\u90E8\u7F72\u7AD9\u70B9>\uFF08\u6309 prod \u5730\u5740\u63A8\u5BFC\uFF09`
|
|
1148
|
+
});
|
|
1149
|
+
continue;
|
|
1150
|
+
}
|
|
1151
|
+
manifests.set(name, { exposes: new Set([...normalizeExposes(got.manifest).keys()].map(normSpecKey)), from: got.from });
|
|
1152
|
+
sources.push({ remote: name, from: got.from });
|
|
1153
|
+
}
|
|
1154
|
+
const derive = hp?.deriveSpec ?? DEFAULT_DERIVE;
|
|
1155
|
+
let checked = 0;
|
|
1156
|
+
for (const page of pages) {
|
|
1157
|
+
const prefixHit = Object.entries(prefixes).sort((a, b) => b[0].length - a[0].length).find(
|
|
1158
|
+
([p]) => page.route.startsWith(p.endsWith("/") ? p : `${p}/`) || `${page.route}/` === (p.endsWith("/") ? p : `${p}/`)
|
|
1159
|
+
);
|
|
1160
|
+
if (!prefixHit) {
|
|
1161
|
+
issues.push({ level: "error", message: `\u8DEF\u7531 "${page.route}" \u4E0D\u5728\u4EFB\u4F55 remotePrefixes \u524D\u7F00\u4E0B` });
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
checked++;
|
|
1165
|
+
const m = manifests.get(prefixHit[1]);
|
|
1166
|
+
if (!m) continue;
|
|
1167
|
+
const spec = normSpecKey(String(page.spec ?? derive(page.route)));
|
|
1168
|
+
if (!m.exposes.has(spec)) {
|
|
1169
|
+
issues.push({
|
|
1170
|
+
level: "error",
|
|
1171
|
+
message: `\u8DEF\u7531 "${page.route}" \u7684 spec "${spec}" \u4E0D\u5728\u8FDC\u7A0B "${prefixHit[1]}" \u7684 exposes \u6E05\u5355\u4E2D\uFF08\u6765\u6E90 ${m.from}\uFF09\u3002
|
|
1172
|
+
\u8FDC\u7A0B\u5B9E\u9645 exposes\uFF08\u524D 10\uFF09\uFF1A${[...m.exposes].slice(0, 10).join("\u3001") || "\uFF08\u7A7A\uFF09"}
|
|
1173
|
+
\u4FEE\u6CD5: \u6838\u5BF9\u8FDC\u7A0B federation({ exposes }) \u952E\u540D\u6216\u4FEE\u6B63\u9875\u9762\u8868 spec`
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const failed = issues.some((i) => i.level === "error");
|
|
1178
|
+
return { app: options.name, checked, issues, failed, unverifiedFailed: !!opts.requireVerified, manifestSources: sources };
|
|
1179
|
+
}
|
|
1180
|
+
async function checkPagesRepo(cfg, appPathOrName, opts) {
|
|
740
1181
|
const app = cfg.apps.find((a) => a.path === appPathOrName || a.name === appPathOrName);
|
|
741
1182
|
if (!app) {
|
|
742
1183
|
throw new Error(`[fulgurjs:check-pages] \u5E94\u7528 "${appPathOrName}" \u4E0D\u5728\u914D\u7F6E\u4E2D\uFF08\u53EF\u7528\uFF1A${cfg.apps.map((a) => a.path).join("\u3001")}\uFF09`);
|
|
@@ -749,7 +1190,7 @@ async function checkPages(configPath, appPathOrName, opts = {}) {
|
|
|
749
1190
|
level: "unverified",
|
|
750
1191
|
message: "\u4ED3\u5E93\u914D\u7F6E\u672A\u63D0\u4F9B\u9875\u9762\u8868\uFF08pages \u53EF\u9009\uFF0C\u5E94\u7528\u4EE3\u7801\u9875\u9762\u8868\u4E3A\u8FD0\u884C\u65F6\u771F\u6E90\uFF09\u2014\u2014\u672C\u547D\u4EE4\u65E0\u4ECE\u6838\u5BF9\u3002\n \u4FEE\u6CD5: \u5728 fulgurjs.config.ts \u5BBF\u4E3B host.pages \u63D0\u4F9B\u9875\u9762\u8868\u526F\u672C\uFF0C\u6216\u4F9D\u8D56 dev \u671F remoteSchema \u63A2\u9488\u6821\u9A8C"
|
|
751
1192
|
});
|
|
752
|
-
return { app: app.name, checked: 0, issues, failed: false };
|
|
1193
|
+
return { app: app.name, checked: 0, issues, failed: false, unverifiedFailed: !!opts.requireVerified, manifestSources: [] };
|
|
753
1194
|
}
|
|
754
1195
|
const violations = validatePages(pages, { remotes: prefixes });
|
|
755
1196
|
for (const v of violations) {
|
|
@@ -757,13 +1198,14 @@ async function checkPages(configPath, appPathOrName, opts = {}) {
|
|
|
757
1198
|
}
|
|
758
1199
|
const remoteNames = [...new Set(Object.values(prefixes))];
|
|
759
1200
|
const manifests = /* @__PURE__ */ new Map();
|
|
1201
|
+
const sources = [];
|
|
760
1202
|
for (const name of remoteNames) {
|
|
761
1203
|
const remoteApp = cfg.apps.find((a) => a.name === name);
|
|
762
1204
|
if (!remoteApp) {
|
|
763
1205
|
issues.push({ level: "error", message: `\u8DEF\u7531\u524D\u7F00\u6620\u5C04\u5230\u672A\u77E5\u8FDC\u7A0B "${name}"\u2014\u2014\u914D\u7F6E apps \u4E2D\u4E0D\u5B58\u5728\u8BE5\u5BB9\u5668\u540D` });
|
|
764
1206
|
continue;
|
|
765
1207
|
}
|
|
766
|
-
const got = await
|
|
1208
|
+
const got = await fetchRemoteManifestRepo(cfg, remoteApp, opts);
|
|
767
1209
|
if (!got) {
|
|
768
1210
|
issues.push({
|
|
769
1211
|
level: "unverified",
|
|
@@ -773,6 +1215,7 @@ async function checkPages(configPath, appPathOrName, opts = {}) {
|
|
|
773
1215
|
continue;
|
|
774
1216
|
}
|
|
775
1217
|
manifests.set(name, { exposes: new Set([...normalizeExposes(got.manifest).keys()].map(normSpecKey)), from: got.from });
|
|
1218
|
+
sources.push({ remote: name, from: got.from });
|
|
776
1219
|
}
|
|
777
1220
|
const derive = app.host?.deriveSpec ?? ((r) => r.split("/").filter(Boolean).slice(1).filter((s) => !s.startsWith(":")).join("/"));
|
|
778
1221
|
let checked = 0;
|
|
@@ -797,7 +1240,18 @@ async function checkPages(configPath, appPathOrName, opts = {}) {
|
|
|
797
1240
|
});
|
|
798
1241
|
}
|
|
799
1242
|
}
|
|
800
|
-
|
|
1243
|
+
const failed = issues.some((i) => i.level === "error");
|
|
1244
|
+
return { app: app.name, checked, issues, failed, unverifiedFailed: !!opts.requireVerified, manifestSources: sources };
|
|
1245
|
+
}
|
|
1246
|
+
async function checkPages(configPath, appPathOrName, opts = {}) {
|
|
1247
|
+
const loaded = await loadAppConfig(configPath);
|
|
1248
|
+
if (loaded.kind === "repo") {
|
|
1249
|
+
if (!appPathOrName) {
|
|
1250
|
+
throw new Error("[fulgurjs:check-pages] \u805A\u5408\u914D\u7F6E\u9700 --app <\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D>\uFF08\u5355\u9879\u76EE\u914D\u7F6E\u53EF\u7701\u7565\uFF09");
|
|
1251
|
+
}
|
|
1252
|
+
return checkPagesRepo(loaded.repo, appPathOrName, opts);
|
|
1253
|
+
}
|
|
1254
|
+
return checkPagesApp(loaded, opts);
|
|
801
1255
|
}
|
|
802
1256
|
function formatCheckPages(r) {
|
|
803
1257
|
const L = [];
|
|
@@ -805,19 +1259,28 @@ function formatCheckPages(r) {
|
|
|
805
1259
|
const unverified = r.issues.filter((i) => i.level === "unverified");
|
|
806
1260
|
const warns = r.issues.filter((i) => i.level === "warn");
|
|
807
1261
|
L.push(`[fulgurjs:check-pages] \u5E94\u7528 ${r.app}\uFF1A\u6838\u5BF9 ${r.checked} \u6761\u9875\u9762\uFF0Cerror ${errors.length} / warn ${warns.length} / \u65E0\u6CD5\u9A8C\u8BC1 ${unverified.length}`);
|
|
1262
|
+
if (r.manifestSources?.length) {
|
|
1263
|
+
L.push("manifest \u6765\u6E90\uFF08\u4F18\u5148\u7EA7\uFF1A--manifest > --site/prod \u63A8\u5BFC > \u672C\u5730 dist\uFF1B\u4EE5\u5B9E\u9645\u547D\u4E2D\u7684\u6765\u6E90\u4E3A\u51C6\uFF09\uFF1A");
|
|
1264
|
+
for (const s of r.manifestSources) L.push(` ${s.remote} \u2190 ${s.from}`);
|
|
1265
|
+
}
|
|
808
1266
|
for (const i of [...errors, ...warns, ...unverified]) L.push(`
|
|
809
1267
|
[${i.level.toUpperCase()}] ${i.message}`);
|
|
810
1268
|
if (r.issues.length === 0) L.push("\u5168\u90E8\u9875\u9762 spec \u4E0E\u8FDC\u7A0B exposes \u4E00\u81F4 \u2713");
|
|
1269
|
+
if (r.unverifiedFailed && unverified.length > 0 && errors.length === 0) {
|
|
1270
|
+
L.push(`
|
|
1271
|
+
--require-verified\uFF1A\u5B58\u5728 ${unverified.length} \u9879\u65E0\u6CD5\u9A8C\u8BC1\u2014\u2014\u6309 CI \u4E25\u683C\u6A21\u5F0F\u5224\u5B9A\u4E3A\u672A\u901A\u8FC7\uFF08\u9000\u51FA\u7801\u975E\u96F6\uFF09`);
|
|
1272
|
+
}
|
|
811
1273
|
return L.join("\n");
|
|
812
1274
|
}
|
|
813
|
-
var normSpecKey;
|
|
1275
|
+
var DEFAULT_DERIVE, normSpecKey;
|
|
814
1276
|
var init_commands = __esm({
|
|
815
1277
|
"src/commands.ts"() {
|
|
816
1278
|
"use strict";
|
|
817
|
-
|
|
1279
|
+
init_app_config();
|
|
818
1280
|
init_config();
|
|
819
1281
|
init_pages();
|
|
820
1282
|
init_manifest();
|
|
1283
|
+
DEFAULT_DERIVE = (route) => route.split("/").filter(Boolean).slice(1).filter((s) => !s.startsWith(":")).join("/");
|
|
821
1284
|
normSpecKey = (s) => s.replace(/^[./]+/, "").replace(/\/+$/, "");
|
|
822
1285
|
}
|
|
823
1286
|
});
|
|
@@ -1135,24 +1598,31 @@ function formatDoctorReport(checks) {
|
|
|
1135
1598
|
// src/cli.ts
|
|
1136
1599
|
var HELP = `fulgurjs \u2014 Vite Module Federation CLI (@fulgurjs/federation)
|
|
1137
1600
|
|
|
1138
|
-
\u7528\u6CD5\uFF1A
|
|
1139
|
-
fulgurjs init [--template <path>] [--force] \u751F\u6210\
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
\
|
|
1601
|
+
\u7528\u6CD5\uFF08\u5355\u9879\u76EE fulgurjs.config.ts \u5728\u5E94\u7528\u6839\u76EE\u5F55\uFF1B\u547D\u4EE4\u9ED8\u8BA4\u8BFB ./fulgurjs.config.ts\uFF09\uFF1A
|
|
1602
|
+
fulgurjs init [--template <path>] [--force] \u751F\u6210\u5355\u9879\u76EE fulgurjs.config.ts \u8D77\u6B65\u6A21\u677F
|
|
1603
|
+
\uFF08\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879\uFF09
|
|
1604
|
+
fulgurjs init --config <path> \u6821\u9A8C\u914D\u7F6E\uFF1B\u8F93\u51FA federation(fulgurjsConfig) \u63A5\u5165\u5757
|
|
1605
|
+
\u4E0E\u63A5\u5165\u6838\u5BF9\u6E05\u5355\uFF08NGINX \u6837\u677F\u4EC5\u968F\u65E7\u805A\u5408\u914D\u7F6E\u6253\u5370\uFF09
|
|
1606
|
+
fulgurjs explain [--config <path>] [--app <name>] [--json]
|
|
1607
|
+
\u89E3\u91CA\u672C\u5E94\u7528\u6709\u6548\u8054\u90A6\u5F62\u6001\u4E0E\u52A0\u8F7D\u94FE\uFF08\u7EAF\u672C\u5730\uFF0C\u65E0\u7F51\u7EDC\uFF1B
|
|
1608
|
+
\u5355\u9879\u76EE\u5F62\u6001\u514D --app\uFF0C\u65E7\u805A\u5408\u914D\u7F6E\u5FC5\u586B\uFF09
|
|
1609
|
+
fulgurjs check-pages [--config <path>] [--app <name>] [--site <URL>]
|
|
1610
|
+
[--manifest <remote>=<\u8DEF\u5F84|URL>]... [--require-verified] [--json]
|
|
1611
|
+
\u6838\u5BF9\u5BBF\u4E3B\u9875\u9762\u8868\u4E0E\u8FDC\u7A0B exposes\uFF08\u5BBF\u4E3B\u9879\u76EE\u8FD0\u884C\uFF1B
|
|
1612
|
+
manifest \u6765\u6E90\u4F18\u5148\u7EA7 --manifest > --site/prod \u63A8\u5BFC\uFF1B
|
|
1613
|
+
\u786E\u5B9A\u6027\u9519\u8BEF\u975E\u96F6\u9000\u51FA\uFF1B--require-verified \u65F6\u65E0\u6CD5\u9A8C\u8BC1\u4E5F\u975E\u96F6\uFF09
|
|
1146
1614
|
fulgurjs doctor --base <URL> --apps <a,b,c> [--dev] [--json] [--chunk-sample N]
|
|
1147
1615
|
fulgurjs --help
|
|
1148
1616
|
|
|
1149
|
-
\u793A\u4F8B\uFF1A
|
|
1617
|
+
\u793A\u4F8B\uFF08\u5355\u9879\u76EE\u5F62\u6001\uFF0C\u5E94\u7528\u6839\u76EE\u5F55\u5185\u8FD0\u884C\uFF09\uFF1A
|
|
1150
1618
|
fulgurjs init # \u5F53\u524D\u76EE\u5F55\u5199 fulgurjs.config.ts\uFF08\u5DF2\u5B58\u5728\u5219\u62D2\u7EDD\uFF0C--force \u8986\u76D6\uFF09
|
|
1151
|
-
fulgurjs
|
|
1152
|
-
fulgurjs
|
|
1153
|
-
fulgurjs check-pages --
|
|
1154
|
-
fulgurjs doctor --base http://your-site --apps app-a
|
|
1155
|
-
|
|
1619
|
+
fulgurjs explain # \u89E3\u91CA\u672C\u5E94\u7528\uFF08--config \u6307\u5411\u5176\u4ED6\u8DEF\u5F84\u65F6\u663E\u5F0F\u4F20\uFF09
|
|
1620
|
+
fulgurjs check-pages --site http://your-site # \u6309 remotes prod \u5730\u5740\u63A8\u5BFC\u8FDC\u7A0B manifest \u6838\u5BF9
|
|
1621
|
+
fulgurjs check-pages --manifest remote-a=https://cdn.example.com/remote-a/fulgurjs-manifest.json
|
|
1622
|
+
fulgurjs doctor --base http://your-site --apps my-app,remote-a
|
|
1623
|
+
|
|
1624
|
+
\u65E7\u805A\u5408\u914D\u7F6E\uFF08root + apps[]\uFF0C\u517C\u5BB9\u671F\uFF09\uFF1A\u6240\u6709\u5B50\u547D\u4EE4\u52A0 --config \u6307\u5411\u805A\u5408\u6587\u4EF6\uFF0C
|
|
1625
|
+
explain/check-pages \u9700 --app <\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D>\u3002
|
|
1156
1626
|
`;
|
|
1157
1627
|
async function main() {
|
|
1158
1628
|
const argv = process.argv.slice(2);
|
|
@@ -1166,6 +1636,17 @@ async function main() {
|
|
|
1166
1636
|
return i > -1 ? argv[i + 1] : void 0;
|
|
1167
1637
|
};
|
|
1168
1638
|
const has = (k) => argv.includes(k);
|
|
1639
|
+
const kvAllOf = (k) => {
|
|
1640
|
+
const out = {};
|
|
1641
|
+
argv.forEach((a, i) => {
|
|
1642
|
+
if (a !== k) return;
|
|
1643
|
+
const v = argv[i + 1];
|
|
1644
|
+
const eq = v?.indexOf("=");
|
|
1645
|
+
if (!v || !eq || eq < 1) return;
|
|
1646
|
+
out[v.slice(0, eq)] = v.slice(eq + 1);
|
|
1647
|
+
});
|
|
1648
|
+
return out;
|
|
1649
|
+
};
|
|
1169
1650
|
if (cmd === "init") {
|
|
1170
1651
|
const { writeConfigTemplate: writeConfigTemplate2, inspectConfig: inspectConfig2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
1171
1652
|
const configPath = argOf("--config");
|
|
@@ -1184,34 +1665,37 @@ async function main() {
|
|
|
1184
1665
|
console.error(`[fulgurjs:init] ${target} \u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6\uFF08--force \u5F3A\u5236\u8986\u76D6\uFF09`);
|
|
1185
1666
|
return 2;
|
|
1186
1667
|
}
|
|
1187
|
-
console.log(`[fulgurjs:init] \u5DF2\u751F\u6210\u8D77\u6B65\u6A21\u677F ${target}
|
|
1668
|
+
console.log(`[fulgurjs:init] \u5DF2\u751F\u6210\u5355\u9879\u76EE\u8D77\u6B65\u6A21\u677F ${target}
|
|
1188
1669
|
\u540E\u7EED\u6B65\u9AA4\uFF1A
|
|
1189
|
-
1. \u7F16\u8F91 fulgurjs.config.ts\uFF1A\u586B\u5165\
|
|
1190
|
-
2.
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1670
|
+
1. \u7F16\u8F91 fulgurjs.config.ts\uFF1A\u586B\u5165\u5BB9\u5668\u540D/exposes/remotes/shared\uFF08\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879\uFF09
|
|
1671
|
+
2. vite.config.ts \u63A5\u5165\uFF08\u4EC5\u4E24\u884C\u8054\u90A6\u76F8\u5173\u4EE3\u7801\uFF09\uFF1A
|
|
1672
|
+
import federation from '@fulgurjs/federation'
|
|
1673
|
+
import fulgurjsConfig from './fulgurjs.config'
|
|
1674
|
+
// plugins: [ ...\u539F\u6709\u63D2\u4EF6, federation(fulgurjsConfig) ]
|
|
1675
|
+
3. npx fulgurjs explain # \u6838\u5BF9\u6709\u6548\u5F62\u6001\u4E0E\u52A0\u8F7D\u94FE
|
|
1676
|
+
4. \u5BBF\u4E3B\u5E94\u7528\u53E6\u5728 fulgurjs.config.ts \u5177\u540D\u5BFC\u51FA hostPages\uFF08\u4E0E\u8FD0\u884C\u65F6\u9875\u9762\u6570\u636E\u6A21\u5757\u540C\u6E90\uFF09\uFF0C
|
|
1677
|
+
\u8FD0\u884C npx fulgurjs check-pages --site <\u7AD9\u70B9> \u6838\u5BF9\u9875\u9762\u5951\u7EA6
|
|
1678
|
+
5. \u90E8\u7F72\u540E\uFF1Anpx fulgurjs doctor --base <URL> --apps <\u5BB9\u5668\u540D>`);
|
|
1194
1679
|
return 0;
|
|
1195
1680
|
}
|
|
1196
1681
|
if (cmd === "explain" || cmd === "check-pages") {
|
|
1197
|
-
const configPath = argOf("--config");
|
|
1198
1682
|
const app = argOf("--app");
|
|
1199
|
-
if (!configPath || !app) {
|
|
1200
|
-
console.error(`[fulgurjs:${cmd}] \u7F3A\u5C11\u53C2\u6570\uFF1A--config <fulgurjs.config.ts \u8DEF\u5F84> \u4E0E --app <\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D>`);
|
|
1201
|
-
return 2;
|
|
1202
|
-
}
|
|
1203
1683
|
try {
|
|
1204
1684
|
if (cmd === "explain") {
|
|
1205
1685
|
const { explainApp: explainApp2, formatExplain: formatExplain2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
1206
|
-
const r2 = await explainApp2(resolve(
|
|
1686
|
+
const r2 = await explainApp2(resolve(argOf("--config") ?? "fulgurjs.config.ts"), app);
|
|
1207
1687
|
console.log(has("--json") ? JSON.stringify(r2, null, 2) : formatExplain2(r2));
|
|
1208
1688
|
return 0;
|
|
1209
1689
|
}
|
|
1210
1690
|
const { checkPages: checkPages2, formatCheckPages: formatCheckPages2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
1211
|
-
const
|
|
1212
|
-
|
|
1691
|
+
const opts = {
|
|
1692
|
+
...argOf("--site") ? { site: argOf("--site") } : {},
|
|
1693
|
+
...Object.keys(kvAllOf("--manifest")).length ? { manifests: kvAllOf("--manifest") } : {},
|
|
1694
|
+
...has("--require-verified") ? { requireVerified: true } : {}
|
|
1695
|
+
};
|
|
1696
|
+
const r = await checkPages2(resolve(argOf("--config") ?? "fulgurjs.config.ts"), app, opts);
|
|
1213
1697
|
console.log(has("--json") ? JSON.stringify(r, null, 2) : formatCheckPages2(r));
|
|
1214
|
-
return r.failed ? 1 : 0;
|
|
1698
|
+
return r.failed || r.unverifiedFailed ? 1 : 0;
|
|
1215
1699
|
} catch (e) {
|
|
1216
1700
|
console.error(String(e.message ?? e));
|
|
1217
1701
|
return 2;
|