Compiler

Registry

Configure the registries to compile.

Overview

A registry is a directory of source files that belongs to a package. It is configured like a bundler: components are the entries, and files are the rules for installing them.

import { compile, writeRegistry } from "fuma-cli/compiler";

const out = await compile({
  root: {
    name: "acme-ui",
    dir: "packages/ui/src",
    components: {
      button: "button.tsx",
    },
    files: {
      "button.tsx": { type: "ui" },
      "utils/*": { type: "lib" },
    },
  },
});

await writeRegistry(out, { dir: "public/registry" });

compile() starts from the entries, follows the imports of each installed file, and returns the output in memory.

Options

OptionDescription
nameUnique name, it prefixes file IDs like acme-ui:button.tsx.
dirThe source directory, file paths are relative to it.
componentsWhat consumers can install, see below.
filesGlob pattern to the rule for installing matched files, see Files.
entriesSource files of package exports, see below.
externalPaths the consumer is expected to own, imports of them are kept as-is.
dependenciesOverride the version of dependencies, null for the latest.
subRegistriesRegistries compiled together, files can reference each other across them.

components

A component is a named list of entry files. Files imported by an entry are installed along, they don't need to be listed.

const registry: Registry = {
  name: "acme-ui",
  dir: "src",
  components: {
    // one entry
    card: "card/index.tsx",
    // multiple entries
    form: ["form/input.tsx", "form/select.tsx"],
    // with info
    button: { title: "Button", description: "A clickable button", entry: "button.tsx" },
  },
  files: {
    "**": { type: "components", target: "<dir>/*" },
  },
};
FieldDescription
entryEntry files, relative to dir.
titleDisplay name.
descriptionShort description.
unlistedHide from component lists, still installable.
  • Every entry must match a rule in files, otherwise the compilation fails.
  • A file can be an entry of multiple components. To offer several components as one, like all, list all their entries.

Entries can be generated, a single rule covers all of them:

import path from "node:path";
import { glob } from "tinyglobby";

const components: Registry["components"] = {};
for (const file of await glob("icons/*.tsx", { cwd: "src" })) {
  components[path.basename(file, ".tsx")] = file;
}

entries

The compiler needs to know which source file is behind each export of your package, to keep package imports in installed code.

By default, it reads exports in package.json and maps dist to dir:

exportsSource file
"./button": "./dist/button.js"<dir>/button.tsx (or .ts)
".": { "import": "./dist/index.js" }<dir>/index.ts

Specify it when your build doesn't mirror the source directory:

const registry: Registry = {
  name: "acme-ui",
  dir: "src",
  entries: {
    ".": "index.ts",
    "./button": "components/button.tsx",
  },
};

external

Some files only exist for your own app, and the consumer has their own version.

const registry: Registry = {
  name: "docs",
  dir: ".",
  // `import { source } from "@/lib/source"` is kept as-is
  external: ["lib/source.ts"],
};

dependencies

Versions are taken from package.json of the registry (dependencies, peerDependencies, then devDependencies).

  • Packages of registries in the same compilation use their current version.
  • Protocols like workspace:* are replaced with the installed version.
  • A package only listed as @types/* is added as a dev dependency.
const registry: Registry = {
  name: "acme-ui",
  dir: "src",
  dependencies: {
    // always the latest
    "acme-core": null,
    // inlined by our bundler, but needed by installed files
    "fast-content-type-parse": "^3.0.0",
  },
};

Sub Registries

const registry: Registry = {
  name: "acme",
  dir: "apps/docs",
  subRegistries: [
    { name: "acme/ui", dir: "packages/ui/src" },
    { name: "acme/charts", dir: "packages/charts/src" },
  ],
};

A file in acme/charts can import acme-ui/button or ../../ui/src/button, both resolve to the same installable file.

Last updated on

On this page