halo-dev/halo · error · Error
Unsupported shared dependency subpath ${specifier} imported
Error message
Unsupported shared dependency subpath ${specifier} imported by ${sourceId}. Import the ${deepRoot} package root or select IIFE output. What it means
Thrown by SharedDependencyValidator.validateImport when a source module imports a shared dependency via a deep subpath (e.g. 'vue/dist/vue.runtime.esm-bundler.js', '@halo-dev/components/Foo'). ESM provider output externalizes only the package root so the host can supply one shared copy; a subpath import cannot be mapped to the host's externalized global, so the build rejects it to avoid shipping a duplicate or a broken reference.
Source
Thrown at ui/packages/ui-plugin-bundler-kit/src/shared-dependencies.ts:52
>();
constructor(options: SharedDependencyValidatorOptions) {
this.#snapshot = options.snapshot;
this.#providerRoot = path.resolve(options.providerRoot);
}
async validateSource(code: string, sourceId: string) {
for (const specifier of parseImports(code)) {
await this.validateImport(specifier, sourceId);
}
}
async validateImport(specifier: string, sourceId: string) {
const deepRoot = SHARED_PACKAGE_ROOTS.find((root) =>
specifier.startsWith(`${root}/`)
);
if (deepRoot) {
throw new Error(
`Unsupported shared dependency subpath ${specifier} imported by ${sourceId}. ` +
`Import the ${deepRoot} package root or select IIFE output.`
);
}
if (!isSharedPackageRoot(specifier)) {
return false;
}
await this.validateResolvedRoot(specifier, sourceId);
return true;
}
getValidatedRoots() {
return [...this.#validatedRoots];
}
getBuildReport(): SharedDependencyBuildReport {
const roots = SHARED_PACKAGE_ROOTS.filter((root) =>View on GitHub (pinned to d2f5165f9c)
Solutions
- Replace the deep import with the package root import: `import { x } from 'vue'` instead of `import { x } from 'vue/dist/...'`.
- If you genuinely need the subpath, switch the build to IIFE output (format: 'iife').
- Audit the offending sourceId named in the message and grep its import statements for any of the 10 shared roots followed by '/'.
Example fix
// before
import { nextTick } from "vue/dist/vue.runtime.esm-bundler.js";
// after
import { nextTick } from "vue"; Defensive patterns
Strategy: validation
Validate before calling
import { SHARED_PACKAGE_ROOTS } from "@halo-dev/ui-plugin-bundler-kit/runtime-snapshot";
function assertNoSharedSubpath(specifier: string, sourceId: string) {
const deep = SHARED_PACKAGE_ROOTS.find((r) => specifier.startsWith(`${r}/`));
if (deep) {
throw new Error(`${sourceId}: import ${specifier} — import the ${deep} root, not a subpath.`);
}
} Type guard
import { SHARED_PACKAGE_ROOTS } from "@halo-dev/ui-plugin-bundler-kit/runtime-snapshot";
function isSharedRootImport(specifier: string): boolean {
return SHARED_PACKAGE_ROOTS.some((r) => specifier === r) ||
!SHARED_PACKAGE_ROOTS.some((r) => specifier.startsWith(`${r}/`));
} Prevention
- Lint plugin source for `from "(vue|@halo-dev/...)/` patterns and fail the PR.
- Always import shared packages by their root entry only.
- Use IIFE output if a dependency forces subpath imports you cannot change.
When it happens
Trigger: A plugin source file contains `import x from 'vue/...'`, `import '@halo-dev/components/...'`, or any specifier starting with one of SHARED_PACKAGE_ROOTS followed by '/'. Fires during the transform hook (per-module) of the halo:esm-ui-provider Vite plugin.
Common situations: Copying a snippet that imports 'vue/jsx-runtime' or a deep CSS path; a library re-export that resolves to a subpath; using 'axios/' internals; importing a specific subpath for tree-shaking that worked under IIFE but breaks under ESM.
Related errors
- ${root} resolved to invalid version ${resolved.version} at $
- ${root} snapshot version must be stable semver.
- ${root} snapshot exports must be unique identifiers.
- ${root} snapshot runtime descriptor is invalid.
- Explicit ESM output requires a simple stable spec.requires t
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/030d3c1ae808448b.
Report an issue: GitHub.