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

  1. Replace the deep import with the package root import: `import { x } from 'vue'` instead of `import { x } from 'vue/dist/...'`.
  2. If you genuinely need the subpath, switch the build to IIFE output (format: 'iife').
  3. 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

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


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/030d3c1ae808448b. Report an issue: GitHub.