Skip to content

About

Opinionated Rstack CLI presets

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@heyq02/rstack-config

npm version downloads node version license

Opinionated Rstack CLI presets — the Rstack counterpart of the sxzz toolchain split (@sxzz/eslint-config + @sxzz/prettier-config + tsdown-preset-sxzz), with tree-shakeable subpaths and a unified define.extends entry.

Features

  • Tool subpaths: rslint / rslib / fmt / test / staged / commitlint / tsconfig / tsconfig/app
  • Unified rstack() → RstackConfig for define.extends([...]), including Rsbuild sites via app
  • sideEffects: false + distinct ESM bundles
  • Optional peers: install only the tools you use
  • Lazy factories so rs lint does not load the Rslib graph

Install

pnpm add -D @heyq02/rstack-config rstack @rslint/core @rslib/core
# Optional — commit message lint (commit-msg hook)
pnpm add -D @commitlint/cli

Usage

Preferred — Rstack CLI shared config

// rstack.config.ts
import { define } from 'rstack';
import { rstack } from '@heyq02/rstack-config/rstack';

define.extends([
  rstack({
    lib: { entry: 'index' },
    lint: { typescript: true, rstest: true },
  }),
]);

// Optional project overrides (merge on top of the shared preset):
define.fmt({ printWidth: 100 });

Site — Rsbuild (rs dev / rs build / rs preview)

Setting app registers define.app() and leaves the library build off. Lint keeps Node rules for config files, and turns off node/no-missing-import so Rsbuild extensionless imports (./mount) are not reported.

// rstack.config.ts
import { define } from 'rstack';
import { rstack } from '@heyq02/rstack-config/rstack';

define.extends([
  rstack({
    app: {
      source: { entry: { index: './src/index.tsx' } },
    },
    lint: { react: true },
  }),
]);
// tsconfig.json
{
  "extends": "@heyq02/rstack-config/tsconfig/app",
  "include": ["src"]
}

Pass lib as well only when the same project should also build a library. Pass node: false on lint to drop Node rules entirely.

Pick tools (maximum tree-shaking)

import { define } from 'rstack';
import { lint } from '@heyq02/rstack-config/rslint';
import { nodeLib } from '@heyq02/rstack-config/rslib';
import { fmt } from '@heyq02/rstack-config/fmt';
import { test } from '@heyq02/rstack-config/test';
import { staged } from '@heyq02/rstack-config/staged';

define.lib(() => nodeLib());
define.lint(() => lint({ typescript: true }));
define.fmt(fmt());
define.test(test());
define.staged(staged());

Commitlint

Rstack CLI has no define.commitlint(), so commit message lint stays a one-liner config file (same shape as rspack-plugin-git-revision):

// commitlint.config.js
export { default } from '@heyq02/rstack-config/commitlint';

With options:

import { commitlint } from '@heyq02/rstack-config/commitlint';

export default commitlint({
  headerMaxLength: 100,
  // types: ['feat', 'fix', ...],
});

Wire the hook (once per repo):

# .rstack/hooks/commit-msg
pnpm exec commitlint --edit "$1"

And "prepare": "rs hooks" in package.json.

TypeScript

Shareable tsconfig JSON (strict + bundler resolution). Path fields like include / rootDir stay in the consumer so they resolve against the project root:

// tsconfig.json
{
  "extends": "@heyq02/rstack-config/tsconfig",
  "compilerOptions": {
    "rootDir": "src"
  },
  "include": ["src"]
}

Browser and Rsbuild sites extend the DOM + JSX config instead (lib includes DOM, jsx is react-jsx):

{
  "extends": "@heyq02/rstack-config/tsconfig/app",
  "compilerOptions": {
    "types": ["@rsbuild/core/types", "node"]
  },
  "include": ["src", "rsbuild.config.ts", "rstack.config.ts"]
}

./tsconfig.app.json is the same file.

Override when needed (tests, extra types, wider include):

{
  "extends": "@heyq02/rstack-config/tsconfig",
  "compilerOptions": {
    "rootDir": ".",
    "types": ["rstack/types", "node"]
  },
  "include": ["src", "tests", "rstack.config.ts"]
}

Community mapping

