💥 Crackle
A build tool for apps and packages, static and server-rendered sites. Built on Vite, Rollup and esbuild.
Features
Contents
Getting started
pnpm add --save-dev @crackle/cli
Crackle will look for a crackle.config.ts
file in the project directory, but if one doesn't exist, it will use the default configuration.
Here's how to specify a custom configuration file:
import { defineConfig } from '@crackle/cli/config';
export default defineConfig({
});
or
import type { UserConfig } from '@crackle/cli/config';
export default {
} satisfies UserConfig;
(the default config values are documented in the type UserConfig
)
Commands
You can find the full list of commands by running crackle --help
.
The most common ones are listed below.
crackle package
Compile the package for publishing.
This will compile TypeScript files to CJS- and ESM-compatible files and generate TypeScript declaration files (.d.ts
files) for entry points.
Passing the --fix
parameter will also run crackle fix
.
The default entry point is src/index.ts
.
Multiple (nested) entry points are supported, by adding .ts
files to src/entries/
.
Entry points
Given this directory structure:
src
├── entries
│ ├── components.ts
│ └── themes
│ └── apac.ts
└── index.ts
Crackle will generate these entry points:
my-project (main entry point; mapped to src/index.ts)
my-project/components (mapped to src/entries/components.ts)
my-project/themes/apac (mapped to src/entries/themes/apac.ts)
Externals
If a dependency is present in devDependencies
(but not in peerDependencies
) it is bundled along with the project's source code.
dependencies
, peerDependencies
and optionalDependencies
are marked as external and not bundled.
Package mode
crackle package --mode=bundle
crackle package --mode=preserve
This controls how Crackle generates output files.
bundle
rolls up output files into as few chunks as possible (default behaviour)preserve
creates separate files for all modules using the original module names as file names.
This is similar to Rollup's output.preserveModules
, but allows more fine-grained control because we hook into output.manualChunks
.
The mode can also be configured via crackle.config.ts
:
import { defineConfig } from '@crackle/cli/config';
export default defineConfig({
package: {
mode: 'preserve',
},
});
DTS mode
Some libraries declare namespaces, which are hard/impossible to bundle.
For such cases, Crackle has an option to preserve the file structure of the generated .d.ts
files.
import { defineConfig } from '@crackle/cli/config';
export default defineConfig({
dts: {
mode: 'preserve',
},
});
bundle
rolls up output files into as few chunks as possible (default behaviour)preserve
creates separate files for all modules using the original module names as file names.
This is similar to Rollup's output.preserveModules
.
crackle dev
Generate entry points for local development.
This will generate stub entry points for local development.
Stub entry points import the source files directly instead of the compiled files.
Shim mode
By default, Crackle generates a require
shim which enables the loading of TypeScript files in Node.js using a require hook.
There are situations where this is not required, such as when using a bundler that supports TypeScript natively, e.g. esbuild or Vite.
In these cases, the --shim
option can be set to none
.
crackle dev --shim=require
crackle dev --shim=none
require
generates a shim for use in Node.js (default behaviour)none
doesn't generate a require
shim
This can also be configured via crackle.config.ts
:
import { defineConfig } from '@crackle/cli/config';
export default defineConfig({
dev: {
shim: 'none',
},
});
crackle fix
Updates package.json
exports, files, sideEffects
field and more:
package.json
: "main"
, "module"
and "types"
are updated to point to the generated files in dist
package.json
: "exports"
and "files"
are updated to include generated entry pointspackage.json
: "sideEffects"
flag is updated to match the generated files in dist
package.json
: keys are sorted using sort-package-json
.gitignore
is updated to ignore backwards-compatible entry points
Side-effects
Crackle updates the sideEffects
flag if needed.
If an entry point has side-effects (as defined via package.json
's "sideEffects"
key), Crackle will update the "sideEffects"
key to match the output path in dist
.
Based on what's in src
and the value of the flag, when running crackle package
these things will happen:
.css.ts
files (and files importing them) will be placed in dist/styles/<same-path-as-in-src>
- files with side-effects (matching the globs defined in
"sideEffects"
) will be placed in dist/side-effects/<same-path-as-in-src>
- if an entry has side-effects, the
"sideEffects"
key will be updated to match the output path in dist
ESM reconciliation
In the ESM build, Crackle will automatically reconcile import specifiers in the output code to point to an actual file when the imported package doesn't have an "exports"
field.
More details in ESM reconciliation.
DTS bundles
Crackle will generate type declaration files (.d.ts
) for entry points.
The same rules for dependencies apply here, meaning types for devDependencies
(but not peerDependencies
) are bundled with the project's types.
Backwards-compatible entry points
Crackle generates backwards-compatible entry points for tools which don't support the "exports"
field in package.json
.
Although there is good support in bundlers and Node.js, there are still some tools that don't support it, mainly TypeScript versions below 5.0.
Contributing
- Clone this repository
- Set up Node.js using Volta
- Enable Corepack using
corepack enable
- Install dependencies using
pnpm install
- Run bootstrap script using
pnpm bootstrap
- Run
pnpm dev
which runs crackle dev
in every package or run pnpm build
to build packages using crackle package
Self-hosting / Bootstrap
Crackle is self-hosting: it is built and tested with itself.
There's a bootstrap
package that uses a published version of Crackle to build the packages in the monorepo.
This is done by running pnpm bootstrap
at the root of the monorepo.
Once the bootstrap script is done, the current version of Crackle can be used to build itself.
If anything goes wrong and the bootstrap script fails, there's a fallback script to build @crackle/core
using unbuild by running pnpm unbuild
in the packages/core
directory.