- TypeScript 83.3%
- JavaScript 16.7%
|
|
||
|---|---|---|
| scripts | ||
| src | ||
| template | ||
| tests | ||
| .gitignore | ||
| CHANGELOG.md | ||
| LICENSE | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
Introduction
The base template of the family. Scaffolds a Bun package: package.json, TypeScript configuration, and conventions for testing, change management, and git versioning. Use it as-is, extend it into a monorepo, or choose a more specific template from the family for common upgrade paths.
For some use cases a purpose-built template already exists and reduces the amount of manual adjustment needed. Use the table to decide whether to start here or with a more specific template.
Templates in this family:
| Template | Purpose |
|---|---|
create-workspace |
Base Bun package; root of the template family (this template) |
create-ts-lib |
TypeScript library with build pipeline, distributed via registry |
create-hono-server |
Bun+Hono web server |
create-hono-spa |
SPA scaffold, pluggable into a Hono server as a sub-app |
create-skill |
LLM skill package |
create-doc |
Document as a collection of Markdown sections, compiled to PDF |
Table of Contents
Quick Start
# placeholder:
# <TEMPLATE_PACKAGE: @temir.ra/create-workspace
# <TEMPLATE_NAME: @temir.ra/workspace
# <NEW_PACKAGE: <NEW_PACKAGE>
# is used as:
# - the path where the package is created
# - the "name" field in the generated package.json
# <@_VERSION: <@_VERSION>
# pinned version
bun info "@temir.ra/create-workspace" version
bun create --no-install --no-git "@temir.ra/workspace<@_VERSION>" <NEW_PACKAGE>
# latest
# clear the cache to pick up the latest version
bun pm cache rm
bun create --no-install --no-git "@temir.ra/workspace" <NEW_PACKAGE>
# templates only copy files, run install and any setup scripts manually
cd <NEW_PACKAGE>
bun install
Documentation
The following sections explain the configurations and conventions baked into the generated package. Useful when adapting it to fit specific needs.
package.json
See npmjs documentation on package.json for detailed explanations of all fields.
{
"name": "",
"version": "0.0.0",
"description": "",
"author": "",
"license": "",
"keywords": [],
"repository": {
"type": "git",
"url": ""
},
// controls whether the package can be published to a registry
"private": true,
"scripts": {
// deletes node_modules and the lockfile, clears the Bun cache, then reinstalls
// useful for recovering from a corrupted node_modules or lockfile
"reinstall": "rm -rf node_modules && rm -f bun.lock && bun pm cache rm && bun install && bunx tsc --version",
// type-checks the project without emitting output
"typecheck": "tsc --noEmit",
// generates buildinfo.txt (for use in lifecycle hooks and CI pipelines)
"buildinfo": "bun run scripts/buildinfo.ts"
},
"devDependencies": {
"@types/bun": "latest",
"typescript": "^6.0.3"
}
}
Script scripts/buildinfo.ts
Writes buildinfo.txt with the package version from package.json, appending the git short hash as semver build metadata (<version>+<hash>). If the version already contains +, the hash is appended as <version>+<existing>.<hash> instead. Falls back to the bare version when git is unavailable.
tsconfig.json
See the TypeScript documentation on tsconfig.json for detailed explanations of all options.
{
"compilerOptions": {
// ECMAScript version of emitted output; ESNext targets the latest JS version supported by the TypeScript compiler
// if the package must support older runtimes or browsers, pin to a specific year (e.g. "ES2022", "ES2024")
"target": "ESNext",
// output module format; ESNext passes ES module syntax through unchanged
// ES module syntax: import/export statements (as opposed to CommonJS require()/module.exports)
"module": "ESNext",
// type definitions for built-in APIs
"lib": [
"ESNext" // standard JavaScript runtime APIs
],
// module resolution strategy; bundler mode allows omitting file extensions in imports
"moduleResolution": "bundler",
// enables all strict type-checking options
"strict": true,
// enforces import type for type-only imports; emitted module syntax matches source exactly
"verbatimModuleSyntax": true,
// array indexing and index signature access returns T | undefined instead of T
"noUncheckedIndexedAccess": true,
// distinguishes absent optional properties from those explicitly set to undefined
"exactOptionalPropertyTypes": true,
// requires explicit override keyword when overriding base class methods
"noImplicitOverride": true,
// requires explicit types on all exported declarations; enables parallel .d.ts generation by external tools
"isolatedDeclarations": true,
// allows default imports from CommonJS modules
"esModuleInterop": true,
// enables project references and incremental builds via *.tsbuildinfo
"composite": true,
// do not type-check `.d.ts` files in `node_modules/`
"skipLibCheck": true,
// TS6 defaults types to [] - @types/* packages must be listed explicitly
"types": ["bun"],
// enforce consistent casing across import statements
"forceConsistentCasingInFileNames": true,
// allows importing JSON files as typed modules
"resolveJsonModule": true
},
// files matched by include are type-checked and visible to the IDE (IntelliSense, go-to-definition, etc.)
"include": [
"scripts/**/*.ts"
],
// files matched by exclude are hidden from the IDE and excluded from type-checking
"exclude": [
"node_modules/"
]
}
Workspaces
To extend the package into a monorepo, add a workspaces field to package.json and run bun install:
{
"workspaces": [
"packages/*"
]
}
The execution environment installs all workspace dependencies into a single shared node_modules/ at the root and symlinks each workspace package by its name field. Cross-workspace imports resolve by package name without path aliases or module mapping.
<NEW_PACKAGE>/
├── package.json ← root
└── packages/
├── pkg-a/
│ ├── package.json
│ └── ...
└── pkg-b/
├── package.json
└── ...
Script Propagation
Append && bun run --filter './*' <script> to any script to propagate the call to all workspace packages:
{
"scripts": {
"clean:dist": "rm -rf dist/ && bun run --filter './*' clean:dist",
"clean:tsbuildinfo": "rm -f *.tsbuildinfo && bun run --filter './*' clean:tsbuildinfo",
"tests": "bun test && bun run --filter './*' tests",
"typecheck": "bun run --filter './*' typecheck"
}
}
./* targets all direct workspace packages. Replace with a more specific glob to limit propagation to a subset.
By default packages are run in sequence. Add --parallel to run them concurrently, or --sequential to make it explicit:
bun run --filter './*' --parallel typecheck
bun run --filter './*' --sequential clean
Cross-workspace Dependencies
To use one workspace package from another, declare it as a dependency using the workspace: protocol:
// packages/pkg-a/package.json
{
"dependencies": {
// workspace: resolves to the local package instead of fetching from a registry;
// workspace:* tracks the exact local version;
// workspace:^ is replaced by ^version on publish, tracking the semver range in the registry
"@scope/pkg-b": "workspace:*"
}
}
Run bun install after adding the entry. The execution environment creates the symlink in node_modules/ so imports resolve by package name at runtime and at the type level - no path alias or paths mapping required.
Scaffolding Patterns
Scaffold the package first, add workspaces to package.json, then scaffold workspace packages inside it. After scaffolding each workspace package, update its package.json with the correct name, version, description, author, license, and repository fields. To wire cross-workspace dependencies, add the workspace:* entry to the consuming package's package.json and run bun install from the root.
Library
<NEW_PACKAGE>/
└── packages/
└── my-lib/ ← create-ts-lib
bun create --no-install --no-git "@temir.ra/create-workspace" <NEW_PACKAGE>
cd <NEW_PACKAGE>
bun create --no-install --no-git "@temir.ra/ts-lib" packages/my-lib
bun install
create-ts-lib
Starting point for any package distributed via a registry. See the full documentation at @temir.ra/create-ts-lib.
- Dual
tsconfig:tsconfig.json(dev,bundlerresolution, includestests/+scripts/) andtsconfig.build.json(prod,nodenext,src/only, emits JS +.d.ts) exportsconditions:entrypoint(custom, source entry for the bundle script),types,browser(bundled output),import(compiled ESM)importsfield:#src/*.js→./src/*.ts- runtime alias fordev.ts,tests/,scripts/only- Build metadata:
scripts/buildinfo.tsgeneratesbuildinfo.txt(version + git hash) as aprebuildhook - Bundle script:
scripts/build-lib-bundle.tsbundles via Bun; supports CDN specifier rewriting viacdn-rewrite-map.json - Asset resolution contract: assets under
assets/@scope/lib-name/, accessed viaimport.meta.url+fetch() - Optional CLI entry point via
binfield andbuild:cli-bundlescript
Server
<NEW_PACKAGE>/
└── packages/
└── server/ ← create-hono-server
bun create --no-install --no-git "@temir.ra/create-workspace" <NEW_PACKAGE>
cd <NEW_PACKAGE>
bun create --no-install --no-git "@temir.ra/hono-server" packages/server
bun install
create-hono-server
Starting point for any HTTP backend. See the full documentation at @temir.ra/create-hono-server.
createAppHost(options)- configures and returns aHono<AppEnv>instance- Built-in middleware pipeline:
Logging,requestId,RequestLogger,compress,secureHeaders - Built-in endpoints:
/health,/buildinfo, OpenAPI spec, Scalar UI endpointGroups- mounts additionalHonosub-apps; integration point for SPA packagesAppEnv- exported, extensible context type; extend it to carry custom variables through the contextstartServerHost(options)- wrapsBun.serve(), graceful shutdown onSIGINT/SIGTERM
Server + SPA
<NEW_PACKAGE>/
└── packages/
├── server/ ← create-hono-server
└── spa/ ← create-hono-spa
bun create --no-install --no-git "@temir.ra/create-workspace" <NEW_PACKAGE>
cd <NEW_PACKAGE>
bun create --no-install --no-git "@temir.ra/hono-server" packages/server
bun create --no-install --no-git "@temir.ra/hono-spa" packages/spa
bun install
Add the SPA as a dependency of the server, then reinstall:
// packages/server/package.json
{
"dependencies": {
"@scope/spa": "workspace:*"
}
}
bun install
create-hono-spa
Starting point for a frontend SPA distributed as a Hono sub-app library. See the full documentation at @temir.ra/create-hono-spa.
createSpa(options)- returns aHonosub-app serving the SPA shell/app/*wildcard handles client-side routing;<base href>patched at request time frombasePathandpath- Assets resolved via
import.meta.url; no file copying or static serving config needed on the consuming server - PWA scaffold in
assets/:index.html,favicon.svg,manifest.webmanifest, screenshots - Distributed as a library (
exports+dist/+assets/); consumed viaworkspace:*in the server
Full-Stack with Shared Types
<NEW_PACKAGE>/
└── packages/
├── server/ ← create-hono-server
├── spa/ ← create-hono-spa
└── types/ ← create-ts-lib
bun create --no-install --no-git "@temir.ra/create-workspace" <NEW_PACKAGE>
cd <NEW_PACKAGE>
bun create --no-install --no-git "@temir.ra/hono-server" packages/server
bun create --no-install --no-git "@temir.ra/hono-spa" packages/spa
bun create --no-install --no-git "@temir.ra/ts-lib" packages/types
bun install
Add the types package as a dependency of both the server and the SPA, then reinstall:
// packages/server/package.json and packages/spa/package.json
{
"dependencies": {
"@scope/types": "workspace:*"
}
}
bun install
Skill
<NEW_PACKAGE>/
└── packages/
└── my-skill/ ← create-skill
bun create --no-install --no-git "@temir.ra/create-workspace" <NEW_PACKAGE>
cd <NEW_PACKAGE>
bun create --no-install --no-git "@temir.ra/skill" packages/my-skill
bun install
create-skill
Starting point for any LLM skill package. See the full documentation at @temir.ra/create-skill.
skill/skill.json— the skill definition:frontmatter(slug, description) andbody(name, purpose, activation conditions, instructions, examples, sections)skill/— typed schema, render helpers, and companion files (assets/,references/)scripts/— one build script per target platform; ships builders for Claude and OpenCodedist/— generated artifacts, one subdirectory per platform; deploy by copyingdist/<platform>/<slug>/into the target AI tool's skill directory
DevOps
bun update
bun install
bun run clean
bun run build
bun run tests
# see publish section for publish instructions
Change Management
- Create a new branch for the change.
- Make the changes and commit.
- Bump the version in
package.json. - Add an entry for the new version in
CHANGELOG.md. - Pull request the branch.
- Ensure package artifacts are current.
- Publish.
Publish
Publish to the public npm registry.
# authenticate
npm login
# publish
bun publish --registry https://registry.npmjs.org/ --access public