| name | my-simple-bun-project |
| description | Create or update small publishable TypeScript packages that use Bun for dependency installation, Vite+ (vite-plus) for formatting and bundled library output, and npm trusted publishing through a manually dispatched GitHub Actions release workflow. Use when scaffolding a Bun npm package, configuring src/index.ts and Vite+ pack, adding a Node-compatible CLI, or implementing major/minor/patch npm and GitHub releases. |
My Simple Bun Project Skill
Create a minimal, maintainable npm package with Bun as the package manager and Vite+ as the unified toolchain. Apply every requirement below unless the user explicitly overrides it.
Build the project
- Use TypeScript and make
src/index.ts the package entry point.
- Use
bun install to install and update dependencies. Commit bun.lock.
- Install
vite-plus as a development dependency. Do not substitute Vite, tsdown, Prettier, or separate lint/build tools for Vite+.
- Put Vite+ configuration in
vite.config.ts and import defineConfig from vite-plus.
- Configure formatting exactly as
fmt: { semi: false, singleQuote: true }.
- Configure
pack.entry as ['src/index.ts'] and enable declaration output. Bundle the package with vp pack through a package script.
- Point package exports,
main, module, and types at files actually emitted in dist/. Include only publishable files with the files field.
- Add
prepublishOnly so a direct npm publish builds and validates the package.
- Use a Node shebang (
#!/usr/bin/env node) for source files exposed through bin and intended to run through bunx, npx, or npm-created executable shims. Never use a Bun shebang for distributed CLIs.
- Write the project
README.md in English.
Use this baseline configuration:
import { defineConfig } from 'vite-plus'
export default defineConfig({
fmt: {
semi: false,
singleQuote: true,
},
pack: {
entry: ['src/index.ts'],
dts: true,
format: ['esm'],
sourcemap: true,
},
})
Use scripts shaped like:
{
"scripts": {
"build": "vp pack",
"check": "vp check",
"format": "vp fmt . --write",
"prepublishOnly": "bun run check && bun run build"
}
}
Prepare trusted publishing
Set package.json.repository to the canonical public GitHub repository. Its owner and repository must exactly match the repository configured as the npm trusted publisher. Prefer the explicit form:
{
"repository": {
"type": "git",
"url": "git+https://github.com/OWNER/REPOSITORY.git"
}
}
Before claiming trusted publishing is ready, tell the user to configure the package on npm with the exact GitHub owner, repository, and workflow filename. Configure the publisher to allow npm publish. Do not add NPM_TOKEN, NODE_AUTH_TOKEN, or any long-lived publish credential to the workflow.
Use a GitHub-hosted runner, Node 24 or newer, npm 11.5.1 or newer, registry-url: https://registry.npmjs.org, and these permissions:
permissions:
contents: write
id-token: write
Implement the release workflow
Create .github/workflows/publish.yml with workflow_dispatch and one required choice input named bump, limited to major, minor, and patch.
Implement this order:
- Check out the default branch with full history.
- Set up Node and Bun.
- Run
bun install --frozen-lockfile before release work.
- Read the package name from
package.json.
- Fetch the latest published version from npm with
npm view "$PACKAGE_NAME" version. Fail clearly if the package has no published version; this workflow increments an existing npm package and must not guess a first version.
- Set the local package version to the fetched version, then increment it from the selected dispatch input with
npm version "$BUMP" --no-git-tag-version.
- Run
bun install again so package metadata and bun.lock remain synchronized.
- Run checks and build with Bun scripts. Ensure
vp pack produces the bundled dist output.
- Verify the target version does not already exist on npm or as a Git tag.
- Prepare a local release commit and annotated
v<version> tag, but do not push them yet.
- Publish only with
npm publish. Do not publish with bun publish, vp, a GitHub Action wrapper, or another registry client. Add --access public when required for a public scoped package. Trusted publishing supplies OIDC automatically; do not pass --provenance unless the user explicitly needs it because npm trusted publishing generates provenance automatically.
- Only after
npm publish succeeds, push the release commit and tag, then create a public GitHub Release for that tag with generated release notes (for example, gh release create "$TAG" --verify-tag --generate-notes).
Keep version calculation shell-safe: validate that npm returned a strict semantic version and that bump is one of the three allowed values even though the UI uses a choice input. Write the computed version and tag to GITHUB_OUTPUT for later steps. Use a concurrency group for publishing so two manual releases cannot race.
Do not trigger publishing from ordinary pushes or pull requests. Do not create the GitHub Release before npm confirms successful publication.
Verify the result
Run bun install, formatting or format checks, type/lint checks, tests when present, and bun run build. Inspect the package contents with npm pack --dry-run without publishing. Confirm that:
dist contains bundled JavaScript and declarations from src/index.ts.
- Package export paths match emitted filenames.
- Executable output preserves a Node shebang when a
bin is present.
- The workflow has
workflow_dispatch, the three bump choices, OIDC permission, bun install, npm registry lookup, npm publish, and post-publish GitHub Release creation.
- No npm publish token is committed or referenced.