Buttery ComponentsHeadless, accessible & style method agnostic React components that you can import, re-export and/or copy & paste
Buttery CommandsBuild a TS CLI the same way you would define NextJS or Remix routes
Buttery DocsCo-located, SSR ready, dead simple .md & .mdx docs
Buttery TokensEasily create, use, and scale a pure CSS design token system with 100% type-safety
Buttery LogsIsomorphic logging for full-stack apps
Buttery MetaSSR'd meta tags for your SSR'd React app
@buttery/core/builder
A @buttery/core sub-path export that uses esbuild to quickly and consistently transpile and bundle any of the @buttery tools or supporting libraries to be used for consumption either via import or via the @buttery/cli.
Purpose
To create a consistent and minified build of any of the buttery packages so they could easily be used in the @buttery/cli.
Typically, we wouldn't need to bundle but it's important that we do to ensure that we can run this code using a shebang in our CLI. When TypeScript builds the project, it can easily reason about the endings on a file so importing a file like the
import { someFunction } from "./some-function"works fine, but when running the code using a shebang, node cannot reason about the line endings and it specifically needs the.jsextension. Bundling the necessary files together ensures that the script can be run in both contexts.
Installation
yarn add @buttery/core
Usage
import { ... } from "@buttery/core/builder"
API
There are 2 ways to run the builder and for 2 very distinct purposes.
- Build and bundle the scripts needed to be run in the CLI
- Build and bundle the library needed to be used in the CLI
The builder should only be used to build some of the various @buttery tools packages, it makes a few assumptions about the directory structure as well as the names of the files it's looking for.
Why esbuild instead of tsc?
Node can't resolve any imports that don't have their extensions (unless you enable a feature flag per platform). So in order to ensure that we do away with that without completely changing our TSConfig, we bundle them together so all of the necessary code is in one file that can be run using a shebang.
Build scripts for the CLI
The builder looks for any files in the /src/cli-scripts directory. This convention is the way that it is since the scripts that are being built are runnable, meaning they should be runnable in the CLI or independently elsewhere.
So if we had a CLI that wanted to run a dev command from our package, the convention would be /src/cli-scripts/dev.ts.
Consider the below structure:
|- scripts/
|- scripts.build.ts
|- src/
|- cli-scripts/
|- dev.ts
|- build.ts
|- format.ts
In order to build the scripts, we create a scripts/scripts.build.ts file that will look like the below:
// scripts/dist.build.ts
import { build } from "@buttery/core/builder";
build({ mode: "cli-scripts" });
When we run this script using tsx from the package.json using yarn, the @buttery/core/builder will find all 3 of the scripts located in the src/cli-scripts directory, build and bundle them independently into the /dist directory.
Build a library for the CLI
There might be times where we are bundling a library together that doesn't have any scripts to run it, but still needs to be bundled in order to work in the CLI.
For instance, @buttery/core is used in almost every single one of the @buttery/tools scripts so it needs to have itself bundled as well. In this case, we use the @buttery/core/builder to build a library into the dist directory rather than looking for a specific convention.
Due to this reason, the builder doesn't make any assumptions about the folder structure of the package. Instead it just requires an array of entry points in which to build.
|- src/
|- index.ts
|- scripts/
|- library.build.ts
// scripts/library.build.ts
import path from "node:path";
import { build } from "@buttery/core/builder";
build({ mode: "loose" entryPoints: [path.resolve(import.meta.dirname, "../src/index.ts")]});
We simply define an entry point of what we want to build it bundles and build's it into the /dist directory when use tsx to run the scripts/library.build.ts file.