Subpath Role Inspired by
@heyq02/rstack-config/rslint lint() Rslint flat-config @sxzz/eslint-config
@heyq02/rstack-config/fmt fmt() for rs fmt / define.fmt @sxzz/prettier-config
@heyq02/rstack-config/rslib lib() / nodeLib() tsdown-preset-sxzz
@heyq02/rstack-config/test test() for rs test Rstack-native
@heyq02/rstack-config/staged staged() for rs staged Rstack-native
@heyq02/rstack-config/commitlint commitlint() for @commitlint/cli Conventional Commits
@heyq02/rstack-config/tsconfig shareable tsconfig.json Node library defaults
@heyq02/rstack-config/tsconfig/app site tsconfig (DOM + JSX) Rsbuild / browser
@heyq02/rstack-config/rstack rstack() → define.extends shared cfg Rstack define.extends

There is no root . export — pick a subpath.

Options

rstack()

Option Default Description
app omitted Rsbuild options for define.app(), or false. Setting it defaults lib to false
lib {} LibOptions or false to omit. false when app is set
node true Use nodeLib instead of lib
lint Node library lint defaults lint options or false. With app, node/no-missing-import is off
fmt {} fmt() options or false
test {} test() options or false
staged {} staged() options or false

Rslint — lint()

Option Default Description
typescript auto (typescript) true / false / { typeChecked, strict, stylistic, projectService }
javascript true JavaScript recommended + opinionated rules
unicorn true Unicorn recommended + overrides
imports true Import recommended + no-default-export, etc.
sortImports true true / false / Oxfmt-like options → import/order
node true (module) true / 'module' / 'script' / 'mixed'
promise true Promise recommended
react auto (react) React + React Hooks (+ jsx-a11y)
jest auto (jest) Jest recommended
rstest auto (rstest) Rstest recommended
unusedImports true eslint-plugin-unused-imports
regexp true eslint-plugin-regexp
deMorgan true eslint-plugin-de-morgan
eslintComments true @eslint-community/eslint-plugin-eslint-comments
ignores [] Extra global ignore patterns

Rslib — lib() / nodeLib()

Option Default Description
entry 'index' 'index' / 'shallow' / 'all' / custom source.entry
inlineDeps [] Bundle instead of externalize
publint true rsbuild-plugin-publint
attw true rsbuild-plugin-arethetypeswrong with ESM-only defaults. Needs TypeScript JS API (typescript@npm:@typescript/typescript6 when using TS 7 / tsgo).
rsdoctor false @rsdoctor/rspack-plugin on tools.rspack. true runs when RSDOCTOR=true; 'ci-only' runs when CI is set. CI writes dist/.rsdoctor/rsdoctor-data.json for rsdoctor-action and does not start the client server.

Rstack CLI has no separate Rsdoctor entry. Install the plugin and opt in on the Rslib preset:

pnpm add -D @rsdoctor/rspack-plugin
import { define } from 'rstack';
import { nodeLib } from '@heyq02/rstack-config/rslib';

define.lib(() =>
  nodeLib({
    rsdoctor: true,
  }),
);
RSDOCTOR=true pnpm exec rs lib

In CI, rsdoctor: 'ci-only' (or rsdoctor: true with RSDOCTOR=true) writes brief JSON to dist/.rsdoctor/rsdoctor-data.json after the build. rsdoctor-action reads that file, compares it with main, and comments on the pull request.

fmt / test / staged / commitlint

fmt({
  singleQuote: true,
  sortPackageJson: true,
  ignorePatterns: ['.github/**'],
});
test({ strictCoverage: true });
staged({ formatAll: true, lintFix: true });
commitlint({ headerMaxLength: 100 });

Migration

- import { heyq02 } from '@heyq02/rslint-config';
+ import { lint } from '@heyq02/rstack-config/rslint';

- import { lib, nodeLib } from '@heyq02/rslib-config';
+ import { lib, nodeLib } from '@heyq02/rstack-config/rslib';

+ import { rstack } from '@heyq02/rstack-config/rstack';
+ define.extends([rstack()]);

Development

pnpm install
pnpm run build
pnpm run lint
pnpm run typecheck
pnpm run test
pnpm run format   # automd + rs fmt
pnpm run check    # rs check + typecheck
pnpm release      # global bumpp: bump, commit, tag, push

Release

pnpm release

Uses your globally installed bumpp to bump, commit, tag, and push. The v* tag runs .github/workflows/release.yml (GitHub Release via changelogithub + npm publish via sxzz/workflows). Every push/PR also gets a preview package from .github/workflows/release-commit.yml (pkg-pr-new).

Configure npm Trusted Publishing for this GitHub repo so OIDC publish works without NPM_TOKEN.

License

Published under the MIT license. Made by @heyq02 and community 💛


🤖 auto updated with automd

About

Opinionated Rstack CLI presets

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages