Repository: jaredpalmer/tsdx Branch: master Commit: 5b1aa0d67788 Files: 74 Total size: 158.5 KB Directory structure: gitextract_xy9rkl98/ ├── .changeset/ │ ├── README.md │ └── config.json ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── config.yml │ │ └── feature_request.md │ ├── dependabot.yml │ ├── stale.yml │ └── workflows/ │ ├── nodejs.yml │ └── release.yml ├── .gitignore ├── CHANGELOG.md ├── CLAUDE.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MIGRATION.md ├── README.md ├── package.json ├── src/ │ └── index.ts ├── templates/ │ ├── basic/ │ │ ├── .github/ │ │ │ └── workflows/ │ │ │ ├── main.yml │ │ │ └── size.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ ├── test/ │ │ │ └── index.test.ts │ │ ├── tsconfig.json │ │ └── vitest.config.ts │ └── react/ │ ├── .github/ │ │ └── workflows/ │ │ ├── main.yml │ │ └── size.yml │ ├── LICENSE │ ├── README.md │ ├── example/ │ │ ├── index.html │ │ ├── index.tsx │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── gitignore │ ├── package.json │ ├── src/ │ │ └── index.tsx │ ├── test/ │ │ └── index.test.tsx │ ├── tsconfig.json │ └── vitest.config.ts ├── test/ │ ├── cli.test.ts │ └── e2e.test.ts ├── tsconfig.json ├── vitest.config.ts └── website/ ├── .gitignore ├── app/ │ ├── (home)/ │ │ ├── layout.tsx │ │ └── page.tsx │ ├── docs/ │ │ ├── [[...slug]]/ │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── global.css │ ├── layout.config.tsx │ └── layout.tsx ├── content/ │ └── docs/ │ ├── commands.mdx │ ├── configuration.mdx │ ├── index.mdx │ ├── installation.mdx │ ├── meta.json │ ├── migration.mdx │ ├── project-structure.mdx │ ├── quick-start.mdx │ └── templates.mdx ├── lib/ │ └── source.ts ├── mdx-components.tsx ├── next.config.mjs ├── package.json ├── postcss.config.js ├── public/ │ └── favicon/ │ └── site.webmanifest ├── source.config.ts ├── tsconfig.json └── vercel.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .changeset/README.md ================================================ # Changesets Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", "changelog": [ "@changesets/changelog-github", { "repo": "jaredpalmer/tsdx" } ], "commit": false, "fixed": [], "linked": [], "access": "public", "baseBranch": "main", "updateInternalDependencies": "patch", "ignore": [] } ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- ### Describe the Bug A clear and concise description of what the bug is. ### Steps to Reproduce 1. Run `tsdx create mylib` 2. ... 3. See error ### Expected Behavior What you expected to happen. ### Actual Behavior What actually happened. ### Screenshots/Logs If applicable, add screenshots or error logs. ``` Paste error output here ``` ### Environment ``` TSDX version: Node version: Bun version: OS: Template used: ``` Run this to get versions: ```bash echo "TSDX: $(bunx tsdx --version 2>/dev/null || echo 'not installed')" echo "Node: $(node --version)" echo "Bun: $(bun --version)" echo "OS: $(uname -a)" ``` ### Additional Context Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- ### Problem Statement What problem are you trying to solve? What's the current behavior? ### Proposed Solution Describe the solution you'd like. Be specific about the API or behavior. ### Alternatives Considered What alternative solutions or features have you considered? ### Who Benefits? Who is this for? All users? Specific use cases? ### Additional Context Add any other context, screenshots, or examples about the feature request here. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: npm directory: '/' schedule: interval: weekly commit-message: prefix: 'deps:' versioning-strategy: increase-if-necessary allow: - dependency-name: '*' dependency-type: production open-pull-requests-limit: 5 ================================================ FILE: .github/stale.yml ================================================ # Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 3600 # Issues with these labels will never be considered stale exemptLabels: - enhancement - pinned - RFC - bug - in progress - 2.0 # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable markComment: false # Comment to post when closing a stale issue. Set to `false` to disable closeComment: false ================================================ FILE: .github/workflows/nodejs.yml ================================================ name: CI on: push: branches: [main, master] pull_request: branches: [main, master] jobs: build: name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: node: ['20', '22'] os: [ubuntu-latest, windows-latest, macos-latest] steps: - name: Checkout repo uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Node.js ${{ matrix.node }} uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - name: Install dependencies run: bun install - name: Lint run: bun run lint - name: Type check run: bun run typecheck - name: Build run: bun run build - name: Test run: bun run test ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: branches: - master concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: release: name: Release runs-on: ubuntu-latest permissions: contents: write pull-requests: write id-token: write steps: - name: Checkout repo uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 registry-url: 'https://registry.npmjs.org' - name: Install dependencies run: bun install - name: Build run: bun run build - name: Create Release Pull Request or Publish id: changesets uses: changesets/action@v1 with: version: bun run changeset version publish: bun run release title: 'chore: release package' commit: 'chore: release package' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_CONFIG_PROVENANCE: true ================================================ FILE: .gitignore ================================================ # Dependencies node_modules .pnp .pnp.js # Build output dist *.tsbuildinfo # Bun bun.lockb # IDE .idea .vscode *.swp *.swo # OS .DS_Store Thumbs.db # Logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* # Testing coverage # Misc .env .env.local .netlify # Test directories tester tester-react ================================================ FILE: CHANGELOG.md ================================================ # tsdx ## 2.0.0 ### Major Changes - [#1202](https://github.com/jaredpalmer/tsdx/pull/1202) [`6fcfef1`](https://github.com/jaredpalmer/tsdx/commit/6fcfef1dcb1c1d7f9f2c04969ee208a702876140) Thanks [@jaredpalmer](https://github.com/jaredpalmer)! - Initial 2.0.0 release - complete rewrite with modern Rust-based tooling - Bundling with bunchee - Testing with vitest - Linting with oxlint - Formatting with oxfmt - Project scaffolding with basic and react templates ================================================ FILE: CLAUDE.md ================================================ # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview TSDX is a zero-config CLI for TypeScript package development. Version 2.0 is a complete rewrite using modern Rust-based tooling: bunchee (bundling), vitest (testing), oxlint (linting), and oxfmt (formatting). ## Development Commands ```bash bun install # Install dependencies bun run build # Build CLI with bunchee bun run dev # Watch mode (rebuilds on changes) bun run test # Run all tests with vitest bun run test:watch # Run tests in watch mode bun run test test/cli.test.ts # Run a specific test file bun run lint # Lint with oxlint bun run typecheck # TypeScript type checking bun run format # Format with oxfmt bun run format:check # Check formatting ``` ## Testing Notes Tests require a build first since they test the compiled CLI: ```bash bun run build && bun run test ``` The e2e tests create projects in temp directories and have longer timeouts (60s). ## Architecture **Single CLI Entry Point**: `src/index.ts` contains all CLI commands using Commander.js: - `create` - scaffolds projects from templates, installs deps with bun - `build/dev` - wraps bunchee - `test` - wraps vitest - `lint` - wraps oxlint - `format` - wraps oxfmt - `typecheck` - wraps tsc - `init` - adds tsdx config to existing project **Templates**: `templates/basic/` and `templates/react/` are copied directly during `create`. Template `gitignore` files are renamed to `.gitignore` post-copy. `` and `` placeholders in LICENSE are replaced. ## Adding a New Template 1. Create directory in `templates/` 2. Register in `src/index.ts` in the `templates` object 3. Include: package.json, tsconfig.json, vitest.config.ts, src/, test/, gitignore (not .gitignore), LICENSE with `` and `` placeholders ## Documentation Website The documentation site is in `./website/` and built with: - **Next.js 16** - React framework - **Fumadocs** - Documentation framework (fumadocs-core, fumadocs-mdx, fumadocs-ui) - **Tailwind CSS v4** - CSS-first configuration - **IBM Plex Sans/Mono** - Typography via next/font/google ### Website Commands ```bash cd website bun install # Install dependencies bun run dev # Start dev server bun run build # Build for production ``` ### Content Structure - `content/docs/` - MDX documentation files - `content/docs/meta.json` - Sidebar navigation structure - `app/` - Next.js App Router pages - `app/layout.config.tsx` - Navigation and logo configuration ### Adding Documentation Pages 1. Create `.mdx` file in `content/docs/` 2. Add frontmatter with `title` and `description` 3. Add page to `content/docs/meta.json` in desired position 4. Use `---Section Name---` syntax in meta.json for sidebar sections ## Commit Convention Uses Conventional Commits: `feat:`, `fix:`, `docs:`, `test:`, `refactor:`, `chore:` ## Release Process Uses [changesets](https://github.com/changesets/changesets) for version management and npm publishing. ### Creating a Changeset When making changes that should be released: ```bash bun run changeset ``` Follow the prompts to select version bump type (patch/minor/major) and describe the change. ### Release Workflow 1. Create a changeset with your PR 2. Merge PR to main 3. GitHub Action creates a "Release" PR with version bumps 4. Merge the Release PR to publish to npm ### Manual Release ```bash bun run changeset version # Apply version bumps from changesets bun run release # Build and publish to npm ``` ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@formium.io. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to TSDX Thanks for your interest in TSDX! Contributions are welcome. If you're proposing a new feature, please [open an issue](https://github.com/jaredpalmer/tsdx/issues/new/choose) first to discuss it. ## Prerequisites - [Node.js](https://nodejs.org/) 20+ (LTS) - [Bun](https://bun.sh/) (latest version) ### Installing Bun ```bash # macOS/Linux curl -fsSL https://bun.sh/install | bash # Windows powershell -c "irm bun.sh/install.ps1 | iex" ``` ## Setup 1. Fork this repository to your own GitHub account and clone it: ```bash git clone https://github.com/your-username/tsdx.git cd tsdx ``` 2. Install dependencies: ```bash bun install ``` 3. Build the CLI: ```bash bun run build ``` 4. Link for local development: ```bash bun link ``` Now you can use `tsdx` commands globally and they'll run your local version. ## Development Workflow ### Building ```bash # Build once bun run build # Watch mode (rebuilds on changes) bun run dev ``` ### Testing ```bash # Run all tests bun run test # Watch mode bun run test:watch # Run specific test file bun run test test/cli.test.ts ``` ### Linting ```bash # Lint the codebase bun run lint # Auto-fix issues bun run lint --fix ``` ### Type Checking ```bash bun run typecheck ``` ### Formatting ```bash # Format all files bun run format # Check formatting bun run format:check ``` ## Testing Your Changes ### Testing the CLI After building, test your changes by creating a new project: ```bash # Create a test project cd /tmp tsdx create test-project --template basic cd test-project # Verify it works bun run build bun run test ``` ### Testing Templates Templates are in the `templates/` directory. After modifying a template: 1. Build tsdx: `bun run build` 2. Create a new project: `tsdx create test-project --template ` 3. Verify the generated project works correctly ## Project Structure ``` tsdx/ ├── src/ │ └── index.ts # CLI entry point ├── templates/ │ ├── basic/ # Basic TypeScript template │ └── react/ # React component template ├── test/ │ ├── cli.test.ts # CLI unit tests │ └── e2e.test.ts # End-to-end tests ├── package.json ├── tsconfig.json └── vitest.config.ts ``` ## Submitting a PR 1. Create a feature branch: ```bash git checkout -b feature/my-feature ``` 2. Make your changes 3. Run all checks: ```bash bun run lint bun run typecheck bun run test bun run build ``` 4. Commit your changes with a descriptive message: ```bash git commit -m "feat: add new feature" ``` 5. Push and create a pull request: ```bash git push origin feature/my-feature ``` ### Commit Message Guidelines We follow [Conventional Commits](https://www.conventionalcommits.org/): - `feat:` - New features - `fix:` - Bug fixes - `docs:` - Documentation changes - `test:` - Test changes - `refactor:` - Code refactoring - `chore:` - Maintenance tasks ## Adding a New Template 1. Create a new directory in `templates/`: ```bash mkdir templates/my-template ``` 2. Add the template files (use `basic` as reference) 3. Register the template in `src/index.ts`: ```typescript const templates = { basic: { ... }, react: { ... }, 'my-template': { name: 'my-template', description: 'Description of my template', }, }; ``` 4. Add tests for the new template 5. Update the README to document the new template ## Questions? Feel free to [open an issue](https://github.com/jaredpalmer/tsdx/issues) if you have questions or need help. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 Jared Palmer https://jaredpalmer.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: MIGRATION.md ================================================ # Migration Guide: TSDX v0.x to v2.0 This guide helps you migrate from the original TSDX (v0.x) to the modern TSDX 2.0. ## What's Changed TSDX 2.0 is a complete rewrite that replaces the original toolchain with modern, high-performance alternatives: | Old (v0.x) | New (v2.0) | Why | |------------|------------|-----| | Rollup + Babel | [bunchee](https://github.com/huozhi/bunchee) | Zero-config, SWC-powered, faster | | Jest | [vitest](https://vitest.dev/) | Vite-native, faster, Jest-compatible | | ESLint | [oxlint](https://oxc.rs/) | 50-100x faster, Rust-powered | | Prettier | [oxfmt](https://oxc.rs/) | 35x faster, Rust-powered | | yarn/npm | [bun](https://bun.sh/) | Faster installs and execution | | Node 10+ | Node 20+ | LTS only | ## Quick Migration For most projects, follow these steps: ### 1. Install Bun ```bash # macOS/Linux curl -fsSL https://bun.sh/install | bash # Windows powershell -c "irm bun.sh/install.ps1 | iex" ``` ### 2. Update package.json Replace your scripts: ```json { "scripts": { "dev": "tsdx dev", "build": "tsdx build", "test": "tsdx test", "lint": "tsdx lint", "format": "tsdx format", "typecheck": "tsdx typecheck", "prepublishOnly": "bun run build" } } ``` ### 3. Update Dependencies Remove old dependencies and add new ones: ```bash # Remove old dependencies bun remove tsdx rollup @rollup/plugin-* babel-* @babel/* jest ts-jest eslint @typescript-eslint/* prettier husky lint-staged # Add new tsdx bun add -D tsdx typescript ``` ### 4. Replace Jest with Vitest Create `vitest.config.ts`: ```typescript import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, environment: 'node', // or 'jsdom' for React/DOM testing }, }); ``` Update test files: - Change `import { describe, it, expect } from 'jest'` to `import { describe, it, expect } from 'vitest'` - Or use `globals: true` in vitest.config.ts to avoid imports **Jest to Vitest Cheatsheet:** | Jest | Vitest | |------|--------| | `jest.fn()` | `vi.fn()` | | `jest.mock()` | `vi.mock()` | | `jest.spyOn()` | `vi.spyOn()` | | `jest.useFakeTimers()` | `vi.useFakeTimers()` | | `beforeAll/afterAll` | Same | | `beforeEach/afterEach` | Same | | `describe/it/test` | Same | | `expect()` | Same | ### 5. Remove Old Config Files Delete these files (they're no longer needed): ```bash rm -f tsdx.config.js rm -f jest.config.js rm -f .babelrc babel.config.js babel.config.json rm -f .eslintrc .eslintrc.js .eslintrc.json .eslintignore rm -f .prettierrc .prettierrc.js .prettierrc.json .prettierignore rm -f rollup.config.js rm -f yarn.lock package-lock.json ``` ### 6. Update tsconfig.json Update to modern settings: ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "lib": ["ES2022", "DOM"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "declaration": true, "declarationMap": true, "outDir": "./dist", "rootDir": "./src", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true }, "include": ["src"], "exclude": ["node_modules", "dist"] } ``` ### 7. Update package.json Exports Ensure your package.json has modern exports: ```json { "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }, "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } }, "./package.json": "./package.json" }, "files": ["dist", "src"], "engines": { "node": ">=20" } } ``` ### 8. Install and Test ```bash # Install dependencies bun install # Run tests bun run test # Build bun run build # Lint bun run lint ``` ## Detailed Migration ### Build Configuration **Old TSDX (tsdx.config.js):** ```javascript module.exports = { rollup(config, options) { // Custom rollup config return config; }, }; ``` **New TSDX:** No configuration needed! bunchee reads your `package.json` exports field. For advanced customization, create `bunchee.config.ts`: ```typescript import { BuncheeConfig } from 'bunchee'; export default { // See bunchee documentation } satisfies BuncheeConfig; ``` ### Testing **Old Jest test:** ```typescript import { sum } from './index'; describe('sum', () => { it('adds numbers', () => { expect(sum(1, 2)).toBe(3); }); }); ``` **New Vitest test (same syntax!):** ```typescript import { describe, it, expect } from 'vitest'; import { sum } from './index'; describe('sum', () => { it('adds numbers', () => { expect(sum(1, 2)).toBe(3); }); }); ``` Or with `globals: true` in vitest.config.ts: ```typescript import { sum } from './index'; describe('sum', () => { it('adds numbers', () => { expect(sum(1, 2)).toBe(3); }); }); ``` ### React Testing **Old (enzyme/react-testing-library with Jest):** ```typescript import { render, screen } from '@testing-library/react'; import { MyComponent } from './MyComponent'; test('renders', () => { render(); expect(screen.getByText('Hello')).toBeInTheDocument(); }); ``` **New (same, just with Vitest!):** ```typescript import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/react'; import { MyComponent } from './MyComponent'; describe('MyComponent', () => { it('renders', () => { render(); expect(screen.getByText('Hello')).toBeDefined(); }); }); ``` Note: Replace `toBeInTheDocument()` with `toBeDefined()` or add `@testing-library/jest-dom` and configure in vitest setup. ### Linting **Old ESLint (.eslintrc.js):** ```javascript module.exports = { extends: ['react-app', 'prettier'], rules: { 'no-unused-vars': 'warn', }, }; ``` **New oxlint (.oxlintrc.json) - optional:** ```json { "rules": { "no-unused-vars": "warn" } } ``` Most ESLint rules have equivalents in oxlint. Check [oxlint rules documentation](https://oxc.rs/docs/guide/usage/linter/rules.html). ### Formatting **Old Prettier (.prettierrc):** ```json { "semi": true, "singleQuote": true, "tabWidth": 2 } ``` **New oxfmt (.oxfmtrc.json) - optional:** ```json { "indentWidth": 2, "lineWidth": 100 } ``` ### GitHub Actions **Old workflow:** ```yaml jobs: build: runs-on: ubuntu-latest strategy: matrix: node: [12, 14, 16] steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - run: yarn install - run: yarn build - run: yarn test ``` **New workflow:** ```yaml jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: node: ['20', '22'] os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 with: bun-version: latest - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} - run: bun install - run: bun run lint - run: bun run typecheck - run: bun run build - run: bun run test ``` ## Breaking Changes ### Removed Features 1. **Storybook template** - Use [Storybook CLI](https://storybook.js.org/docs/get-started/install) directly 2. **Custom Rollup config** - Use bunchee config or raw rollup if needed 3. **tsdx lint** - Now wraps oxlint instead of ESLint 4. **Node.js < 20** - Only Node.js 20+ (LTS) is supported ### Changed Behavior 1. **Build output** - Slightly different but compatible 2. **Watch mode** - Now uses bunchee's watch, may have different behavior 3. **Test runner** - Vitest instead of Jest (mostly compatible API) 4. **Default branch** - Uses `main` instead of `master` in templates ## Compatibility ### Your Library Consumers **No changes needed!** The build output format is compatible: - ESM and CommonJS dual publish - TypeScript declarations - Same export patterns ### Your Development Workflow | Task | Old Command | New Command | |------|-------------|-------------| | Create project | `npx tsdx create mylib` | `bunx tsdx create mylib` | | Development | `yarn start` | `bun run dev` | | Build | `yarn build` | `bun run build` | | Test | `yarn test` | `bun run test` | | Lint | `yarn lint` | `bun run lint` | | Format | `yarn prettier --write .` | `bun run format` | ## Troubleshooting ### "bun: command not found" Install bun: ```bash curl -fsSL https://bun.sh/install | bash ``` ### Tests fail with "vi is not defined" Add vitest imports: ```typescript import { describe, it, expect, vi } from 'vitest'; ``` Or enable globals in `vitest.config.ts`: ```typescript export default defineConfig({ test: { globals: true, }, }); ``` ### TypeScript errors with moduleResolution Update tsconfig.json: ```json { "compilerOptions": { "moduleResolution": "bundler" } } ``` ### ESM/CJS interop issues Ensure your package.json has: ```json { "type": "module" } ``` ### "Cannot find module" in tests Check your vitest.config.ts has correct paths: ```typescript export default defineConfig({ test: { include: ['test/**/*.test.ts'], }, }); ``` ## Getting Help - [TSDX GitHub Issues](https://github.com/jaredpalmer/tsdx/issues) - [Vitest Documentation](https://vitest.dev/) - [bunchee Documentation](https://github.com/huozhi/bunchee) - [oxlint Documentation](https://oxc.rs/docs/guide/usage/linter.html) - [Bun Documentation](https://bun.sh/docs) ================================================ FILE: README.md ================================================ # TSDX Zero-config CLI for TypeScript package development. [![CI](https://github.com/jaredpalmer/tsdx/actions/workflows/nodejs.yml/badge.svg)](https://github.com/jaredpalmer/tsdx/actions/workflows/nodejs.yml) [![npm](https://img.shields.io/npm/v/tsdx.svg)](https://www.npmjs.com/package/tsdx) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) Modern TypeScript library development, simplified. TSDX provides a zero-config CLI that helps you develop, test, and publish TypeScript packages with ease. > **TSDX 2.0** is a complete rewrite using modern, high-performance Rust-based tooling. See the [Migration Guide](./MIGRATION.md) if upgrading from v0.x ## Features - **Zero config** - Sensible defaults, just start coding - **Modern tooling** - Built on [bunchee](https://github.com/huozhi/bunchee), [vitest](https://vitest.dev/), [oxlint](https://oxc.rs/docs/guide/usage/linter.html), and [oxfmt](https://oxc.rs/docs/guide/usage/formatter) - **Dual ESM/CJS** - Automatic dual module builds with proper exports - **TypeScript first** - Full TypeScript support with declaration generation - **Lightning fast** - Rust-powered linting (50-100x faster than ESLint) and formatting (35x faster than Prettier) - **Bun-native** - Uses bun for package management - **Modern Node.js** - Supports Node.js 20+ (LTS) ## Quick Start ```bash # Create a new package bunx tsdx create mylib # Navigate to the project cd mylib # Start development bun run dev ``` That's it! Start editing `src/index.ts` and build your library. ## Installation ### Global Installation (recommended for creating projects) ```bash bun add -g tsdx ``` ### Per-Project Installation ```bash bun add -D tsdx ``` ## Commands ### `tsdx create ` Create a new TypeScript package from a template. ```bash # Interactive template selection bunx tsdx create mylib # Specify template directly bunx tsdx create mylib --template react ``` **Available Templates:** | Template | Description | |----------|-------------| | `basic` | A basic TypeScript library with vitest | | `react` | A React component library with Testing Library | ### `tsdx build` Build the package for production using [bunchee](https://github.com/huozhi/bunchee). ```bash tsdx build # Skip cleaning dist folder tsdx build --no-clean ``` Outputs ESM and CommonJS formats with TypeScript declarations. ### `tsdx dev` / `tsdx watch` Start development mode with file watching. ```bash tsdx dev ``` Rebuilds automatically when files change. ### `tsdx test` Run tests using [vitest](https://vitest.dev/). ```bash # Run tests once tsdx test # Watch mode tsdx test --watch # With coverage tsdx test --coverage # Update snapshots tsdx test --update ``` ### `tsdx lint` Lint the codebase using [oxlint](https://oxc.rs/docs/guide/usage/linter.html). ```bash # Lint src and test directories (default) tsdx lint # Lint specific paths tsdx lint src lib # Auto-fix issues tsdx lint --fix # Use custom config tsdx lint --config .oxlintrc.json ``` ### `tsdx format` Format the codebase using [oxfmt](https://oxc.rs/docs/guide/usage/formatter). ```bash # Format all files tsdx format # Check formatting without changes tsdx format --check # Format specific paths tsdx format src test ``` ### `tsdx typecheck` Run TypeScript type checking. ```bash tsdx typecheck # Watch mode tsdx typecheck --watch ``` ### `tsdx init` Initialize tsdx configuration in an existing project. ```bash bunx tsdx init ``` This adds the necessary configuration to your `package.json`, creates `tsconfig.json` and `vitest.config.ts` if they don't exist. ## Project Structure Projects created with tsdx follow this structure: ``` mylib/ ├── src/ │ └── index.ts # Library entry point ├── test/ │ └── index.test.ts # Tests (vitest) ├── dist/ # Build output (generated) │ ├── index.js # ESM │ ├── index.cjs # CommonJS │ └── index.d.ts # TypeScript declarations ├── .github/ │ └── workflows/ # CI/CD workflows ├── package.json ├── tsconfig.json ├── vitest.config.ts ├── LICENSE └── README.md ``` ### React Template Additional Structure ``` mylib/ ├── src/ │ └── index.tsx # React component entry ├── test/ │ └── index.test.tsx # Tests with Testing Library ├── example/ # Demo app (Vite-powered) │ ├── index.tsx │ ├── index.html │ ├── package.json │ └── vite.config.ts └── ... ``` ## Module Formats TSDX outputs both ESM and CommonJS formats: | File | Format | Usage | |------|--------|-------| | `dist/index.js` | ESM | Modern bundlers, Node.js with `type: "module"` | | `dist/index.cjs` | CommonJS | Legacy Node.js, older bundlers | | `dist/index.d.ts` | TypeScript | Type definitions | | `dist/index.d.cts` | TypeScript | CJS type definitions | The `package.json` exports field is configured automatically: ```json { "type": "module", "main": "./dist/index.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" }, "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } }, "./package.json": "./package.json" } } ``` ## Tool Stack TSDX 2.0 uses modern, high-performance tools: | Tool | Purpose | Performance | |------|---------|-------------| | [bunchee](https://github.com/huozhi/bunchee) | Bundling | Zero-config, built on Rollup + SWC | | [vitest](https://vitest.dev/) | Testing | Vite-native, Jest-compatible API | | [oxlint](https://oxc.rs/docs/guide/usage/linter.html) | Linting | 50-100x faster than ESLint | | [oxfmt](https://oxc.rs/docs/guide/usage/formatter) | Formatting | 35x faster than Prettier | | [bun](https://bun.sh/) | Package Management | Native speed, npm-compatible | ## Configuration ### TypeScript (`tsconfig.json`) TSDX creates a modern TypeScript configuration: ```json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "declaration": true, "declarationMap": true } } ``` ### Vitest (`vitest.config.ts`) Default test configuration: ```typescript import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, environment: 'node', // or 'jsdom' for React }, }); ``` ### Linting (`.oxlintrc.json`) Optional oxlint configuration: ```json { "rules": { "no-unused-vars": "warn" } } ``` ### Formatting (`.oxfmtrc.json`) Optional oxfmt configuration: ```json { "indentWidth": 2, "lineWidth": 100 } ``` ## Requirements - **Node.js**: 20+ (LTS) - **Bun**: Latest version ### Installing Bun ```bash # macOS/Linux curl -fsSL https://bun.sh/install | bash # Windows powershell -c "irm bun.sh/install.ps1 | iex" # npm (alternative) npm install -g bun ``` ## Migrating from TSDX v0.x See the [Migration Guide](./MIGRATION.md) for detailed instructions on upgrading from the original TSDX. **Quick summary:** 1. Install bun 2. Update `package.json` scripts to use tsdx commands 3. Replace Jest with vitest 4. Replace ESLint with oxlint (optional) 5. Replace Prettier with oxfmt (optional) 6. Run `bun install` ## Publishing ```bash # Build the package bun run build # Publish to npm npm publish ``` We recommend using [np](https://github.com/sindresorhus/np) or [changesets](https://github.com/changesets/changesets) for publishing. ## FAQ ### Why bun? Bun provides significantly faster package installation and script execution. It's compatible with npm packages and the Node.js ecosystem. ### Can I still use npm/yarn/pnpm? The generated projects use bun for package management, but the built packages are compatible with any package manager. Your library consumers can use npm, yarn, pnpm, or bun. ### Why oxlint instead of ESLint? oxlint is 50-100x faster than ESLint while catching the most important issues. For comprehensive linting, you can still use ESLint alongside oxlint. ### Is this compatible with the old TSDX? The build output format is fully compatible. Your library consumers won't notice any difference. However, the development workflow and configuration are different. ## Contributing Contributions are welcome! Please see [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines. ## Acknowledgments TSDX 2.0 is built on the shoulders of giants: - [bunchee](https://github.com/huozhi/bunchee) by Jiachi Liu - [vitest](https://vitest.dev/) by the Vitest team - [oxc](https://oxc.rs/) by the OXC team - [bun](https://bun.sh/) by the Bun team ## Author - [Jared Palmer](https://twitter.com/jaredpalmer) ## License [MIT](./LICENSE) ================================================ FILE: package.json ================================================ { "name": "tsdx", "version": "2.0.0", "author": "Jared Palmer ", "description": "Zero-config TypeScript package development", "license": "MIT", "homepage": "https://github.com/jaredpalmer/tsdx", "repository": { "type": "git", "url": "git+https://github.com/jaredpalmer/tsdx.git" }, "keywords": [ "typescript", "bundle", "bunchee", "vitest", "oxlint" ], "bugs": { "url": "https://github.com/jaredpalmer/tsdx/issues" }, "type": "module", "bin": { "tsdx": "./dist/index.js" }, "exports": { ".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" } }, "scripts": { "build": "bunchee", "dev": "bunchee --watch", "lint": "oxlint", "format": "oxfmt --write .", "format:check": "oxfmt --check .", "test": "vitest run", "test:watch": "vitest", "typecheck": "tsc --noEmit", "prepare": "bun run build", "changeset": "changeset", "release": "bun run build && changeset publish" }, "files": [ "dist", "templates" ], "engines": { "node": ">=20" }, "dependencies": { "commander": "^13.0.0", "enquirer": "^2.4.1", "execa": "^9.5.2", "fs-extra": "^11.2.0", "ora": "^8.1.1", "picocolors": "^1.1.1" }, "devDependencies": { "@changesets/changelog-github": "^0.5.2", "@changesets/cli": "^2.29.8", "@types/fs-extra": "^11.0.4", "@types/node": "^22.10.2", "bunchee": "^6.4.0", "oxlint": "^0.16.0", "typescript": "^5.7.2", "vitest": "^2.1.8" } } ================================================ FILE: src/index.ts ================================================ #!/usr/bin/env node import { program } from 'commander'; import pc from 'picocolors'; import fs from 'fs-extra'; import path from 'path'; import { execa, execaCommand } from 'execa'; import ora from 'ora'; import Enquirer from 'enquirer'; const { Select, Input } = Enquirer as unknown as { Select: new (options: { message: string; choices: { name: string; message: string }[] }) => { run: () => Promise }; Input: new (options: { message: string; initial?: string }) => { run: () => Promise }; }; // Read package.json for version const pkgPath = path.resolve(__dirname, '../package.json'); const pkg = fs.readJSONSync(pkgPath); // Path constants const paths = { appRoot: process.cwd(), appPackageJson: path.resolve(process.cwd(), 'package.json'), appDist: path.resolve(process.cwd(), 'dist'), appSrc: path.resolve(process.cwd(), 'src'), }; // Template definitions const templates = { basic: { name: 'basic', description: 'A basic TypeScript library', }, react: { name: 'react', description: 'A React component library', }, } as const; type TemplateName = keyof typeof templates; // ASCII banner const banner = ` ${pc.cyan('████████╗███████╗██████╗ ██╗ ██╗')} ${pc.cyan('╚══██╔══╝██╔════╝██╔══██╗╚██╗██╔╝')} ${pc.cyan(' ██║ ███████╗██║ ██║ ╚███╔╝ ')} ${pc.cyan(' ██║ ╚════██║██║ ██║ ██╔██╗ ')} ${pc.cyan(' ██║ ███████║██████╔╝██╔╝ ██╗')} ${pc.cyan(' ╚═╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝')} ${pc.dim('Zero-config TypeScript package development')} ${pc.dim('Powered by bunchee, oxlint, vitest')} `; program .name('tsdx') .description('Zero-config TypeScript package development') .version(pkg.version); // CREATE command program .command('create ') .description('Create a new TypeScript package') .option('-t, --template