Compiler

Imports

How the compiler handles each import of an installable file.

Resolution

The compiler collects an import record for each reference in a file, then resolves it, including tsconfig paths.

KindSyntax
import-statementimport ... from "x", export ... from "x"
dynamic-importimport("x")
new-urlnew URL("./x", import.meta.url)
The import resolves toInstalled code
a Node.js built-in, or a macrounchanged
a package outside of registriesunchanged, added to dependencies
a path under externalunchanged
a file matching a rule in filesrelative import of the installed file
a file matching a rule with preservepackage import, or relative if installed
a file exported by its package, without a rulepackage import
anything elsecompilation error

Files excluded from tsconfig.json

A file written for the consumer's codebase is often excluded from your tsconfig.json, so paths no longer apply to it and @/lib/source fails as a missing dependency. Give it a tsconfig.json:

registry/tsconfig.json
{
  "extends": "../tsconfig.json",
  "include": ["build-graph.ts"],
  "exclude": []
}

Package Imports

Installed code often needs things that must stay in your package, like React contexts, which are only the same instance when imported from the package.

You don't declare them. The compiler follows the re-exports of each entry, and knows where every name is publicly available.

src/index.ts
export * from "./context";
export { useTheme as useAcmeTheme } from "./theme";
src/card/index.tsx
import { useCtx } from "../context";
import { useTheme, type Theme } from "../theme";
import * as icons from "../icons";
  • Names are matched individually, renamed exports are handled.
  • Namespace, side-effect and dynamic imports need the file to be an entry itself.
  • When a name is exported from multiple entries, the first one in exports wins.
  • Private packages ("private": true) are never imported, their files need a rule.

Errors

An import that cannot be installed nor swapped fails the compilation, with all problems reported at once:

src/card/index.tsx: "../theme" matches no rule in `files` of registry "acme-ui",
and internalOnly of it is not a public export of "acme-ui". Add a rule for theme.ts,
or export it from the package.

This is checked against your source, so a registry never ships an import that your package doesn't satisfy.

Cross-Registry Imports

Imports of another registry in the same compilation follow the same table, whether written as a relative path or a package specifier.

packages/charts/src/chart.tsx
// matches a rule of `acme-ui` -> relative import of the installed button
import { Button } from "acme-ui/button";
// no rule, but an entry -> unchanged
import { useCtx } from "acme-ui";

Last updated on

On this page