@fulgurjs/federation 4.3.1 → 5.0.1

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/dist/cli.js CHANGED
@@ -154,140 +154,6 @@ var init_manifest = __esm({
154
154
  }
155
155
  });
156
156
 
157
- // src/config.ts
158
- async function loadRepoConfig(configPath) {
159
- const { pathToFileURL: pathToFileURL2, fileURLToPath } = await import("node:url");
160
- const { createRequire: createRequire2 } = await import("node:module");
161
- const fs3 = await import("node:fs");
162
- const os = await import("node:os");
163
- const path3 = await import("node:path");
164
- const selfDir = await (async () => {
165
- try {
166
- return path3.dirname(fileURLToPath(import.meta.url));
167
- } catch {
168
- }
169
- try {
170
- return __dirname;
171
- } catch {
172
- }
173
- return "";
174
- })();
175
- const selfConfigJs = selfDir ? path3.join(selfDir, "config.js") : "";
176
- const SELF_SPEC = selfConfigJs && fs3.existsSync(selfConfigJs) ? pathToFileURL2(selfConfigJs).href : "@fulgurjs-federation-config-unavailable";
177
- const rewriteSelfImports = (source) => source.replace(/(['"])@fulgurjs\/federation\/config\1/g, (_m, q) => `${q}${SELF_SPEC}${q}`);
178
- let cacheBust = 0;
179
- const importConfigs = async (cacheKey) => {
180
- return await import(`${cacheKey}?t=${Date.now()}-${++cacheBust}`);
181
- };
182
- let mod;
183
- if (configPath.endsWith(".json")) {
184
- mod = { default: JSON.parse(fs3.readFileSync(configPath, "utf8")) };
185
- } else {
186
- const source = rewriteSelfImports(fs3.readFileSync(configPath, "utf8"));
187
- const tmpBase = path3.join(os.tmpdir(), `fulgurjs-config-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`);
188
- if (/\.(ts|mts|cts)$/.test(configPath)) {
189
- try {
190
- const tmpTs = `${tmpBase}.ts`;
191
- fs3.writeFileSync(tmpTs, source);
192
- mod = await importConfigs(pathToFileURL2(tmpTs).href);
193
- } catch (e) {
194
- if (!/Unexpected|SyntaxError|ERR_UNSUPPORTED_NODE_MODULES|ERR_UNKNOWN_FILE_EXTENSION|ERR_IMPORT_ATTRIBUTE/.test(String(e)) && process.version.startsWith("v2")) {
195
- throw e;
196
- }
197
- const requireFromConfig = createRequire2(configPath);
198
- let esbuild;
199
- try {
200
- esbuild = requireFromConfig("esbuild");
201
- } catch {
202
- const requireFromSelf = createRequire2(import.meta.url);
203
- esbuild = requireFromSelf("esbuild");
204
- }
205
- const out = esbuild.buildSync({ entryPoints: [configPath], bundle: false, write: false, format: "esm", target: "node18" });
206
- const jsFile = `${tmpBase}.mjs`;
207
- fs3.writeFileSync(jsFile, rewriteSelfImports(out.outputFiles[0].text));
208
- mod = await importConfigs(pathToFileURL2(jsFile).href);
209
- }
210
- } else {
211
- const jsFile = `${tmpBase}.mjs`;
212
- fs3.writeFileSync(jsFile, source);
213
- mod = await importConfigs(pathToFileURL2(jsFile).href);
214
- }
215
- }
216
- const cfg = mod.default;
217
- if (!cfg?.root) {
218
- throw new Error(
219
- `[fulgurjs:init] \u914D\u7F6E\u7F3A\u5C11 root\uFF08\u5DE5\u7A0B\u6839\u76EE\u5F55\u7EDD\u5BF9\u8DEF\u5F84\uFF09
220
- \u6839\u56E0\uFF1ACLI \u9700\u8981\u77E5\u9053\u5728\u54EA\u4E2A\u5DE5\u7A0B\u4E0A\u505A\u96C6\u6210
221
- \u4FEE\u6CD5\uFF1Afulgurjs.config.ts \u9876\u5C42\u8865 root: '/abs/path/to/repo'\uFF08\u8D77\u6B65\u6A21\u677F\uFF1Afulgurjs init\uFF09`
222
- );
223
- }
224
- if (!Array.isArray(cfg.apps) || cfg.apps.length === 0) {
225
- throw new Error("[fulgurjs:init] \u914D\u7F6E\u7F3A\u5C11 apps\uFF08\u81F3\u5C11\u4E00\u4E2A\u5BBF\u4E3B\u6216\u8FDC\u7A0B\u5E94\u7528\uFF09");
226
- }
227
- for (const app of cfg.apps) {
228
- if (!app.host && !app.remote) {
229
- throw new Error(
230
- `[fulgurjs:init] \u5E94\u7528 "${app.path}" \u65E2\u65E0 host \u4E5F\u65E0 remote \u89D2\u8272
231
- \u6839\u56E0\uFF1A\u5E94\u7528\u5FC5\u987B\u81F3\u5C11\u58F0\u660E\u4E00\u4E2A\u89D2\u8272
232
- \u4FEE\u6CD5\uFF1A\u5BBF\u4E3B\u8865 host: { remotePrefixes, remotes }\uFF08pages \u53EF\u9009\uFF09\uFF0C\u8FDC\u7A0B\u8865 remote: { exposes }`
233
- );
234
- }
235
- }
236
- return cfg;
237
- }
238
- function federationOptionsForApp(config, appPathOrName) {
239
- const app = config.apps.find(
240
- (a) => a.path === appPathOrName || a.name === appPathOrName
241
- );
242
- if (!app) {
243
- throw new Error(
244
- `[fulgurjs] \u5E94\u7528 "${appPathOrName}" \u4E0D\u5728\u4ED3\u5E93\u914D\u7F6E\u4E2D
245
- \u53EF\u7528\u5E94\u7528: ${config.apps.map((a) => `${a.path}(${a.name})`).join("\u3001")}
246
- \u4FEE\u6CD5: \u4FEE\u6B63\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D\uFF08fulgurjs.config.ts apps \u6570\u7EC4\u5185\u4E8C\u9009\u4E00\u5339\u914D\uFF09`
247
- );
248
- }
249
- if (!app.host && !app.remote) {
250
- throw new Error(
251
- `[fulgurjs] \u5E94\u7528 "${app.path}" \u65E2\u65E0 host \u4E5F\u65E0 remote \u89D2\u8272
252
- \u4FEE\u6CD5: \u5BBF\u4E3B\u8865 host: { remotePrefixes, remotes }\uFF0C\u8FDC\u7A0B\u8865 remote: { exposes }`
253
- );
254
- }
255
- const remotes = {};
256
- const remoteSource = /* @__PURE__ */ new Map();
257
- const mergeRemotes = (from, role) => {
258
- for (const [key, addr] of Object.entries(from ?? {})) {
259
- const prev = remotes[key];
260
- if (prev && (prev.dev !== addr.dev || prev.prod !== addr.prod)) {
261
- throw new Error(
262
- `[fulgurjs] \u5E94\u7528 "${app.path}" \u7684\u8FDC\u7A0B "${key}" \u5728 ${role} \u4E0E ${remoteSource.get(key)} \u4E24\u5904\u5730\u5740\u4E0D\u4E00\u81F4
263
- ${remoteSource.get(key)}: dev=${prev.dev} prod=${prev.prod}
264
- ${role}: dev=${addr.dev} prod=${addr.prod}
265
- \u4FEE\u6CD5: \u4FEE\u6B63 fulgurjs.config.ts \u4F7F\u4E24\u5904\u4E00\u81F4\uFF08\u540C\u4E00\u8FDC\u7A0B\u5728\u4E00\u4E2A\u5E94\u7528\u5185\u53EA\u80FD\u6709\u4E00\u4E2A\u5730\u5740\uFF09`
266
- );
267
- }
268
- remotes[key] = addr;
269
- remoteSource.set(key, role);
270
- }
271
- };
272
- mergeRemotes(app.host?.remotes, "host.remotes");
273
- mergeRemotes(app.remote?.remotes, "remote.remotes");
274
- const hasExposes = !!app.remote && Object.keys(app.remote.exposes).length > 0;
275
- const hasRemotes = Object.keys(remotes).length > 0;
276
- return {
277
- name: app.name,
278
- ...hasRemotes ? { remotes } : {},
279
- ...hasExposes ? { exposes: app.remote.exposes } : {},
280
- ...app.remote?.setup ? { setup: app.remote.setup } : {},
281
- ...app.shared ? { shared: app.shared } : {},
282
- devSharedSelf: app.devSharedSelf ?? (hasExposes || !!app.remote?.setup)
283
- };
284
- }
285
- var init_config = __esm({
286
- "src/config.ts"() {
287
- "use strict";
288
- }
289
- });
290
-
291
157
  // src/app-config.ts
292
158
  import { createRequire } from "node:module";
293
159
  import { pathToFileURL } from "node:url";
@@ -299,6 +165,13 @@ function appConfigError(what, cause, fix) {
299
165
  function isAggregateShape(value) {
300
166
  return !!value && typeof value === "object" && Array.isArray(value.apps);
301
167
  }
168
+ function aggregateMigrationError() {
169
+ appConfigError(
170
+ "\u914D\u7F6E\u662F\u65E7\u805A\u5408\u5F62\u6001\uFF08root + apps[]\uFF0C\u5DF2\u5220\u9664\uFF09",
171
+ "4.1.0 \u7684\u805A\u5408\u914D\u7F6E\u94FE\uFF08defineRepoConfig / loadRepoConfig / federationOptionsForApp \u4E0E @fulgurjs/federation/config \u5B50\u8DEF\u5F84\uFF09\u5DF2\u5728 5.0.0 \u5220\u9664\uFF1BCLI \u53EA\u63A5\u53D7\u5355\u9879\u76EE\u914D\u7F6E\uFF1A\u6BCF\u4E2A\u5E94\u7528\u6839\u76EE\u5F55\u4E00\u4EFD fulgurjs.config.ts\uFF0C\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879",
172
+ "\u628A\u805A\u5408\u6587\u4EF6\u91CC\u6BCF\u4E2A\u5E94\u7528\u62C6\u6210\u5404\u81EA\u9879\u76EE\u6839\u76EE\u5F55\u7684 fulgurjs.config.ts\uFF1A\n \u5E94\u7528\u6839/fulgurjs.config.ts\uFF1Aexport default { name, remotes, exposes, setup, shared, devSharedSelf? } satisfies FederationOptions\n \uFF08host.pages/remotePrefixes/deriveSpec \u2192 \u5177\u540D\u5BFC\u51FA hostPages\uFF1Bhost.remotes \u2192 \u9876\u5C42 remotes\uFF1Bremote.exposes \u2192 \u9876\u5C42 exposes\uFF1Bremote.setup \u2192 \u9876\u5C42 setup\uFF09\n \u5404\u9879\u76EE vite.config.ts\uFF1Aimport fulgurjsConfig from './fulgurjs.config' \u540E federation(fulgurjsConfig)\uFF1B\u5220\u9664\u7236\u76EE\u5F55\u805A\u5408\u6587\u4EF6"
173
+ );
174
+ }
302
175
  function fieldError(field, got, expect, example) {
303
176
  appConfigError(
304
177
  `fulgurjs.config.ts \u7684 ${field} \u5F62\u72B6\u4E0D\u5408\u6CD5\uFF08\u5B9E\u9645 ${JSON.stringify(got)}\uFF09`,
@@ -320,8 +193,8 @@ function validateAppOptions(options) {
320
193
  if (options[legacyField] !== void 0) {
321
194
  appConfigError(
322
195
  `\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`
196
+ "\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[]\uFF1B\u65E7\u805A\u5408\u914D\u7F6E\uFF08root + apps[]\uFF09\u5DF2\u5728 5.0.0 \u5220\u9664",
197
+ 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\u5DF2\u5220\u9664\u7684\u65E7\u805A\u5408\u914D\u7F6E\uFF08root + apps[]\uFF09\u3002\u5355\u9879\u76EE\u5F62\u6001\u8BF7\u5220\u9664\u8BE5\u5B57\u6BB5\u2014\u2014\u6BCF\u4E2A\u5E94\u7528\u4E00\u4EFD fulgurjs.config.ts\uFF08\u89C1 README\uFF09`
325
198
  );
326
199
  }
327
200
  }
@@ -342,17 +215,17 @@ function validateHostPages(value) {
342
215
  }
343
216
  return hp;
344
217
  }
345
- function validatePathsInsideApp(options, appRoot, fs3, path3) {
218
+ function validatePathsInsideApp(options, appRoot, fs3, path2) {
346
219
  const checkModule = (field, value) => {
347
220
  if (typeof value !== "string" || value.trim() === "") return;
348
- if (/^(https?:)?\/\//.test(value) || path3.isAbsolute(value)) {
221
+ if (/^(https?:)?\/\//.test(value) || path2.isAbsolute(value)) {
349
222
  appConfigError(
350
223
  `${field} "${value}" \u4E0D\u662F\u672C\u9879\u76EE\u5185\u7684\u6A21\u5757\u8DEF\u5F84`,
351
224
  "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
225
  `\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
226
  );
354
227
  }
355
- const abs = path3.resolve(appRoot, value);
228
+ const abs = path2.resolve(appRoot, value);
356
229
  if (!fs3.existsSync(abs)) {
357
230
  appConfigError(
358
231
  `${field} \u6307\u5411\u7684\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${value}`,
@@ -424,8 +297,8 @@ function resolveEsbuild(configPath) {
424
297
  async function loadAppConfig(configPath) {
425
298
  const fs3 = await import("node:fs");
426
299
  const os = await import("node:os");
427
- const path3 = await import("node:path");
428
- const abs = path3.resolve(configPath);
300
+ const path2 = await import("node:path");
301
+ const abs = path2.resolve(configPath);
429
302
  if (!fs3.existsSync(abs)) {
430
303
  appConfigError(
431
304
  `\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${abs}`,
@@ -435,11 +308,16 @@ async function loadAppConfig(configPath) {
435
308
  }
436
309
  if (abs.endsWith(".json")) {
437
310
  const parsed = JSON.parse(fs3.readFileSync(abs, "utf8"));
438
- if (isAggregateShape(parsed)) {
439
- const repo = await loadRepoConfig(abs);
440
- return { kind: "repo", configPath: abs, appRoot: path3.dirname(abs), repo };
441
- }
442
- return finishAppShape(parsed, {}, abs, path3.dirname(abs), fs3, path3);
311
+ if (isAggregateShape(parsed)) aggregateMigrationError();
312
+ return finishAppShape(parsed, {}, abs, path2.dirname(abs), fs3, path2);
313
+ }
314
+ const rawSource = fs3.readFileSync(abs, "utf8");
315
+ if (/@fulgurjs\/federation\/config/.test(rawSource)) {
316
+ appConfigError(
317
+ `\u914D\u7F6E\u5BFC\u5165\u4E86\u5DF2\u5220\u9664\u7684\u5B50\u8DEF\u5F84 "@fulgurjs/federation/config"`,
318
+ "defineRepoConfig / loadRepoConfig / federationOptionsForApp \u4E0E\u805A\u5408\u7C7B\u578B\uFF08RepoConfig \u7B49\uFF09\u6240\u5728\u7684 /config \u5B50\u8DEF\u5F84\u5DF2\u5728 5.0.0 \u5220\u9664\uFF1B\u5355\u9879\u76EE\u914D\u7F6E\u4E0D\u9700\u8981\u4EFB\u4F55\u8FD0\u884C\u65F6\u5305\u88C5\u51FD\u6570",
319
+ "\u5220\u9664\u8BE5\u5BFC\u5165\uFF0C\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u5199 federation() \u9009\u9879\u5BF9\u8C61\uFF1A\n import type { FederationOptions } from '@fulgurjs/federation'\n export default { name: 'my-app', exposes: { /* \u2026 */ } } satisfies FederationOptions"
320
+ );
443
321
  }
444
322
  const esbuild = resolveEsbuild(abs);
445
323
  const selfRedirect = {
@@ -464,21 +342,18 @@ async function loadAppConfig(configPath) {
464
342
  plugins: [selfRedirect],
465
343
  logLevel: "silent"
466
344
  });
467
- const tmpDir = fs3.mkdtempSync(path3.join(os.tmpdir(), "fulgurjs-appcfg-"));
345
+ const tmpDir = fs3.mkdtempSync(path2.join(os.tmpdir(), "fulgurjs-appcfg-"));
468
346
  try {
469
- const bundleFile = path3.join(tmpDir, "fulgurjs.config.bundle.mjs");
347
+ const bundleFile = path2.join(tmpDir, "fulgurjs.config.bundle.mjs");
470
348
  fs3.writeFileSync(bundleFile, out.outputFiles[0].text);
471
349
  const mod = await import(`${pathToFileURL(bundleFile).href}?t=${Date.now()}`);
472
- if (isAggregateShape(mod.default)) {
473
- const repo = await loadRepoConfig(abs);
474
- return { kind: "repo", configPath: abs, appRoot: path3.dirname(abs), repo };
475
- }
476
- return finishAppShape(mod.default, { hostPages: mod.hostPages }, abs, path3.dirname(abs), fs3, path3);
350
+ if (isAggregateShape(mod.default)) aggregateMigrationError();
351
+ return finishAppShape(mod.default, { hostPages: mod.hostPages }, abs, path2.dirname(abs), fs3, path2);
477
352
  } finally {
478
353
  fs3.rmSync(tmpDir, { recursive: true, force: true });
479
354
  }
480
355
  }
481
- function finishAppShape(def, named, configPath, appRoot, fs3, path3) {
356
+ function finishAppShape(def, named, configPath, appRoot, fs3, path2) {
482
357
  if (def === void 0 || def === null) {
483
358
  appConfigError(
484
359
  "fulgurjs.config.ts \u6CA1\u6709\u53EF\u7528\u7684\u9ED8\u8BA4\u5BFC\u51FA",
@@ -491,7 +366,7 @@ function finishAppShape(def, named, configPath, appRoot, fs3, path3) {
491
366
  }
492
367
  const options = def;
493
368
  validateAppOptions(options);
494
- validatePathsInsideApp(options, appRoot, fs3, path3);
369
+ validatePathsInsideApp(options, appRoot, fs3, path2);
495
370
  const hostPages = named.hostPages !== void 0 ? validateHostPages(named.hostPages) : void 0;
496
371
  return {
497
372
  kind: "app",
@@ -511,7 +386,6 @@ var TS_SYNTAX_PROBE;
511
386
  var init_app_config = __esm({
512
387
  "src/app-config.ts"() {
513
388
  "use strict";
514
- init_config();
515
389
  TS_SYNTAX_PROBE = "export default {} satisfies Record<string, unknown>";
516
390
  }
517
391
  });
@@ -533,36 +407,6 @@ async function writeConfigTemplate(target, force = false) {
533
407
  fs.writeFileSync(path.resolve(target), STARTER_CONFIG);
534
408
  return "written";
535
409
  }
536
- function remoteEntriesLiteral(remotes) {
537
- return Object.entries(remotes).map(([k, v]) => ` '${k}': { dev: '${v.dev}', prod: '${v.prod}' },`).join("\n");
538
- }
539
- function exposesLiteral(exposes) {
540
- return Object.entries(exposes).map(([k, v]) => ` '${k}': '${v}',`).join("\n");
541
- }
542
- function viteSnippetFor(app) {
543
- const hostRemotes = app.host ? remoteEntriesLiteral(app.host.remotes) : "";
544
- const remoteRemotes = app.remote?.remotes ? remoteEntriesLiteral(app.remote.remotes) : "";
545
- const remotesBlock = hostRemotes || remoteRemotes ? ` remotes: {
546
- ${hostRemotes || remoteRemotes}
547
- },
548
- ` : "";
549
- const exposesBlock = app.remote?.exposes ? ` exposes: {
550
- ${exposesLiteral(app.remote.exposes)}
551
- },
552
- ` : "";
553
- const setupBlock = app.remote?.setup ? ` setup: '${app.remote.setup}',
554
- ` : "";
555
- const sharedBlock = app.shared ? ` shared: {
556
- ${Object.entries(app.shared).map(([k, v]) => {
557
- const opts = [v.singleton ? "singleton: true" : "", v.requiredVersion ? `requiredVersion: '${v.requiredVersion}'` : ""].filter(Boolean);
558
- return ` '${k}': { ${opts.join(", ")} },`;
559
- }).join("\n")}
560
- },
561
- ` : "";
562
- return `federation({
563
- name: '${app.name}',
564
- ${remotesBlock}${exposesBlock}${setupBlock}${sharedBlock}})`;
565
- }
566
410
  function viteSnippetForAppMode(appRoot) {
567
411
  return `// ${appRoot}/vite.config.ts\uFF08\u8054\u90A6\u76F8\u5173\u884C\uFF1B\u5176\u4F59 Vite \u914D\u7F6E\u539F\u6837\u4FDD\u7559\uFF09
568
412
  import federation from '@fulgurjs/federation'
@@ -575,64 +419,6 @@ export default defineConfig({
575
419
  ],
576
420
  })`;
577
421
  }
578
- function nginxSnippetFor(cfg) {
579
- const listen = cfg.deploy?.listen ?? 8080;
580
- const webRoot = cfg.deploy?.webRoot ?? "/var/www/your-site";
581
- const hostApp = cfg.apps.find((a) => a.host) ?? cfg.apps[0];
582
- const hostIndex = `/${hostApp.base.replace(/^\/|\/$/g, "")}/index.html`.replace(/\/{2,}/g, "/");
583
- const blocks = cfg.apps.map(
584
- (a) => {
585
- const b = a.base === "/" || a.base === "" ? "/" : a.base.replace(/\/$/, "");
586
- return ` location ${b} {
587
- try_files $uri $uri/ ${hostIndex};
588
-
589
- location = ${b}/fulgurjs-remoteEntry.js {
590
- add_header Cache-Control "no-cache";
591
- add_header Access-Control-Allow-Origin "*";
592
- }
593
- location = ${b}/fulgurjs-manifest.json {
594
- add_header Cache-Control "no-cache";
595
- add_header Access-Control-Allow-Origin "*";
596
- }
597
- location = ${b}/index.html {
598
- add_header Cache-Control "no-cache";
599
- }
600
- }`;
601
- }
602
- ).join("\n\n");
603
- 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
604
- # \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
605
- # \u5E26 hash \u7684 assets \u624D\u914D\u957F\u7F13\u5B58\uFF1B\u8DE8\u6E90\u90E8\u7F72\u65F6\u4FDD\u7559 Access-Control-Allow-Origin\uFF09
606
- server {
607
- listen ${listen};
608
- root ${webRoot};
609
-
610
- ${blocks}
611
- }`;
612
- }
613
- function appSummary(app) {
614
- const role = app.host ? app.remote ? "\u5BBF\u4E3B+\u8FDC\u7A0B" : "\u5BBF\u4E3B" : "\u8FDC\u7A0B";
615
- const lines = [];
616
- lines.push(` ${app.name}\uFF08${role}\uFF0C\u76EE\u5F55 ${app.path}\uFF0Cdev \u7AEF\u53E3 ${app.port}\uFF0Cbase ${app.base}\uFF09`);
617
- if (app.host) {
618
- for (const [k, v] of Object.entries(app.host.remotes)) {
619
- lines.push(` \u6D88\u8D39\u8FDC\u7A0B ${k} \u2192 dev ${v.dev} / prod ${v.prod}`);
620
- }
621
- lines.push(` \u9875\u9762\u8DEF\u7531\u8868\uFF1A${app.host.pages?.length ?? 0} \u6761${app.host.pages ? "" : "\uFF08\u672A\u5728\u4ED3\u5E93\u914D\u7F6E\u4E2D\u63D0\u4F9B\u2014\u2014\u4EE5\u5E94\u7528\u4EE3\u7801\u9875\u9762\u8868\u4E3A\u51C6\uFF09"}`);
622
- }
623
- if (app.remote?.exposes) {
624
- lines.push(` exposes\uFF1A${Object.keys(app.remote.exposes).join("\u3001")}`);
625
- }
626
- if (app.remote?.setup) {
627
- lines.push(` setup\uFF08\u53EF\u9009\u8FDC\u7A0B\u521D\u59CB\u5316\uFF09\uFF1A${app.remote.setup}`);
628
- }
629
- if (app.remote?.remotes) {
630
- for (const [k, v] of Object.entries(app.remote.remotes)) {
631
- lines.push(` \u53CD\u5411\u6D88\u8D39 ${k} \u2192 dev ${v.dev} / prod ${v.prod}\uFF08\u53CC\u5411\u8054\u90A6\uFF09`);
632
- }
633
- }
634
- return lines.join("\n");
635
- }
636
422
  function appModeSummary(loaded) {
637
423
  const options = loaded.options;
638
424
  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"];
@@ -658,28 +444,11 @@ function appModeSummary(loaded) {
658
444
  async function inspectConfig(configPath) {
659
445
  const loaded = await loadAppConfig(configPath);
660
446
  const out = [];
661
- if (loaded.kind === "app") {
662
- out.push(`${MARK} \u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\uFF1A\u5355\u9879\u76EE\u5F62\u6001\uFF08\u9ED8\u8BA4\u5BFC\u51FA = federation() \u9009\u9879\uFF09`);
663
- out.push("\u5E94\u7528\u6458\u8981\uFF1A");
664
- out.push(...appModeSummary(loaded));
665
- 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");
666
- out.push(viteSnippetForAppMode(loaded.appRoot));
667
- 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");
668
- out.push(...COMMON_CHECKLIST);
669
- return out.join("\n");
670
- }
671
- const cfg = loaded.repo ?? await loadRepoConfig(loaded.configPath);
672
- 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`);
447
+ out.push(`${MARK} \u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\uFF1A\u5355\u9879\u76EE\u5F62\u6001\uFF08\u9ED8\u8BA4\u5BFC\u51FA = federation() \u9009\u9879\uFF09`);
673
448
  out.push("\u5E94\u7528\u6458\u8981\uFF1A");
674
- for (const app of cfg.apps) out.push(appSummary(app));
675
- 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");
676
- for (const app of cfg.apps) {
677
- out.push(`
678
- # ${app.path}\uFF08${app.name}\uFF09`);
679
- out.push(viteSnippetFor(app));
680
- }
681
- out.push("\n\u2500\u2500 NGINX \u7AD9\u70B9\u6837\u677F\uFF08\u6253\u5370\u6837\u677F\uFF0C\u4E0D\u5199\u6587\u4EF6\uFF09 \u2500\u2500");
682
- out.push(nginxSnippetFor(cfg));
449
+ out.push(...appModeSummary(loaded));
450
+ 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");
451
+ out.push(viteSnippetForAppMode(loaded.appRoot));
683
452
  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");
684
453
  out.push(...COMMON_CHECKLIST);
685
454
  return out.join("\n");
@@ -689,7 +458,6 @@ var init_init = __esm({
689
458
  "src/init.ts"() {
690
459
  "use strict";
691
460
  init_app_config();
692
- init_config();
693
461
  MARK = "[fulgurjs:init]";
694
462
  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
695
463
  //
@@ -746,7 +514,7 @@ export default {
746
514
  " \uFF08\u9000\u51FA\u65F6 clearAppContext \u6E05\u7406\uFF09\uFF0C\u8FDC\u7A0B setup/onSession \u7528 getAppContext / requireAppContext \u6D88\u8D39",
747
515
  "5. \u5E94\u7528\u4EE3\u7801\u552F\u4E00 API \u5165\u53E3\uFF1Aimport { loadRemote, provideAppContext, getAppContext, clearAppContext, definePages, createHostPages, remoteSchema, remoteComponent } from '@fulgurjs/federation/runtime'",
748
516
  '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',
749
- "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",
517
+ "7. \u914D\u7F6E\u89E3\u91CA\uFF1Afulgurjs explain\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",
750
518
  " \u90E8\u7F72\u4F53\u68C0\uFF1Afulgurjs doctor --base <URL> --apps <\u5BB9\u5668\u540D...>",
751
519
  "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"
752
520
  ];
@@ -883,24 +651,6 @@ __export(commands_exports, {
883
651
  stripRemoteNamePrefix: () => stripRemoteNamePrefix
884
652
  });
885
653
  import fs2 from "node:fs";
886
- import path2 from "node:path";
887
- function roleOf(app) {
888
- if (app.host && app.remote) return "dual";
889
- return app.host ? "host" : "remote";
890
- }
891
- function pageMappings(app) {
892
- const pages = app.host?.pages ?? [];
893
- const prefixes = Object.entries(app.host?.remotePrefixes ?? {}).sort((a, b) => b[0].length - a[0].length);
894
- const remoteOf = (route) => {
895
- for (const [prefix, name] of prefixes) {
896
- const p = prefix.endsWith("/") ? prefix : `${prefix}/`;
897
- if (route.startsWith(p) || `${route}/` === p) return name;
898
- }
899
- return null;
900
- };
901
- const derive = app.host?.deriveSpec ?? ((route) => route.split("/").filter(Boolean).slice(1).filter((s) => !s.startsWith(":")).join("/"));
902
- return mappingsOf({ pages, remotePrefixes: app.host?.remotePrefixes ?? {}, deriveSpec: app.host?.deriveSpec }, derive);
903
- }
904
654
  function mappingsOf(hp, deriveFallback) {
905
655
  const pages = hp.pages ?? [];
906
656
  const prefixes = Object.entries(hp.remotePrefixes ?? {}).sort((a, b) => b[0].length - a[0].length);
@@ -952,14 +702,8 @@ function chainLines(options, role) {
952
702
  }
953
703
  return chain;
954
704
  }
955
- function explainAppMode(loaded, appName) {
705
+ function explainAppMode(loaded) {
956
706
  const options = loaded.options;
957
- if (appName && appName !== options.name) {
958
- throw new Error(
959
- `[fulgurjs:explain] \u5355\u9879\u76EE\u914D\u7F6E\u53EA\u63CF\u8FF0\u672C\u5E94\u7528\uFF08name: "${options.name}"\uFF09\uFF0C\u4E0E --app "${appName}" \u4E0D\u4E00\u81F4
960
- \u4FEE\u6CD5: \u53BB\u6389 --app\uFF0C\u6216\u6539\u4E3A --app ${options.name}`
961
- );
962
- }
963
707
  const role = roleOfOptions(options);
964
708
  const devSharedSelfExplicit = options.devSharedSelf !== void 0;
965
709
  const devSharedSelfValue = devSharedSelfExplicit ? options.devSharedSelf === true : role !== "host";
@@ -967,7 +711,6 @@ function explainAppMode(loaded, appName) {
967
711
  return {
968
712
  app: options.name,
969
713
  role,
970
- mode: "app",
971
714
  path: loaded.appRoot,
972
715
  remotes: remotesOfOptions(options),
973
716
  exposes: Object.keys(options.exposes ?? {}),
@@ -979,65 +722,13 @@ function explainAppMode(loaded, appName) {
979
722
  chain: chainLines(options, role)
980
723
  };
981
724
  }
982
- function explainRepoMode(cfg, appPathOrName) {
983
- const app = cfg.apps.find((a) => a.path === appPathOrName || a.name === appPathOrName);
984
- if (!app) {
985
- throw new Error(
986
- `[fulgurjs:explain] \u5E94\u7528 "${appPathOrName}" \u4E0D\u5728\u914D\u7F6E\u4E2D\uFF08\u53EF\u7528\uFF1A${cfg.apps.map((a) => a.path).join("\u3001")}\uFF09`
987
- );
988
- }
989
- const opts = federationOptionsForApp(cfg, appPathOrName);
990
- const remotes = Object.entries(opts.remotes ?? {}).map(
991
- ([key, v]) => ({ key, dev: String(v.dev ?? v.external ?? ""), prod: String(v.prod ?? v.external ?? "") })
992
- );
993
- const shared = Object.entries(opts.shared ?? {}).map(
994
- ([name, v]) => ({ name, singleton: !!v.singleton, requiredVersion: v.requiredVersion ?? false })
995
- );
996
- const chain = [];
997
- chain.push(app.host ? "\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" : "\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");
998
- if (app.remote?.setup) {
999
- chain.push(`setup \u5165\u53E3 ${app.remote.setup}\uFF1A\u9ED8\u8BA4\u5BFC\u51FA\u5E94\u7528\u7EA7\u6267\u884C\u4E00\u6B21\uFF1B${"onSession"} \u6309\u5BBF\u4E3B sessionKey \u53BB\u91CD\uFF08\u7F3A sessionKey \u65F6\u62A5 MFU-013\uFF09`);
1000
- } else {
1001
- 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");
1002
- }
1003
- return {
1004
- app: app.name,
1005
- role: roleOf(app),
1006
- mode: "repo",
1007
- path: app.path,
1008
- base: app.base,
1009
- port: app.port,
1010
- remotes,
1011
- exposes: Object.keys(app.remote?.exposes ?? {}),
1012
- setup: app.remote?.setup,
1013
- shared,
1014
- devSharedSelf: {
1015
- value: opts.devSharedSelf === true,
1016
- source: app.devSharedSelf === void 0 ? "inferred" : "explicit"
1017
- },
1018
- pages: pageMappings(app),
1019
- 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",
1020
- chain
1021
- };
1022
- }
1023
- async function explainApp(configPath, appName) {
1024
- const loaded = await loadAppConfig(configPath);
1025
- if (loaded.kind === "repo") {
1026
- if (!appName) {
1027
- 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");
1028
- }
1029
- return explainRepoMode(loaded.repo, appName);
1030
- }
1031
- return explainAppMode(loaded, appName);
725
+ async function explainApp(configPath) {
726
+ return explainAppMode(await loadAppConfig(configPath));
1032
727
  }
1033
728
  function formatExplain(r) {
1034
729
  const roleText = r.role === "dual" ? "\u5BBF\u4E3B+\u8FDC\u7A0B\uFF08\u53CC\u89D2\u8272\uFF09" : r.role === "host" ? "\u5BBF\u4E3B" : "\u8FDC\u7A0B";
1035
730
  const L = [];
1036
- if (r.mode === "app") {
1037
- 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`);
1038
- } else {
1039
- 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`);
1040
- }
731
+ 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`);
1041
732
  if (r.remotes.length) {
1042
733
  L.push("\u6D88\u8D39\u8FDC\u7A0B\uFF1A");
1043
734
  for (const x of r.remotes) L.push(` ${x.key} \u2192 dev ${x.dev} / prod ${x.prod}`);
@@ -1100,31 +791,6 @@ function manifestUrlForRemoteAddress(addr) {
1100
791
  if (/fulgurjs-remoteEntry\.js$/.test(clean)) return clean.replace(/fulgurjs-remoteEntry\.js$/, "fulgurjs-manifest.json");
1101
792
  return `${clean}/fulgurjs-manifest.json`;
1102
793
  }
1103
- async function fetchRemoteManifestRepo(cfg, app, opts) {
1104
- const explicit = opts.manifests?.[app.name] ?? opts.manifests?.[app.path];
1105
- if (explicit) {
1106
- if (/^https?:\/\//.test(explicit)) {
1107
- const got2 = await manifestFromUrl(explicit);
1108
- return got2 ? { manifest: got2.manifest, from: explicit } : void 0;
1109
- }
1110
- const got = manifestFromFile(explicit);
1111
- return got ? { manifest: got, from: explicit } : void 0;
1112
- }
1113
- if (opts.site) {
1114
- const base = app.base === "/" ? "" : app.base.replace(/\/$/, "");
1115
- const url = `${opts.site.replace(/\/$/, "")}${base}/fulgurjs-manifest.json`;
1116
- const got = await manifestFromUrl(url);
1117
- if (got) return { manifest: got.manifest, from: got.url };
1118
- return void 0;
1119
- }
1120
- const candidates = [app.deployDir || app.base.replace(/^\/|\/$/g, ""), "dist"];
1121
- for (const dir of candidates) {
1122
- const p = path2.join(cfg.root, app.path, dir, "fulgurjs-manifest.json");
1123
- const got = manifestFromFile(p);
1124
- if (got) return { manifest: got, from: p };
1125
- }
1126
- return void 0;
1127
- }
1128
794
  async function fetchRemoteManifestApp(loaded, options, remoteName, opts) {
1129
795
  const explicit = opts.manifests?.[remoteName];
1130
796
  if (explicit) {
@@ -1220,83 +886,8 @@ async function checkPagesApp(loaded, opts) {
1220
886
  const unverified = issues.filter((i) => i.level === "unverified").length;
1221
887
  return { app: options.name, checked, issues, failed, unverifiedFailed: !!opts.requireVerified && unverified > 0, manifestSources: sources };
1222
888
  }
1223
- async function checkPagesRepo(cfg, appPathOrName, opts) {
1224
- const app = cfg.apps.find((a) => a.path === appPathOrName || a.name === appPathOrName);
1225
- if (!app) {
1226
- 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`);
1227
- }
1228
- const issues = [];
1229
- const pages = app.host?.pages ?? [];
1230
- const prefixes = app.host?.remotePrefixes ?? {};
1231
- if (pages.length === 0) {
1232
- issues.push({
1233
- level: "unverified",
1234
- 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"
1235
- });
1236
- return { app: app.name, checked: 0, issues, failed: false, unverifiedFailed: !!opts.requireVerified && issues.some((i) => i.level === "unverified"), manifestSources: [] };
1237
- }
1238
- const violations = validatePages(pages, { remotes: prefixes });
1239
- for (const v of violations) {
1240
- issues.push({ level: v.level === "error" ? "error" : "warn", message: v.message });
1241
- }
1242
- const remoteNames = [...new Set(Object.values(prefixes))];
1243
- const manifests = /* @__PURE__ */ new Map();
1244
- const sources = [];
1245
- for (const name of remoteNames) {
1246
- const remoteApp = cfg.apps.find((a) => a.name === name);
1247
- if (!remoteApp) {
1248
- 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` });
1249
- continue;
1250
- }
1251
- const got = await fetchRemoteManifestRepo(cfg, remoteApp, opts);
1252
- if (!got) {
1253
- const how = opts.manifests?.[name] ?? opts.manifests?.[remoteApp.path] ? `--manifest \u6307\u5B9A\u6765\u6E90\u4E0D\u53EF\u8FBE\u6216\u975E\u6709\u6548 manifest` : opts.site ? `--site ${opts.site} \u6309 base \u63A8\u5BFC\u7684 manifest URL \u4E0D\u53EF\u8FBE\uFF08\u663E\u5F0F\u6307\u5B9A\u6765\u6E90\u5931\u8D25\u65F6\u4E0D\u56DE\u9000\u672C\u5730 dist\uFF09` : "\u672C\u5730 dist \u672A\u547D\u4E2D\u4E14\u672A\u6307\u5B9A --site/--manifest";
1254
- issues.push({
1255
- level: "unverified",
1256
- 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
1257
- \u4FEE\u6CD5: \u5148\u6784\u5EFA\u8BE5\u8FDC\u7A0B\uFF08\u4EA7\u7269\u542B fulgurjs-manifest.json\uFF09\uFF0C\u6216\u7528 --site <URL> \u6307\u5411\u5DF2\u90E8\u7F72\u7AD9\u70B9\uFF0C\u6216 --manifest ${name}=<\u8DEF\u5F84|URL>`
1258
- });
1259
- continue;
1260
- }
1261
- manifests.set(name, { exposes: new Set([...normalizeExposes(got.manifest).keys()].map(normSpecKey)), from: got.from });
1262
- sources.push({ remote: name, from: got.from });
1263
- }
1264
- const derive = app.host?.deriveSpec ?? ((r) => r.split("/").filter(Boolean).slice(1).filter((s) => !s.startsWith(":")).join("/"));
1265
- let checked = 0;
1266
- for (const page of pages) {
1267
- const prefixHit = Object.entries(prefixes).sort((a, b) => b[0].length - a[0].length).find(
1268
- ([p]) => page.route.startsWith(p.endsWith("/") ? p : `${p}/`) || `${page.route}/` === (p.endsWith("/") ? p : `${p}/`)
1269
- );
1270
- if (!prefixHit) {
1271
- issues.push({ level: "error", message: `\u8DEF\u7531 "${page.route}" \u4E0D\u5728\u4EFB\u4F55 remotePrefixes \u524D\u7F00\u4E0B` });
1272
- continue;
1273
- }
1274
- checked++;
1275
- const m = manifests.get(prefixHit[1]);
1276
- if (!m) continue;
1277
- const spec = normSpecKey(String(page.spec ?? derive(page.route)));
1278
- if (!m.exposes.has(spec)) {
1279
- issues.push({
1280
- level: "error",
1281
- 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
1282
- \u8FDC\u7A0B\u5B9E\u9645 exposes\uFF08\u524D 10\uFF09\uFF1A${[...m.exposes].slice(0, 10).join("\u3001") || "\uFF08\u7A7A\uFF09"}
1283
- \u4FEE\u6CD5: \u6838\u5BF9\u8FDC\u7A0B federation({ exposes }) \u952E\u540D\u6216\u4FEE\u6B63\u9875\u9762\u8868 spec`
1284
- });
1285
- }
1286
- }
1287
- const failed = issues.some((i) => i.level === "error");
1288
- const unverifiedCount = issues.filter((i) => i.level === "unverified").length;
1289
- return { app: app.name, checked, issues, failed, unverifiedFailed: !!opts.requireVerified && unverifiedCount > 0, manifestSources: sources };
1290
- }
1291
- async function checkPages(configPath, appPathOrName, opts = {}) {
1292
- const loaded = await loadAppConfig(configPath);
1293
- if (loaded.kind === "repo") {
1294
- if (!appPathOrName) {
1295
- 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");
1296
- }
1297
- return checkPagesRepo(loaded.repo, appPathOrName, opts);
1298
- }
1299
- return checkPagesApp(loaded, opts);
889
+ async function checkPages(configPath, opts = {}) {
890
+ return checkPagesApp(await loadAppConfig(configPath), opts);
1300
891
  }
1301
892
  function formatCheckPages(r) {
1302
893
  const L = [];
@@ -1305,7 +896,7 @@ function formatCheckPages(r) {
1305
896
  const warns = r.issues.filter((i) => i.level === "warn");
1306
897
  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}`);
1307
898
  if (r.manifestSources?.length) {
1308
- L.push("manifest \u6765\u6E90\uFF08\u4F18\u5148\u7EA7\uFF1A--manifest > --site/prod \u63A8\u5BFC\uFF1B\u672C\u5730 dist \u4EC5\u5728\u672A\u6307\u5B9A\u4EFB\u4F55\u7EBF\u4E0A\u6765\u6E90\u65F6\u515C\u5E95\uFF1B\u4EE5\u5B9E\u9645\u547D\u4E2D\u7684\u6765\u6E90\u4E3A\u51C6\uFF09\uFF1A");
899
+ L.push("manifest \u6765\u6E90\uFF08\u4F18\u5148\u7EA7\uFF1A--manifest > --site/prod \u63A8\u5BFC\uFF1B\u663E\u5F0F\u6307\u5B9A\u6765\u6E90\u5931\u8D25\u4E0D\u56DE\u9000\u3001\u4EE5\u5B9E\u9645\u547D\u4E2D\u7684\u6765\u6E90\u4E3A\u51C6\uFF09\uFF1A");
1309
900
  for (const s of r.manifestSources) L.push(` ${s.remote} \u2190 ${s.from}`);
1310
901
  }
1311
902
  for (const i of [...errors, ...warns, ...unverified]) L.push(`
@@ -1322,7 +913,6 @@ var init_commands = __esm({
1322
913
  "src/commands.ts"() {
1323
914
  "use strict";
1324
915
  init_app_config();
1325
- init_config();
1326
916
  init_pages();
1327
917
  init_manifest();
1328
918
  DEFAULT_DERIVE = (route) => route.split("/").filter(Boolean).slice(1).filter((s) => !s.startsWith(":")).join("/");
@@ -1647,29 +1237,23 @@ var HELP = `fulgurjs \u2014 Vite Module Federation CLI (@fulgurjs/federation)
1647
1237
  fulgurjs init [--template <path>] [--force] \u751F\u6210\u5355\u9879\u76EE fulgurjs.config.ts \u8D77\u6B65\u6A21\u677F
1648
1238
  \uFF08\u9ED8\u8BA4\u5BFC\u51FA\u76F4\u63A5\u662F federation() \u9009\u9879\uFF09
1649
1239
  fulgurjs init --config <path> \u6821\u9A8C\u914D\u7F6E\uFF1B\u8F93\u51FA federation(fulgurjsConfig) \u63A5\u5165\u5757
1650
- \u4E0E\u63A5\u5165\u6838\u5BF9\u6E05\u5355\uFF08NGINX \u6837\u677F\u4EC5\u968F\u65E7\u805A\u5408\u914D\u7F6E\u6253\u5370\uFF09
1651
- fulgurjs explain [--config <path>] [--app <name>] [--json]
1652
- \u89E3\u91CA\u672C\u5E94\u7528\u6709\u6548\u8054\u90A6\u5F62\u6001\u4E0E\u52A0\u8F7D\u94FE\uFF08\u7EAF\u672C\u5730\uFF0C\u65E0\u7F51\u7EDC\uFF1B
1653
- \u5355\u9879\u76EE\u5F62\u6001\u514D --app\uFF0C\u65E7\u805A\u5408\u914D\u7F6E\u5FC5\u586B\uFF09
1654
- fulgurjs check-pages [--config <path>] [--app <name>] [--site <URL>]
1240
+ \u4E0E\u63A5\u5165\u6838\u5BF9\u6E05\u5355
1241
+ fulgurjs explain [--config <path>] [--json] \u89E3\u91CA\u672C\u5E94\u7528\u6709\u6548\u8054\u90A6\u5F62\u6001\u4E0E\u52A0\u8F7D\u94FE\uFF08\u7EAF\u672C\u5730\uFF0C\u65E0\u7F51\u7EDC\uFF09
1242
+ fulgurjs check-pages [--config <path>] [--site <URL>]
1655
1243
  [--manifest <remote>=<\u8DEF\u5F84|URL>]... [--require-verified] [--json]
1656
1244
  \u6838\u5BF9\u5BBF\u4E3B\u9875\u9762\u8868\u4E0E\u8FDC\u7A0B exposes\uFF08\u5BBF\u4E3B\u9879\u76EE\u8FD0\u884C\uFF1B
1657
1245
  manifest \u6765\u6E90\u4F18\u5148\u7EA7 --manifest > --site/prod \u63A8\u5BFC\uFF0C
1658
- \u663E\u5F0F\u6307\u5B9A\u6765\u6E90\u5931\u8D25\u4E0D\u56DE\u9000\u672C\u5730 dist\uFF1B\u672C\u5730 dist \u4EC5\u5728
1659
- \u672A\u6307\u5B9A\u4EFB\u4F55\u7EBF\u4E0A\u6765\u6E90\u65F6\u515C\u5E95\uFF1B\u786E\u5B9A\u6027\u9519\u8BEF\u975E\u96F6\u9000\u51FA\uFF1B
1246
+ \u663E\u5F0F\u6307\u5B9A\u6765\u6E90\u5931\u8D25\u4E0D\u56DE\u9000\uFF1B\u786E\u5B9A\u6027\u9519\u8BEF\u975E\u96F6\u9000\u51FA\uFF1B
1660
1247
  --require-verified \u65F6\u65E0\u6CD5\u9A8C\u8BC1\u4E5F\u975E\u96F6\uFF09
1661
1248
  fulgurjs doctor --base <URL> --apps <a,b,c> [--dev] [--json] [--chunk-sample N]
1662
1249
  fulgurjs --help
1663
1250
 
1664
- \u793A\u4F8B\uFF08\u5355\u9879\u76EE\u5F62\u6001\uFF0C\u5E94\u7528\u6839\u76EE\u5F55\u5185\u8FD0\u884C\uFF09\uFF1A
1251
+ \u793A\u4F8B\uFF08\u5E94\u7528\u6839\u76EE\u5F55\u5185\u8FD0\u884C\uFF09\uFF1A
1665
1252
  fulgurjs init # \u5F53\u524D\u76EE\u5F55\u5199 fulgurjs.config.ts\uFF08\u5DF2\u5B58\u5728\u5219\u62D2\u7EDD\uFF0C--force \u8986\u76D6\uFF09
1666
1253
  fulgurjs explain # \u89E3\u91CA\u672C\u5E94\u7528\uFF08--config \u6307\u5411\u5176\u4ED6\u8DEF\u5F84\u65F6\u663E\u5F0F\u4F20\uFF09
1667
1254
  fulgurjs check-pages --site http://your-site # \u6309 remotes prod \u5730\u5740\u63A8\u5BFC\u8FDC\u7A0B manifest \u6838\u5BF9
1668
1255
  fulgurjs check-pages --manifest remote-a=https://cdn.example.com/remote-a/fulgurjs-manifest.json
1669
1256
  fulgurjs doctor --base http://your-site --apps my-app,remote-a
1670
-
1671
- \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
1672
- explain/check-pages \u9700 --app <\u5E94\u7528\u76EE\u5F55\u540D\u6216\u5BB9\u5668\u540D>\u3002
1673
1257
  `;
1674
1258
  async function main() {
1675
1259
  const argv = process.argv.slice(2);
@@ -1689,7 +1273,7 @@ async function main() {
1689
1273
  if (a !== k) return;
1690
1274
  const v = argv[i + 1];
1691
1275
  const eq = v?.indexOf("=");
1692
- if (!v || !eq || eq < 1) return;
1276
+ if (!v || eq === void 0 || eq < 1) return;
1693
1277
  out[v.slice(0, eq)] = v.slice(eq + 1);
1694
1278
  });
1695
1279
  return out;
@@ -1726,11 +1310,18 @@ async function main() {
1726
1310
  return 0;
1727
1311
  }
1728
1312
  if (cmd === "explain" || cmd === "check-pages") {
1729
- const app = argOf("--app");
1313
+ if (has("--app")) {
1314
+ console.error(
1315
+ `[fulgurjs] \u4E0D\u518D\u652F\u6301 --app \u53C2\u6570
1316
+ \u6839\u56E0\uFF1A--app \u662F 4.1.0 \u805A\u5408\u914D\u7F6E\uFF08root + apps[]\uFF09\u7684\u5E94\u7528\u9009\u62E9\u5668\uFF0C\u805A\u5408\u94FE\uFF08@fulgurjs/federation/config\u3001defineRepoConfig\u3001loadRepoConfig\u3001federationOptionsForApp\uFF09\u5DF2\u5728 5.0.0 \u5220\u9664
1317
+ \u4FEE\u6CD5\uFF1A\u6BCF\u4E2A\u5E94\u7528\u6839\u76EE\u5F55\u4E00\u4EFD fulgurjs.config.ts\uFF0C\u5728\u5E94\u7528\u76EE\u5F55\u5185\u76F4\u63A5\u8FD0\u884C fulgurjs ${cmd}\uFF08\u53BB\u6389 --app\uFF09`
1318
+ );
1319
+ return 2;
1320
+ }
1730
1321
  try {
1731
1322
  if (cmd === "explain") {
1732
1323
  const { explainApp: explainApp2, formatExplain: formatExplain2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
1733
- const r2 = await explainApp2(resolve(argOf("--config") ?? "fulgurjs.config.ts"), app);
1324
+ const r2 = await explainApp2(resolve(argOf("--config") ?? "fulgurjs.config.ts"));
1734
1325
  console.log(has("--json") ? JSON.stringify(r2, null, 2) : formatExplain2(r2));
1735
1326
  return 0;
1736
1327
  }
@@ -1740,7 +1331,7 @@ async function main() {
1740
1331
  ...Object.keys(kvAllOf("--manifest")).length ? { manifests: kvAllOf("--manifest") } : {},
1741
1332
  ...has("--require-verified") ? { requireVerified: true } : {}
1742
1333
  };
1743
- const r = await checkPages2(resolve(argOf("--config") ?? "fulgurjs.config.ts"), app, opts);
1334
+ const r = await checkPages2(resolve(argOf("--config") ?? "fulgurjs.config.ts"), opts);
1744
1335
  console.log(has("--json") ? JSON.stringify(r, null, 2) : formatCheckPages2(r));
1745
1336
  return r.failed || r.unverifiedFailed ? 1 : 0;
1746
1337
  } catch (e) {