You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Filed unassigned from the domain:cli lane while implementing #10769 (the host-importer reachability class). Recording only — out of scope there, and it moves app-config plugin loading, so it wants its own decision.
The site
packages/cli/src/commands/serve.ts:2677 (measured on the #10769 branch):
if(typeofplugin==='string'){try{constimported=awaitimport(plugin);pluginToLoad=imported.default||imported;}catch(importError: any){thrownewError(`Failed to import plugin '${plugin}': ${importError.message}`);}}
plugin comes from the served app's own objectstack.config.tsplugins: [...] array. It is therefore an app-supplied specifier by construction — the single most app-owned specifier in the whole file — and it is loaded with a bare import(), which Node ESM resolves against the CLI's realpath.
So an app that writes plugins: ['@acme/my-plugin'] and declares @acme/my-plugin in its own package.json can only be served if that package happens to be hoisted somewhere the CLI can see. In a dev checkout it is; in a real distribution layout it is not. This is the same mechanism as cloud#1013 and #10645, on the documented extension path.
#10769 makes importFromHost reachable from every line of serve.ts and widens the source scan to every app-declarable optional load, classifying a package as app-declarable exactly when packages/cli's own manifest does not declare it. That classification is static, and this specifier is not: the scan cannot know what an app will put in its config. It is enumerated in that PR's UNRESOLVABLE_BARE_IMPORTS allowlist with a pointer to this card rather than being silently passed over.
What the fix probably is
await importFromHost(plugin) — the helper is now reachable at that line. createHostImporter is a strict superset of a bare import() for bare package names (declared by the host resolves from the host; undeclared falls back to the CLI's own resolution), and it passes non-package specifiers (relative paths, file:// URLs) straight through, which the plugins: ['./local-plugin.js'] spelling relies on.
it changes the error message on a missing plugin — the wrapper above nests importError.message, which becomes the long multi-line createHostRequire 认 NODE_PATH,于是 #4699 立下的「host app 必须自己声明」在 pnpm 工作区里根本没被强制 #4719 "declare it in that app's package.json" text. That is arguably a better diagnostic, but it is a visible change to a user-facing failure and nothing currently pins it;
an app that declares a plugin the CLI also declares would start getting its own copy instead of the CLI's. That is very likely correct, but it is a resolution-policy decision (see the sibling finding on the capability loop), not a mechanical repair.
Filed unassigned from the
domain:clilane while implementing #10769 (the host-importer reachability class). Recording only — out of scope there, and it moves app-config plugin loading, so it wants its own decision.The site
packages/cli/src/commands/serve.ts:2677(measured on the #10769 branch):plugincomes from the served app's ownobjectstack.config.tsplugins: [...]array. It is therefore an app-supplied specifier by construction — the single most app-owned specifier in the whole file — and it is loaded with a bareimport(), which Node ESM resolves against the CLI's realpath.So an app that writes
plugins: ['@acme/my-plugin']and declares@acme/my-pluginin its ownpackage.jsoncan only be served if that package happens to be hoisted somewhere the CLI can see. In a dev checkout it is; in a real distribution layout it is not. This is the same mechanism as cloud#1013 and #10645, on the documented extension path.Why #10769 did not fix it
#10769 makes
importFromHostreachable from every line ofserve.tsand widens the source scan to every app-declarable optional load, classifying a package as app-declarable exactly whenpackages/cli's own manifest does not declare it. That classification is static, and this specifier is not: the scan cannot know what an app will put in its config. It is enumerated in that PR'sUNRESOLVABLE_BARE_IMPORTSallowlist with a pointer to this card rather than being silently passed over.What the fix probably is
await importFromHost(plugin)— the helper is now reachable at that line.createHostImporteris a strict superset of a bareimport()for bare package names (declared by the host resolves from the host; undeclared falls back to the CLI's own resolution), and it passes non-package specifiers (relative paths,file://URLs) straight through, which theplugins: ['./local-plugin.js']spelling relies on.The reason this was not just done in #10769:
importError.message, which becomes the long multi-linecreateHostRequire认 NODE_PATH,于是 #4699 立下的「host app 必须自己声明」在 pnpm 工作区里根本没被强制 #4719 "declare it in that app's package.json" text. That is arguably a better diagnostic, but it is a visible change to a user-facing failure and nothing currently pins it;Not a duplicate
serve.ts's host-anchored importer is a mid-functionconst, so any app-declared optional package loaded ABOVE it silently falls back to CLI-anchored resolution — this has now shipped twice #10769 is the reachability class and the static sweep; this is the specifier that sweep provably cannot classify.createHostRequire认 NODE_PATH,于是 #4699 立下的「host app 必须自己声明」在 pnpm 工作区里根本没被强制 #4719 is whether a package may load; this is where it resolves from.