Quick Start
Getting started with Fuma CLI.
Getting Started
Installation
npm i fuma-cliCompile
Like a bundler config, a registry has entries and rules:
import { compile, writeRegistry } from "fuma-cli/compiler";
const out = await compile({
root: {
name: "acme-ui",
// paths below are relative to it
dir: "src",
// what consumers install: name -> entry file
components: {
button: { title: "Button", entry: "button.tsx" },
},
// how files are installed: glob pattern -> rule
files: {
// `type` specifies where the file is installed
"button.tsx": { type: "ui" },
"utils/*": { type: "lib" },
},
},
});
await writeRegistry(out, {
dir: "./public/registry",
cleanDir: true,
});Files imported by button.tsx are installed along, such as utils/cn.ts. They only need a matching rule, see Files for all options.
node ./scripts/compile.tsServe the output, here we assume it is available at https://acme-ui.com/registry.
Implement Installer
Initialize your own CLI package and install dependencies:
npm i fuma-cli @clack/promptsFuma CLI installer is headless, we will use @clack/prompts for the TUI.
import { ComponentInstaller } from "fuma-cli/registry/installer";
import { HttpRegistryConnector } from "fuma-cli/registry/connector";
import { confirm, isCancel, log } from "@clack/prompts";
const installer = new ComponentInstaller(
new HttpRegistryConnector("https://acme-ui.com/registry"),
{
io: {
async confirmFileOverride(file) {
const value = await confirm({
message: `Do you want to override ${file.output}?`,
initialValue: false,
});
return !isCancel(value) && value;
},
onFileWritten(file) {
log.step(file.output);
},
},
},
);
export async function install(name: string) {
const plan = await installer.install(name);
const deps = await plan.deps();
if (deps.hasRequired()) await deps.installRequired();
}import { install } from "../src/install";
await install("button");Examples
Interactive Install UI
Let the user select components from the manifest.
import { autocompleteMultiselect, isCancel } from "@clack/prompts";
const manifest = await installer.fetchManifest();
const options = [];
for (const item of manifest.components) {
if (item.unlisted) continue;
options.push({ label: item.title ?? item.name, value: item.name, hint: item.description });
}
const value = await autocompleteMultiselect({
message: "Select components to install",
options,
});
if (!isCancel(value)) {
for (const name of value) await install(name);
}@fuma-cli/interactive ships this UI pre-built.
Last updated on