diff --git a/README.md b/README.md index 1c2f4a9..e215e7f 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ A collection of templates for [tsdown](https://tsdown.dev). - [Minimal](./minimal) - [Vue](./vue) - [React](./react) +- [React with React Compiler](./react-compiler) - [Solid](./solid) - [Svelte](./svelte) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 009b1b5..b8d77c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -88,6 +88,61 @@ importers: specifier: ^4.0.7 version: 4.0.7(@types/node@24.10.0)(esbuild@0.25.10)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(yaml@2.8.1) + react-compiler: + dependencies: + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + devDependencies: + '@rollup/plugin-babel': + specifier: ^6.1.0 + version: 6.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.52.5) + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.0 + version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@tsconfig/strictest': + specifier: ^2.0.7 + version: 2.0.7 + '@types/node': + specifier: ^24.10.0 + version: 24.10.0 + '@types/react': + specifier: ^19.2.2 + version: 19.2.2 + '@types/react-dom': + specifier: ^19.2.2 + version: 19.2.2(@types/react@19.2.2) + '@vitejs/plugin-react': + specifier: ^5.1.0 + version: 5.1.0(rolldown-vite@7.1.20(@types/node@24.10.0)(esbuild@0.25.10)(jiti@2.6.1)(yaml@2.8.1)) + babel-plugin-react-compiler: + specifier: ^1.0.0 + version: 1.0.0 + bumpp: + specifier: ^10.3.1 + version: 10.3.1 + happy-dom: + specifier: ^20.0.10 + version: 20.0.10 + tsdown: + specifier: ^0.16.0 + version: 0.16.0(typescript@5.9.3)(vue-tsc@3.1.3(typescript@5.9.3)) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + vite: + specifier: npm:rolldown-vite@^7.1.20 + version: rolldown-vite@7.1.20(@types/node@24.10.0)(esbuild@0.25.10)(jiti@2.6.1)(yaml@2.8.1) + vitest: + specifier: ^4.0.7 + version: 4.0.7(@types/node@24.10.0)(esbuild@0.25.10)(happy-dom@20.0.10)(jiti@2.6.1)(jsdom@27.1.0)(yaml@2.8.1) + solid: dependencies: solid-js: @@ -802,10 +857,32 @@ packages: '@rolldown/pluginutils@1.0.0-beta.46': resolution: {integrity: sha512-xMNwJo/pHkEP/mhNVnW+zUiJDle6/hxrwO0mfSJuEVRbBfgrJFuUSRoZx/nYUw5pCjrysl9OkNXCkAdih8GCnA==} + '@rollup/plugin-babel@6.1.0': + resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@types/babel__core': ^7.1.9 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + '@types/babel__core': + optional: true + rollup: + optional: true + '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/rollup-android-arm-eabi@4.52.5': resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] @@ -1200,6 +1277,9 @@ packages: peerDependencies: '@babel/core': ^7.20.12 + babel-plugin-react-compiler@1.0.0: + resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} + babel-preset-solid@1.9.10: resolution: {integrity: sha512-HCelrgua/Y+kqO8RyL04JBWS/cVdrtUv/h45GntgQY+cJl4eBcKkCDV3TdMjtKx1nXwRaR9QXslM/Npm1dxdZQ==} peerDependencies: @@ -2756,11 +2836,30 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.46': {} + '@rollup/plugin-babel@6.1.0(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@4.52.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + optionalDependencies: + '@types/babel__core': 7.20.5 + rollup: 4.52.5 + transitivePeerDependencies: + - supports-color + '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 + '@rollup/pluginutils@5.3.0(rollup@4.52.5)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.5 + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true @@ -3155,6 +3254,10 @@ snapshots: html-entities: 2.3.3 parse5: 7.3.0 + babel-plugin-react-compiler@1.0.0: + dependencies: + '@babel/types': 7.28.5 + babel-preset-solid@1.9.10(@babel/core@7.28.5)(solid-js@1.9.10): dependencies: '@babel/core': 7.28.5 diff --git a/react-compiler/.gitignore b/react-compiler/.gitignore new file mode 100644 index 0000000..7535211 --- /dev/null +++ b/react-compiler/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +*.log +.DS_Store diff --git a/react-compiler/README.md b/react-compiler/README.md new file mode 100644 index 0000000..2a47764 --- /dev/null +++ b/react-compiler/README.md @@ -0,0 +1,29 @@ +# react-compiler-components-starter + +A starter for creating a React component library with React Compiler. + +## Development + +- Install dependencies: + +```bash +npm install +``` + +- Run the playground: + +```bash +npm run play +``` + +- Run the unit tests: + +```bash +npm run test +``` + +- Build the library: + +```bash +npm run build +``` diff --git a/react-compiler/package.json b/react-compiler/package.json new file mode 100644 index 0000000..ae22ece --- /dev/null +++ b/react-compiler/package.json @@ -0,0 +1,59 @@ +{ + "name": "react-compiler-components-starter", + "version": "0.0.0", + "description": "A starter for creating a React component library with React Compiler.", + "type": "module", + "license": "MIT", + "homepage": "https://github.com/author/library#readme", + "bugs": { + "url": "https://github.com/author/library/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/author/library.git" + }, + "author": "Author Name ", + "files": [ + "dist" + ], + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": "./dist/index.js", + "./package.json": "./package.json" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "tsdown", + "dev": "tsdown --watch", + "play": "vite --config playground/vite.config.ts", + "test": "vitest", + "typecheck": "tsc --noEmit", + "release": "bumpp && pnpm publish", + "prepublishOnly": "pnpm run build" + }, + "peerDependencies": { + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@rollup/plugin-babel": "^6.1.0", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.0", + "@tsconfig/strictest": "^2.0.7", + "@types/node": "^24.10.0", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "@vitejs/plugin-react": "^5.1.0", + "babel-plugin-react-compiler": "^1.0.0", + "bumpp": "^10.3.1", + "happy-dom": "^20.0.10", + "tsdown": "^0.16.0", + "typescript": "^5.9.3", + "vite": "npm:rolldown-vite@^7.1.20", + "vitest": "^4.0.7" + } +} diff --git a/react-compiler/playground/index.html b/react-compiler/playground/index.html new file mode 100644 index 0000000..2c9a8d5 --- /dev/null +++ b/react-compiler/playground/index.html @@ -0,0 +1,12 @@ + + + + + + React Components Starter + + +
+ + + diff --git a/react-compiler/playground/src/App.tsx b/react-compiler/playground/src/App.tsx new file mode 100644 index 0000000..c85da45 --- /dev/null +++ b/react-compiler/playground/src/App.tsx @@ -0,0 +1,9 @@ +import { MyButton } from '../../src' + +export function App() { + return ( + <> + + + ) +} diff --git a/react-compiler/playground/src/index.tsx b/react-compiler/playground/src/index.tsx new file mode 100644 index 0000000..5694ed7 --- /dev/null +++ b/react-compiler/playground/src/index.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import { App } from './App.tsx' +import './style.css' + +createRoot(document.querySelector('#app')!).render( + + + , +) diff --git a/react-compiler/playground/src/style.css b/react-compiler/playground/src/style.css new file mode 100644 index 0000000..f691315 --- /dev/null +++ b/react-compiler/playground/src/style.css @@ -0,0 +1,79 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +.card { + padding: 2em; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/react-compiler/playground/vite.config.ts b/react-compiler/playground/vite.config.ts new file mode 100644 index 0000000..844891a --- /dev/null +++ b/react-compiler/playground/vite.config.ts @@ -0,0 +1,7 @@ +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' + +export default defineConfig({ + root: './playground', + plugins: [react({ babel: { plugins: ['babel-plugin-react-compiler'] } })], +}) diff --git a/react-compiler/src/MyButton.tsx b/react-compiler/src/MyButton.tsx new file mode 100644 index 0000000..7a71a4c --- /dev/null +++ b/react-compiler/src/MyButton.tsx @@ -0,0 +1,16 @@ +import { useState } from 'react' + +interface MyButtonProps { + type?: 'primary' +} + +export const MyButton: React.FC = ({ type }) => { + let [count, setCount] = useState(0) + return ( + + ) +} diff --git a/react-compiler/src/index.ts b/react-compiler/src/index.ts new file mode 100644 index 0000000..a607dca --- /dev/null +++ b/react-compiler/src/index.ts @@ -0,0 +1 @@ +export { MyButton } from './MyButton' diff --git a/react-compiler/tests/index.test.tsx b/react-compiler/tests/index.test.tsx new file mode 100644 index 0000000..69a19fd --- /dev/null +++ b/react-compiler/tests/index.test.tsx @@ -0,0 +1,19 @@ +/// + +import { render, screen } from '@testing-library/react' +import { expect, test } from 'vitest' +import { MyButton } from '../src' + +test('button', () => { + render() + + const buttonElement = screen.getByText(/my button/i) + + expect(buttonElement).toBeInTheDocument() + expect(buttonElement).toHaveTextContent('my button type: primary count: 0') + expect(buttonElement.outerHTML).toMatchInlineSnapshot( + `""`, + ) + + expect(buttonElement).toHaveClass('my-button') +}) diff --git a/react-compiler/tests/setup.ts b/react-compiler/tests/setup.ts new file mode 100644 index 0000000..c44951a --- /dev/null +++ b/react-compiler/tests/setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom' diff --git a/react-compiler/tsconfig.json b/react-compiler/tsconfig.json new file mode 100644 index 0000000..5e9e89a --- /dev/null +++ b/react-compiler/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "@tsconfig/strictest/tsconfig.json", + "compilerOptions": { + "target": "esnext", + "jsx": "react-jsx", + "lib": ["es2023", "DOM"], + "moduleDetection": "force", + "module": "preserve", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "types": [], + "declaration": true, + "emitDeclarationOnly": true, + "verbatimModuleSyntax": true, + }, + "include": ["src"] +} diff --git a/react-compiler/tsdown.config.ts b/react-compiler/tsdown.config.ts new file mode 100644 index 0000000..9dd3f08 --- /dev/null +++ b/react-compiler/tsdown.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from 'tsdown' +import pluginBabel from '@rollup/plugin-babel' + +export default defineConfig({ + platform: 'neutral', + plugins: [ + pluginBabel({ + babelHelpers: 'bundled', + parserOpts: { + sourceType: 'module', + plugins: ['jsx', 'typescript'], + }, + plugins: ['babel-plugin-react-compiler'], + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }), + ], +}) diff --git a/react-compiler/vitest.config.ts b/react-compiler/vitest.config.ts new file mode 100644 index 0000000..8a2d860 --- /dev/null +++ b/react-compiler/vitest.config.ts @@ -0,0 +1,11 @@ +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + plugins: [react()], + test: { + environment: 'happy-dom', + globals: true, + setupFiles: './tests/setup.ts', + }, +})