npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

build-preset

v0.7.0

Published

Shared build conventions for browser games: Vite 8 and Vitest configs with headed, muted browser testing, a Capacitor config, a tsup library build, and TypeScript and Biome base configs.

Readme

build-preset

npm CI License: MIT

Shared build conventions for browser games. One dependency gives a project its Vite 8 config, its Vitest unit and real-browser test fragments, a Capacitor config, a tsup library build, and the TypeScript and Biome base configs, so a dozen game repositories stop drifting apart.

  • Vite 8 game config with env-switched base, Rolldown code-splitting groups for heavy vendors (three.js, Rapier, Phaser, Tone.js) or your own vendor chunks, HMR watch-ignore, and an optional @ alias.
  • Vitest 4 or 5 fragments: a jsdom or Node unit config and a headed, muted real-Chromium browser config that builds the Playwright provider itself.
  • Capacitor config with a documented merge, so overriding server.hostname keeps server.androidScheme.
  • tsup library build whose banner is derived from the package name.
  • tsconfig.base.json and biome.base.json to extend.
  • No runtime dependencies. Every entry point ships ESM and CommonJS with matching types.

Install

pnpm add -D build-preset vite vitest @vitest/browser-playwright playwright game-harness

game-harness provides the browser test config in the quick start below.

tsup is an optional peer: install it only if you use build-preset/tsup.

Quick start

// vite.config.ts
import { defineGamePreset } from "build-preset/vite";
import path from "node:path";

export default defineGamePreset({
  appName: "my-game",
  srcDir: path.resolve(import.meta.dirname, "src"),
  heavyDeps: { three: true, rapier: true },
});
// vitest.browser.config.ts: browser tests come from game-harness, the owner of browser QA
import { defineBrowserTestConfig } from "game-harness/vitest";
import { defineConfig } from "vitest/config";

const browserTest = defineBrowserTestConfig({
  include: ["tests/browser/**/*.browser.test.ts"],
});

export default defineConfig({
  optimizeDeps: { include: browserTest.__optimizeDepsInclude ?? [] },
  test: browserTest,
});
// tsconfig.json
{ "extends": "build-preset/tsconfig.base.json" }
// biome.json
{ "extends": ["build-preset/biome.base.json"] }

Vendor chunks by when they load

heavyDeps toggles fixed groups. A game that splits vendor code by when it loads names its own chunks. In declaration order, the first chunk matching a module takes it; chunks outrank heavyDeps:

defineGamePreset({
  appName: "example-game",
  chunks: {
    three: ["three"], // the title preloads these three...
    r3f: ["@react-three/fiber"],
    drei: ["@react-three/drei"],
    rapier: ["@react-three/rapier", "@dimforge/rapier3d-compat"], // ...the room loads these
    post: ["@react-three/postprocessing", "postprocessing", "n8ao"],
    tone: ["tone"],
  },
});

A string is an npm package name; a RegExp is tested against the module id. See the Vite page for the precedence rules.

API overview

| Import | Exports | | --- | --- | | build-preset | Everything below except /tsup (a thin barrel; prefer the subpaths) | | build-preset/vite | defineGamePreset, staticRouteExport, StaticRouteExportOptions, HeavyDepsOptions, VendorChunks, ChunkPattern | | build-preset/vitest | defineUnitTest, defineBrowserTest, defaultBrowserLaunchArgs | | build-preset/capacitor | defineCapacitorPreset, mergeCapacitorConfig, androidVersionGradleSnippet | | build-preset/tsup | libraryBuild | | build-preset/tsconfig.base.json, build-preset/biome.base.json | Shared configuration to extends |

The build-preset init-android command prints the CI-parameterized versionName and versionCode block to paste into android/app/build.gradle.

See the API reference for every option and the architecture notes for why the presets behave as they do.

The browser test contract

defineBrowserTest and defaultBrowserLaunchArgs are deprecated: browser QA has one owner, and it is game-harness (defineBrowserTestConfig from game-harness/vitest). They stay for existing consumers and are removed in the next major.

defineBrowserTest is headed-only. It constructs the Vitest Playwright provider itself and puts --mute-audio in provider.options.launchOptions.args, so a silent run does not depend on a consumer remembering to copy a launch-argument array. It throws on a headless option and on any hidden --headless Chromium argument. Muting the audio does not change a player's saved audio preference: the consumer still asserts a non-persistent runtime mute route in its own tests.

Compatibility

| | Supported | | --- | --- | | Node.js | 22, 24 and 26 (CI verifies each on Linux; Windows on 26) | | Vite | ^8.2.1 | | Vitest | ^4.1.10 or ^5.0.0 | | @vitest/browser-playwright | ^4.1.10 or ^5.0.0, matching Vitest | | Playwright | >=1.62.1 <2 | | tsup (optional) | ^8.5.0 |

The Vitest 4 and Vitest 5 lines are both exercised by the packed-consumer smoke in CI.

Development

mise install            # Node 26 and pnpm 12, or `corepack enable`
pnpm install
pnpm verify             # Biome, markdownlint, tsc, tests with coverage, build, publint, attw, packed-consumer smoke
pnpm docs:build         # the Sourcey documentation site

See CONTRIBUTING.md. Releases are automated by Release Please and published to npm with provenance from GitHub Actions.

Links

License

MIT