diff --git a/.changeset/tired-berries-wonder.md b/.changeset/tired-berries-wonder.md new file mode 100644 index 00000000..9bc99bc0 --- /dev/null +++ b/.changeset/tired-berries-wonder.md @@ -0,0 +1,6 @@ +--- +'@devup-ui/webpack-plugin': patch +'@devup-ui/next-plugin': patch +--- + +Support Turbopack diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 13a79205..ddf662f9 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,12 +9,43 @@ on: - main permissions: write-all +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + jobs: + benchmark: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Cargo tarpaulin and fmt + run: | + cargo install cargo-tarpaulin + rustup component add rustfmt clippy + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + run_install: false + + - uses: jetli/wasm-pack-action@v0.4.0 + with: + version: 'latest' + - name: Install Node.js + uses: actions/setup-node@v4 + with: + registry-url: "https://registry.npmjs.org" + node-version: 22 + cache: 'pnpm' + - run: pnpm i + - run: pnpm build + - name: Benchmark + run: pnpm benchmark + publish: runs-on: ubuntu-latest - concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: false steps: - name: Checkout uses: actions/checkout@v4 @@ -54,8 +85,6 @@ jobs: cargo fmt pnpm test rm -rf .rustfmt.toml - - name: Benchmark - run: pnpm benchmark - name: Build Landing run: | pnpm -F components build-storybook diff --git a/apps/landing/next.config.ts b/apps/landing/next.config.ts index 3a14b62b..4476e8f9 100644 --- a/apps/landing/next.config.ts +++ b/apps/landing/next.config.ts @@ -2,9 +2,6 @@ import { DevupUI } from '@devup-ui/next-plugin' import createMDX from '@next/mdx' const withMDX = createMDX({ - // options: { - // remarkPlugins: [remarkGfm], - // }, extension: /\.mdx?$/, }) @@ -12,5 +9,6 @@ export default withMDX( DevupUI({ pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], output: 'export', + reactCompiler: true, }), ) diff --git a/apps/landing/package.json b/apps/landing/package.json index c87515f6..07455d64 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -6,7 +6,7 @@ "scripts": { "dev": "node ./script.js && next dev", "search": "node ./script.js", - "build": "node ./script.js && next build --webpack", + "build": "node ./script.js && next build", "start": "npx serve ./out", "lint": "eslint" }, @@ -19,21 +19,22 @@ "@next/mdx": "^16.0", "body-scroll-lock": "3.1", "clsx": "^2.1", + "lenis": "1.3", "next": "^16.0", "react": "^19.2", "react-dom": "^19.2", "react-markdown": "^10.1", - "react-syntax-highlighter": "^15.6", - "lenis": "1.3" + "react-syntax-highlighter": "^15.6" }, "devDependencies": { - "@types/mdx": "^2.0", "@devup-ui/next-plugin": "workspace:*", "@types/body-scroll-lock": "^3.1", + "@types/mdx": "^2.0", "@types/node": "^24", "@types/react": "^19", "@types/react-dom": "^19", "@types/react-syntax-highlighter": "^15.5", + "babel-plugin-react-compiler": "^1.0", "typescript": "^5" } } diff --git a/apps/landing/src/app/(detail)/docs/RightIndex.tsx b/apps/landing/src/app/(detail)/docs/RightIndex.tsx index ef05ecff..8132ee85 100644 --- a/apps/landing/src/app/(detail)/docs/RightIndex.tsx +++ b/apps/landing/src/app/(detail)/docs/RightIndex.tsx @@ -72,8 +72,12 @@ export function RightIndex() { Contents - {menus.map((menu) => ( - + {menus.map((menu, idx) => ( + {menu.text} ))} diff --git a/apps/landing/src/app/layout.tsx b/apps/landing/src/app/layout.tsx index 8b5bd1dc..17bf1f7e 100644 --- a/apps/landing/src/app/layout.tsx +++ b/apps/landing/src/app/layout.tsx @@ -27,6 +27,9 @@ export const metadata: Metadata = { resetCss() globalCss({ + pre: { + borderRadius: '10px', + }, fontFaces: [ { fontFamily: 'Pretendard', @@ -85,9 +88,6 @@ globalCss({ lineHeight: '1.5', letterSpacing: '-0.03em', }, - pre: { - borderRadius: '10px', - }, }) export default function RootLayout({ diff --git a/benchmark.js b/benchmark.js index 5080be63..a73e6c3c 100644 --- a/benchmark.js +++ b/benchmark.js @@ -59,6 +59,22 @@ function clearBuildFile() { recursive: true, force: true, }) + if (existsSync('./benchmark/next-tailwind-turbo/.next')) + rmSync('./benchmark/next-tailwind-turbo/.next', { + recursive: true, + force: true, + }) + + if (existsSync('./benchmark/next-devup-ui-single-turbo/.next')) + rmSync('./benchmark/next-devup-ui-single-turbo/.next', { + recursive: true, + force: true, + }) + if (existsSync('./benchmark/next-devup-ui-single-turbo/df')) + rmSync('./benchmark/next-devup-ui-single-turbo/df', { + recursive: true, + force: true, + }) } function checkDirSize(path) { @@ -106,5 +122,7 @@ result.push(benchmark('chakra-ui')) result.push(benchmark('mui')) result.push(benchmark('devup-ui')) result.push(benchmark('devup-ui-single')) +result.push(benchmark('tailwind-turbo')) +result.push(benchmark('devup-ui-single-turbo')) console.info(result.join('\n')) diff --git a/benchmark/next-chakra-ui/tsconfig.json b/benchmark/next-chakra-ui/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-chakra-ui/tsconfig.json +++ b/benchmark/next-chakra-ui/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-devup-ui-single-turbo/.gitignore b/benchmark/next-devup-ui-single-turbo/.gitignore new file mode 100644 index 00000000..5ef6a520 --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/benchmark/next-devup-ui-single-turbo/README.md b/benchmark/next-devup-ui-single-turbo/README.md new file mode 100644 index 00000000..665152ea --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/README.md @@ -0,0 +1 @@ +## Nextjs App diff --git a/benchmark/next-devup-ui-single-turbo/next.config.ts b/benchmark/next-devup-ui-single-turbo/next.config.ts new file mode 100644 index 00000000..9e94bd9b --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/next.config.ts @@ -0,0 +1,7 @@ +import { DevupUI } from '@devup-ui/next-plugin' + +const nextConfig = { + /* config options here */ +} + +export default DevupUI(nextConfig, { singleCss: true }) diff --git a/benchmark/next-devup-ui-single-turbo/package.json b/benchmark/next-devup-ui-single-turbo/package.json new file mode 100644 index 00000000..7cfe14ab --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/package.json @@ -0,0 +1,25 @@ +{ + "name": "next-devup-ui-single-turbo-benchmark", + "version": "0.1.0", + "type": "module", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build --experimental-debug-memory-usage", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "react": "^19.2", + "react-dom": "^19.2", + "next": "^16.0", + "@devup-ui/react": "workspace:*" + }, + "devDependencies": { + "@devup-ui/next-plugin": "workspace:*", + "typescript": "^5", + "@types/node": "^24", + "@types/react": "^19", + "@types/react-dom": "^19" + } +} diff --git a/benchmark/next-devup-ui-single-turbo/public/file.svg b/benchmark/next-devup-ui-single-turbo/public/file.svg new file mode 100644 index 00000000..004145cd --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-devup-ui-single-turbo/public/globe.svg b/benchmark/next-devup-ui-single-turbo/public/globe.svg new file mode 100644 index 00000000..567f17b0 --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-devup-ui-single-turbo/public/next.svg b/benchmark/next-devup-ui-single-turbo/public/next.svg new file mode 100644 index 00000000..5174b28c --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-devup-ui-single-turbo/public/vercel.svg b/benchmark/next-devup-ui-single-turbo/public/vercel.svg new file mode 100644 index 00000000..77053960 --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-devup-ui-single-turbo/public/window.svg b/benchmark/next-devup-ui-single-turbo/public/window.svg new file mode 100644 index 00000000..b2b2a44f --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-devup-ui-single-turbo/src/app/favicon.ico b/benchmark/next-devup-ui-single-turbo/src/app/favicon.ico new file mode 100644 index 00000000..718d6fea Binary files /dev/null and b/benchmark/next-devup-ui-single-turbo/src/app/favicon.ico differ diff --git a/benchmark/next-devup-ui-single-turbo/src/app/layout.tsx b/benchmark/next-devup-ui-single-turbo/src/app/layout.tsx new file mode 100644 index 00000000..6b8b4518 --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/src/app/layout.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + {children} + + ) +} diff --git a/benchmark/next-devup-ui-single-turbo/src/app/page.tsx b/benchmark/next-devup-ui-single-turbo/src/app/page.tsx new file mode 100644 index 00000000..310fa7e7 --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/src/app/page.tsx @@ -0,0 +1,51 @@ +'use client' + +import { Box, Text } from '@devup-ui/react' +import { useState } from 'react' + +export default function HomePage() { + const [color, setColor] = useState('yellow') + const [enabled, setEnabled] = useState(false) + + return ( +
+

+ Track & field champions: +

+ + hello + hello + + text + + hello + + hello + +
+ ) +} diff --git a/benchmark/next-devup-ui-single-turbo/tsconfig.json b/benchmark/next-devup-ui-single-turbo/tsconfig.json new file mode 100644 index 00000000..a9788073 --- /dev/null +++ b/benchmark/next-devup-ui-single-turbo/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "df/*.d.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/benchmark/next-devup-ui-single/tsconfig.json b/benchmark/next-devup-ui-single/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-devup-ui-single/tsconfig.json +++ b/benchmark/next-devup-ui-single/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-devup-ui/tsconfig.json b/benchmark/next-devup-ui/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-devup-ui/tsconfig.json +++ b/benchmark/next-devup-ui/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-kuma-ui/tsconfig.json b/benchmark/next-kuma-ui/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-kuma-ui/tsconfig.json +++ b/benchmark/next-kuma-ui/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-mui/tsconfig.json b/benchmark/next-mui/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-mui/tsconfig.json +++ b/benchmark/next-mui/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-panda-css/tsconfig.json b/benchmark/next-panda-css/tsconfig.json index 0911c907..ccf0f254 100644 --- a/benchmark/next-panda-css/tsconfig.json +++ b/benchmark/next-panda-css/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -28,7 +28,8 @@ "**/*.tsx", ".next/types/**/*.ts", "df/*.d.ts", - "styled-system" + "styled-system", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-stylex/tsconfig.json b/benchmark/next-stylex/tsconfig.json index 3098b586..e9089e9b 100644 --- a/benchmark/next-stylex/tsconfig.json +++ b/benchmark/next-stylex/tsconfig.json @@ -12,7 +12,7 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -28,7 +28,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "app/layout.js" + "app/layout.js", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-tailwind-turbo/.gitignore b/benchmark/next-tailwind-turbo/.gitignore new file mode 100644 index 00000000..5ef6a520 --- /dev/null +++ b/benchmark/next-tailwind-turbo/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/benchmark/next-tailwind-turbo/README.md b/benchmark/next-tailwind-turbo/README.md new file mode 100644 index 00000000..665152ea --- /dev/null +++ b/benchmark/next-tailwind-turbo/README.md @@ -0,0 +1 @@ +## Nextjs App diff --git a/benchmark/next-tailwind-turbo/next.config.mjs b/benchmark/next-tailwind-turbo/next.config.mjs new file mode 100644 index 00000000..b1c6ea43 --- /dev/null +++ b/benchmark/next-tailwind-turbo/next.config.mjs @@ -0,0 +1 @@ +export default {} diff --git a/benchmark/next-tailwind-turbo/package.json b/benchmark/next-tailwind-turbo/package.json new file mode 100644 index 00000000..ef10d34f --- /dev/null +++ b/benchmark/next-tailwind-turbo/package.json @@ -0,0 +1,27 @@ +{ + "name": "next-tailwind-turbo-benchmark", + "version": "0.1.0", + "type": "module", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build --experimental-debug-memory-usage", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "next": "^16.0", + "react": "^19.2", + "react-dom": "^19.2", + "react-icons": "^5.5" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.1", + "postcss": "^8.5", + "@types/node": "^24", + "@types/react": "^19", + "@types/react-dom": "^19", + "typescript": "^5", + "tailwindcss": "^4.1" + } +} diff --git a/benchmark/next-tailwind-turbo/postcss.config.mjs b/benchmark/next-tailwind-turbo/postcss.config.mjs new file mode 100644 index 00000000..ae85b2fe --- /dev/null +++ b/benchmark/next-tailwind-turbo/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +} + +export default config diff --git a/benchmark/next-tailwind-turbo/public/file.svg b/benchmark/next-tailwind-turbo/public/file.svg new file mode 100644 index 00000000..004145cd --- /dev/null +++ b/benchmark/next-tailwind-turbo/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-tailwind-turbo/public/globe.svg b/benchmark/next-tailwind-turbo/public/globe.svg new file mode 100644 index 00000000..567f17b0 --- /dev/null +++ b/benchmark/next-tailwind-turbo/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-tailwind-turbo/public/next.svg b/benchmark/next-tailwind-turbo/public/next.svg new file mode 100644 index 00000000..5174b28c --- /dev/null +++ b/benchmark/next-tailwind-turbo/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-tailwind-turbo/public/vercel.svg b/benchmark/next-tailwind-turbo/public/vercel.svg new file mode 100644 index 00000000..77053960 --- /dev/null +++ b/benchmark/next-tailwind-turbo/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-tailwind-turbo/public/window.svg b/benchmark/next-tailwind-turbo/public/window.svg new file mode 100644 index 00000000..b2b2a44f --- /dev/null +++ b/benchmark/next-tailwind-turbo/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/benchmark/next-tailwind-turbo/src/app/favicon.ico b/benchmark/next-tailwind-turbo/src/app/favicon.ico new file mode 100644 index 00000000..718d6fea Binary files /dev/null and b/benchmark/next-tailwind-turbo/src/app/favicon.ico differ diff --git a/benchmark/next-tailwind-turbo/src/app/global.css b/benchmark/next-tailwind-turbo/src/app/global.css new file mode 100644 index 00000000..a461c505 --- /dev/null +++ b/benchmark/next-tailwind-turbo/src/app/global.css @@ -0,0 +1 @@ +@import "tailwindcss"; \ No newline at end of file diff --git a/benchmark/next-tailwind-turbo/src/app/layout.tsx b/benchmark/next-tailwind-turbo/src/app/layout.tsx new file mode 100644 index 00000000..c97b3260 --- /dev/null +++ b/benchmark/next-tailwind-turbo/src/app/layout.tsx @@ -0,0 +1,20 @@ +import './global.css' + +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + {children} + + ) +} diff --git a/benchmark/next-tailwind-turbo/src/app/page.tsx b/benchmark/next-tailwind-turbo/src/app/page.tsx new file mode 100644 index 00000000..c5f9140e --- /dev/null +++ b/benchmark/next-tailwind-turbo/src/app/page.tsx @@ -0,0 +1,37 @@ +'use client' + +import { useState } from 'react' + +export default function HomePage() { + const [color, setColor] = useState('text-yellow-500') + const [enabled, setEnabled] = useState(false) + + return ( +
+

Track & field champions:

+
+
hello
+
hello
+
+

text

+
+ hello +
+
hello
+ +
+ ) +} diff --git a/benchmark/next-tailwind-turbo/tsconfig.json b/benchmark/next-tailwind-turbo/tsconfig.json new file mode 100644 index 00000000..a9788073 --- /dev/null +++ b/benchmark/next-tailwind-turbo/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + "df/*.d.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/benchmark/next-tailwind/tsconfig.json b/benchmark/next-tailwind/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-tailwind/tsconfig.json +++ b/benchmark/next-tailwind/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/benchmark/next-vanilla-extract/tsconfig.json b/benchmark/next-vanilla-extract/tsconfig.json index 311cfed4..a9788073 100644 --- a/benchmark/next-vanilla-extract/tsconfig.json +++ b/benchmark/next-vanilla-extract/tsconfig.json @@ -11,7 +11,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, "plugins": [ { @@ -27,7 +27,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - "df/*.d.ts" + "df/*.d.ts", + ".next/dev/types/**/*.ts" ], "exclude": ["node_modules"] } diff --git a/packages/next-plugin/src/__tests__/find-root.test.ts b/packages/next-plugin/src/__tests__/find-root.test.ts new file mode 100644 index 00000000..abd468a8 --- /dev/null +++ b/packages/next-plugin/src/__tests__/find-root.test.ts @@ -0,0 +1,131 @@ +import { existsSync } from 'node:fs' +import { join } from 'node:path' + +import { findRoot } from '../find-root' + +vi.mock('node:fs') + +describe('findRoot', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('should return the first directory with package.json when found', () => { + const mockDir = '/project/src/components' + const expectedRoot = '/project' + + vi.mocked(existsSync) + .mockReturnValueOnce(false) // /project/src/components/package.json + .mockReturnValueOnce(false) // /project/src/package.json + .mockReturnValueOnce(true) // /project/package.json + .mockReturnValueOnce(false) // /package.json + + const result = findRoot(mockDir) + + expect(result).toBe(expectedRoot) + expect(existsSync).toHaveBeenCalledWith( + join('/project/src/components', 'package.json'), + ) + expect(existsSync).toHaveBeenCalledWith( + join('/project/src', 'package.json'), + ) + expect(existsSync).toHaveBeenCalledWith(join('/project', 'package.json')) + }) + + it('should return process.cwd() when no package.json is found', () => { + const mockDir = '/some/deep/nested/directory' + const originalCwd = process.cwd() + + vi.mocked(existsSync).mockReturnValue(false) + + const result = findRoot(mockDir) + + expect(result).toBe(originalCwd) + }) + + it('should handle root directory correctly', () => { + const mockDir = '/' + + vi.mocked(existsSync).mockReturnValue(false) + + const result = findRoot(mockDir) + + expect(result).toBe(process.cwd()) + }) + + it('should find package.json in current directory', () => { + const mockDir = '/project' + + vi.mocked(existsSync) + .mockReturnValueOnce(true) // /project/package.json + .mockReturnValueOnce(false) // /package.json + + const result = findRoot(mockDir) + + expect(result).toBe('/project') + }) + + it('should handle multiple package.json files and return the deepest one', () => { + const mockDir = '/project/src/components/deep' + const expectedRoot = '/project' // The function returns the last found package.json (closest to root) + + vi.mocked(existsSync) + .mockReturnValueOnce(false) // /project/src/components/deep/package.json + .mockReturnValueOnce(false) // /project/src/components/package.json + .mockReturnValueOnce(true) // /project/src/package.json + .mockReturnValueOnce(true) // /project/package.json + .mockReturnValueOnce(false) // /package.json + + const result = findRoot(mockDir) + + expect(result).toBe(expectedRoot) + }) + + it('should handle paths', () => { + const mockDir = join('a', 'b', 'c', 'd') + const expectedRoot = join('a', 'b') + + vi.mocked(existsSync) + .mockReturnValueOnce(false) // a/b/c/d/package.json + .mockReturnValueOnce(false) // a/b/c/package.json + .mockReturnValueOnce(true) // a/b/package.json + .mockReturnValueOnce(false) // a/package.json + + const result = findRoot(mockDir) + + expect(result).toBe(expectedRoot) + }) + + it('should stop at filesystem root', () => { + const mockDir = join('a', 'b', 'c') + + // Mock existsSync to return false for all calls, simulating no package.json found + vi.mocked(existsSync).mockReturnValue(false) + + const result = findRoot(mockDir) + + expect(result).toBe(process.cwd()) + }) + + it('should handle empty string input', () => { + const mockDir = '' + + vi.mocked(existsSync).mockReturnValue(false) + + const result = findRoot(mockDir) + + expect(result).toBe(process.cwd()) + }) + + it('should handle single character directory', () => { + const mockDir = 'a' + + vi.mocked(existsSync) + .mockReturnValueOnce(false) // a/package.json + .mockReturnValueOnce(false) // ./package.json + + const result = findRoot(mockDir) + + expect(result).toBe(process.cwd()) + }) +}) diff --git a/packages/next-plugin/src/__tests__/plugin.test.ts b/packages/next-plugin/src/__tests__/plugin.test.ts index 940c9eb8..ee058dcf 100644 --- a/packages/next-plugin/src/__tests__/plugin.test.ts +++ b/packages/next-plugin/src/__tests__/plugin.test.ts @@ -4,9 +4,11 @@ import { join, resolve } from 'node:path' import { DevupUIWebpackPlugin } from '@devup-ui/webpack-plugin' import { DevupUI } from '../plugin' +import { preload } from '../preload' vi.mock('@devup-ui/webpack-plugin') vi.mock('node:fs') +vi.mock('../preload') describe('DevupUINextPlugin', () => { describe('webpack', () => { @@ -85,20 +87,42 @@ describe('DevupUINextPlugin', () => { loader: '@devup-ui/webpack-plugin/css-loader', }, ], - '*.{tsx,ts,js,mjs}': [ - { - loader: '@devup-ui/webpack-plugin/loader', - options: { - package: '@devup-ui/react', - cssDir: resolve('df', 'devup-ui'), - sheetFile: join('df', 'sheet.json'), - classMapFile: join('df', 'classMap.json'), - fileMapFile: join('df', 'fileMap.json'), - watch: false, - singleCss: false, + '*.{tsx,ts,js,mjs}': { + loaders: [ + { + loader: '@devup-ui/webpack-plugin/loader', + options: { + package: '@devup-ui/react', + cssDir: resolve('df', 'devup-ui'), + sheetFile: join('df', 'sheet.json'), + classMapFile: join('df', 'classMap.json'), + fileMapFile: join('df', 'fileMap.json'), + watch: false, + singleCss: false, + theme: {}, + defaultClassMap: {}, + defaultFileMap: {}, + defaultSheet: { + css: {}, + font_faces: {}, + global_css_files: [], + imports: {}, + keyframes: {}, + properties: {}, + }, + }, + }, + ], + condition: { + not: { + path: new RegExp( + `node_modules(?!.*(${['@devup-ui'] + .join('|') + .replaceAll('/', '[\\/\\\\_]')})([\\/\\\\.]|$))`, + ), }, }, - ], + }, }, }, }) @@ -118,20 +142,42 @@ describe('DevupUINextPlugin', () => { loader: '@devup-ui/webpack-plugin/css-loader', }, ], - '*.{tsx,ts,js,mjs}': [ - { - loader: '@devup-ui/webpack-plugin/loader', - options: { - package: '@devup-ui/react', - cssDir: resolve('df', 'devup-ui'), - sheetFile: join('df', 'sheet.json'), - classMapFile: join('df', 'classMap.json'), - fileMapFile: join('df', 'fileMap.json'), - watch: false, - singleCss: false, + '*.{tsx,ts,js,mjs}': { + condition: { + not: { + path: new RegExp( + `node_modules(?!.*(${['@devup-ui'] + .join('|') + .replaceAll('/', '[\\/\\\\_]')})([\\/\\\\.]|$))`, + ), }, }, - ], + loaders: [ + { + loader: '@devup-ui/webpack-plugin/loader', + options: { + package: '@devup-ui/react', + cssDir: resolve('df', 'devup-ui'), + sheetFile: join('df', 'sheet.json'), + classMapFile: join('df', 'classMap.json'), + fileMapFile: join('df', 'fileMap.json'), + watch: false, + singleCss: false, + theme: {}, + defaultClassMap: {}, + defaultFileMap: {}, + defaultSheet: { + css: {}, + font_faces: {}, + global_css_files: [], + imports: {}, + keyframes: {}, + properties: {}, + }, + }, + }, + ], + }, }, }, }) @@ -158,21 +204,42 @@ describe('DevupUINextPlugin', () => { loader: '@devup-ui/webpack-plugin/css-loader', }, ], - '*.{tsx,ts,js,mjs}': [ - { - loader: '@devup-ui/webpack-plugin/loader', - options: { - package: '@devup-ui/react', - cssDir: resolve('df', 'devup-ui'), - sheetFile: join('df', 'sheet.json'), - classMapFile: join('df', 'classMap.json'), - fileMapFile: join('df', 'fileMap.json'), - watch: false, - singleCss: false, - theme: 'theme', + '*.{tsx,ts,js,mjs}': { + condition: { + not: { + path: new RegExp( + `node_modules(?!.*(${['@devup-ui'] + .join('|') + .replaceAll('/', '[\\/\\\\_]')})([\\/\\\\.]|$))`, + ), }, }, - ], + loaders: [ + { + loader: '@devup-ui/webpack-plugin/loader', + options: { + package: '@devup-ui/react', + cssDir: resolve('df', 'devup-ui'), + sheetFile: join('df', 'sheet.json'), + classMapFile: join('df', 'classMap.json'), + fileMapFile: join('df', 'fileMap.json'), + watch: false, + singleCss: false, + theme: 'theme', + defaultClassMap: {}, + defaultFileMap: {}, + defaultSheet: { + css: {}, + font_faces: {}, + global_css_files: [], + imports: {}, + keyframes: {}, + properties: {}, + }, + }, + }, + ], + }, }, }, }) @@ -184,9 +251,23 @@ describe('DevupUINextPlugin', () => { it('should throw error if NODE_ENV is production', () => { vi.stubEnv('NODE_ENV', 'production') vi.stubEnv('TURBOPACK', '1') - const ret = () => DevupUI({}) - expect(ret).toThrow( - 'Devup UI is not supported in production with turbopack', + vi.mocked(preload).mockReturnValue() + const ret = DevupUI({}) + expect(ret).toEqual({ + turbopack: { + rules: expect.any(Object), + }, + }) + expect(preload).toHaveBeenCalledWith( + new RegExp( + `node_modules(?!.*(${['@devup-ui'] + .join('|') + .replaceAll('/', '[\\/\\\\_]')})([\\/\\\\.]|$))`, + ), + '@devup-ui/react', + false, + 'theme', + expect.any(String), ) }) }) diff --git a/packages/next-plugin/src/__tests__/preload.test.ts b/packages/next-plugin/src/__tests__/preload.test.ts new file mode 100644 index 00000000..52248489 --- /dev/null +++ b/packages/next-plugin/src/__tests__/preload.test.ts @@ -0,0 +1,259 @@ +import { globSync, writeFileSync } from 'node:fs' +import { readFileSync } from 'node:fs' +import { existsSync } from 'node:fs' +import { join } from 'node:path' + +import { codeExtract, registerTheme } from '@devup-ui/wasm' + +import { findRoot } from '../find-root' +import { preload } from '../preload' + +// Mock dependencies +vi.mock('node:fs') +vi.mock('@devup-ui/wasm') +vi.mock('../find-root') + +// Mock globSync +vi.mock('node:fs', () => ({ + globSync: vi.fn(), + readFileSync: vi.fn(), + writeFileSync: vi.fn(), + mkdirSync: vi.fn(), + existsSync: vi.fn(), +})) + +// Mock @devup-ui/wasm +vi.mock('@devup-ui/wasm', () => ({ + codeExtract: vi.fn(), + registerTheme: vi.fn(), +})) + +// Mock findRoot +vi.mock('../find-root', () => ({ + findRoot: vi.fn(), +})) + +describe('preload', () => { + beforeEach(() => { + vi.clearAllMocks() + + // Default mock implementations + vi.mocked(findRoot).mockReturnValue('/project/root') + vi.mocked(globSync).mockReturnValue([ + 'src/App.tsx', + 'src/components/Button.tsx', + ]) + vi.mocked(readFileSync).mockReturnValue( + 'const Button = () =>
Hello
', + ) + vi.mocked(codeExtract).mockReturnValue({ + free: vi.fn(), + cssFile: 'styles.css', + css: '.button { color: red; }', + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + vi.mocked(existsSync).mockReturnValue(true) + }) + + it('should find project root and collect files', () => { + const excludeRegex = /node_modules/ + const libPackage = '@devup-ui/react' + const singleCss = false + const theme = { colors: { primary: 'blue' } } + const cssDir = '/output/css' + + preload(excludeRegex, libPackage, singleCss, theme, cssDir) + + expect(findRoot).toHaveBeenCalledWith(process.cwd()) + expect(globSync).toHaveBeenCalledWith( + ['**/*.tsx', '**/*.ts', '**/*.js', '**/*.mjs'], + { + cwd: '/project/root', + exclude: expect.any(Function), + }, + ) + }) + + it('should register theme before processing files', () => { + const theme = { colors: { primary: 'blue' } } + + preload(/node_modules/, '@devup-ui/react', false, theme, '/output/css') + + expect(registerTheme).toHaveBeenCalledWith(theme) + }) + + it('should process each collected file', () => { + const files = ['src/App.tsx', 'src/components/Button.tsx'] + vi.mocked(globSync).mockReturnValue(files) + + preload(/node_modules/, '@devup-ui/react', false, {}, '/output/css') + + expect(codeExtract).toHaveBeenCalledTimes(2) + expect(codeExtract).toHaveBeenCalledWith( + expect.stringMatching(/App\.tsx$/), + 'const Button = () =>
Hello
', + '@devup-ui/react', + '/output/css', + false, + false, + true, + ) + }) + + it('should write CSS file when cssFile is returned', () => { + vi.mocked(codeExtract).mockReturnValue({ + cssFile: 'styles.css', + css: '.button { color: red; }', + free: vi.fn(), + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + + preload(/node_modules/, '@devup-ui/react', false, {}, '/output/css') + + expect(writeFileSync).toHaveBeenCalledWith( + join('/output/css', 'styles.css'), + '.button { color: red; }', + 'utf-8', + ) + }) + + it('should not write CSS file when cssFile is null', () => { + vi.mocked(codeExtract).mockReturnValue({ + cssFile: undefined, + css: '.button { color: red; }', + free: vi.fn(), + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + + preload(/node_modules/, '@devup-ui/react', false, {}, '/output/css') + + expect(writeFileSync).not.toHaveBeenCalled() + }) + + it('should handle empty CSS content', () => { + vi.mocked(codeExtract).mockReturnValue({ + cssFile: 'styles.css', + css: '', + free: vi.fn(), + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + + preload(/node_modules/, '@devup-ui/react', false, {}, '/output/css') + + expect(writeFileSync).toHaveBeenCalledWith( + join('/output/css', 'styles.css'), + '', + 'utf-8', + ) + }) + + it('should handle undefined CSS content', () => { + vi.mocked(codeExtract).mockReturnValue({ + cssFile: 'styles.css', + css: undefined, + free: vi.fn(), + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + + preload(/node_modules/, '@devup-ui/react', false, {}, '/output/css') + + expect(writeFileSync).toHaveBeenCalledWith( + join('/output/css', 'styles.css'), + '', + 'utf-8', + ) + }) + + it('should pass correct parameters to codeExtract', () => { + const libPackage = '@devup-ui/react' + const singleCss = true + const cssDir = '/custom/css/dir' + + preload(/node_modules/, libPackage, singleCss, {}, cssDir) + + expect(codeExtract).toHaveBeenCalledWith( + expect.stringMatching(/App\.tsx$/), + 'const Button = () =>
Hello
', + libPackage, + cssDir, + singleCss, + false, + true, + ) + }) + + it('should handle multiple files with different CSS outputs', () => { + const files = ['src/App.tsx', 'src/components/Button.tsx'] + vi.mocked(globSync).mockReturnValue(files) + + vi.mocked(codeExtract) + .mockReturnValueOnce({ + cssFile: 'app.css', + css: '.app { margin: 0; }', + free: vi.fn(), + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + .mockReturnValueOnce({ + free: vi.fn(), + cssFile: 'button.css', + css: '.button { color: blue; }', + code: '', + map: '', + updatedBaseStyle: false, + [Symbol.dispose]: vi.fn(), + }) + + preload(/node_modules/, '@devup-ui/react', false, {}, '/output/css') + + expect(writeFileSync).toHaveBeenCalledTimes(2) + expect(writeFileSync).toHaveBeenCalledWith( + join('/output/css', 'app.css'), + '.app { margin: 0; }', + 'utf-8', + ) + expect(writeFileSync).toHaveBeenCalledWith( + join('/output/css', 'button.css'), + '.button { color: blue; }', + 'utf-8', + ) + }) + it('should handle exclude regex', () => { + const excludeRegex = /node_modules/ + const libPackage = '@devup-ui/react' + const singleCss = false + const theme = { colors: { primary: 'blue' } } + const cssDir = '/output/css' + + preload(excludeRegex, libPackage, singleCss, theme, cssDir) + expect(globSync).toHaveBeenCalledWith( + ['**/*.tsx', '**/*.ts', '**/*.js', '**/*.mjs'], + { + cwd: '/project/root', + exclude: expect.any(Function), + }, + ) + expect( + (vi.mocked(globSync).mock.calls[0][1].exclude as any)( + '/node_modules/react.tsx', + ), + ).toBe(true) + }) +}) diff --git a/packages/next-plugin/src/find-root.ts b/packages/next-plugin/src/find-root.ts new file mode 100644 index 00000000..dfd3e621 --- /dev/null +++ b/packages/next-plugin/src/find-root.ts @@ -0,0 +1,16 @@ +import { existsSync } from 'node:fs' +import { dirname, join } from 'node:path' + +export function findRoot(dir: string): string { + let root = dir + let prev = null + let result: string = process.cwd() + while (prev === null || root !== prev) { + if (existsSync(join(root, 'package.json'))) { + result = root + } + prev = root + root = dirname(root) + } + return result +} diff --git a/packages/next-plugin/src/plugin.ts b/packages/next-plugin/src/plugin.ts index 9f63af06..0d678188 100644 --- a/packages/next-plugin/src/plugin.ts +++ b/packages/next-plugin/src/plugin.ts @@ -1,12 +1,15 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' import { join, relative, resolve } from 'node:path' +import { exportClassMap, exportFileMap, exportSheet } from '@devup-ui/wasm' import { DevupUIWebpackPlugin, type DevupUIWebpackPluginOptions, } from '@devup-ui/webpack-plugin' import { type NextConfig } from 'next' +import { preload } from './preload' + type DevupUiNextPluginOptions = Omit< Partial, 'watch' @@ -26,9 +29,9 @@ export function DevupUI( process.env.TURBOPACK === '1' || process.env.TURBOPACK === 'auto' // turbopack is now stable, TURBOPACK is set to auto without any flags if (isTurbo) { - if (process.env.NODE_ENV === 'production') { - throw new Error('Devup UI is not supported in production with turbopack') - } + // if (process.env.NODE_ENV === 'production') { + // throw new Error('Devup UI is not supported in production with turbopack') + // } config ??= {} config.turbopack ??= {} @@ -39,6 +42,7 @@ export function DevupUI( cssDir = resolve(distDir, 'devup-ui'), singleCss = false, devupFile = 'devup.json', + include = [], } = options const sheetFile = join(distDir, 'sheet.json') @@ -54,10 +58,25 @@ export function DevupUI( recursive: true, }) if (!existsSync(gitignoreFile)) writeFileSync(gitignoreFile, '*') + const theme = existsSync(devupFile) + ? JSON.parse(readFileSync(devupFile, 'utf-8'))?.['theme'] + : {} // disable turbo parallel - process.env.TURBOPACK_DEBUG_JS = '*' - process.env.NODE_OPTIONS ??= '' - process.env.NODE_OPTIONS += ' --inspect-brk' + const excludeRegex = new RegExp( + `node_modules(?!.*(${['@devup-ui', ...include] + .join('|') + .replaceAll('/', '[\\/\\\\_]')})([\\/\\\\.]|$))`, + ) + + if (process.env.NODE_ENV !== 'production') { + // dev + process.env.TURBOPACK_DEBUG_JS = '*' + process.env.NODE_OPTIONS ??= '' + process.env.NODE_OPTIONS += ' --inspect-brk' + } else { + // build + preload(excludeRegex, libPackage, singleCss, theme, cssDir) + } const rules: NonNullable = { [`./${relative(process.cwd(), cssDir).replaceAll('\\', '/')}/*.css`]: [ @@ -65,24 +84,32 @@ export function DevupUI( loader: '@devup-ui/webpack-plugin/css-loader', }, ], - '*.{tsx,ts,js,mjs}': [ - { - loader: '@devup-ui/webpack-plugin/loader', - options: { - package: libPackage, - cssDir, - sheetFile, - classMapFile, - fileMapFile, - watch: process.env.NODE_ENV === 'development', - singleCss, - // for turbopack, load theme is required on loader - theme: existsSync(devupFile) - ? JSON.parse(readFileSync(devupFile, 'utf-8'))?.['theme'] - : undefined, + '*.{tsx,ts,js,mjs}': { + loaders: [ + { + loader: '@devup-ui/webpack-plugin/loader', + options: { + package: libPackage, + cssDir, + sheetFile, + classMapFile, + fileMapFile, + defaultSheet: JSON.parse(exportSheet()), + defaultClassMap: JSON.parse(exportClassMap()), + defaultFileMap: JSON.parse(exportFileMap()), + watch: process.env.NODE_ENV === 'development', + singleCss, + // for turbopack, load theme is required on loader + theme, + }, + }, + ], + condition: { + not: { + path: excludeRegex, }, }, - ], + }, } Object.assign(config.turbopack.rules, rules) return config diff --git a/packages/next-plugin/src/preload.ts b/packages/next-plugin/src/preload.ts new file mode 100644 index 00000000..8fb52fc5 --- /dev/null +++ b/packages/next-plugin/src/preload.ts @@ -0,0 +1,38 @@ +import { globSync, readFileSync, writeFileSync } from 'node:fs' +import { basename, join, relative } from 'node:path' + +import { codeExtract, registerTheme } from '@devup-ui/wasm' + +import { findRoot } from './find-root' + +export function preload( + excludeRegex: RegExp, + libPackage: string, + singleCss: boolean, + theme: object, + cssDir: string, +) { + const projectRoot = findRoot(process.cwd()) + + const collected = globSync(['**/*.tsx', '**/*.ts', '**/*.js', '**/*.mjs'], { + cwd: projectRoot, + exclude: (fileName) => excludeRegex.test(fileName), + }) + registerTheme(theme) + for (const file of collected) { + const filePath = relative(process.cwd(), join(projectRoot, file)) + const { cssFile, css } = codeExtract( + filePath, + readFileSync(filePath, 'utf-8'), + libPackage, + cssDir, + singleCss, + false, + true, + ) + + if (cssFile) { + writeFileSync(join(cssDir, basename(cssFile!)), css ?? '', 'utf-8') + } + } +} diff --git a/packages/react/src/utils/global-css.ts b/packages/react/src/utils/global-css.ts index b3dfcc72..5b55b9df 100644 --- a/packages/react/src/utils/global-css.ts +++ b/packages/react/src/utils/global-css.ts @@ -2,11 +2,11 @@ import type { DevupCommonProps } from '../types/props' import type { AdvancedSelector, CamelCase, + DevupSelectorProps, DevupThemeSelectorProps, ExtractSelector, SimpleSelector, } from '../types/props/selector' -import type { DevupSelectorProps } from '../types/props/selector' type GlobalCssKeys = | `*${T}` @@ -22,16 +22,21 @@ type GlobalCssProps = { } } & { [K in GlobalCssKeys< - Exclude + Extract >]?: DevupCommonProps & DevupSelectorProps & DevupThemeSelectorProps & { params?: string[] } } & { - [K in GlobalCssKeys | (string & {})]?: DevupCommonProps & + [K in GlobalCssKeys]?: DevupCommonProps & DevupSelectorProps & DevupThemeSelectorProps +} & { + [K in + | keyof HTMLElementTagNameMap + | keyof SVGElementTagNameMap + | '*']?: DevupCommonProps & DevupSelectorProps & DevupThemeSelectorProps } interface FontFaceProps { @@ -52,24 +57,35 @@ interface FontFaceProps { } type Import = { url: string; query?: string } | string +interface AdditionalGlobalCssProps { + imports?: Import[] + fontFaces?: FontFaceProps[] +} + export function globalCss( - strings?: - | TemplateStringsArray - | (Omit & { - imports?: Import[] - fontFaces?: FontFaceProps[] - }), + strings: AdditionalGlobalCssProps & GlobalCssProps, ): void +export function globalCss( + strings: Record< + string, + DevupCommonProps & DevupSelectorProps & DevupThemeSelectorProps + >, +): void + +export function globalCss(strings?: TemplateStringsArray): void + export function globalCss(): void export function globalCss( // eslint-disable-next-line @typescript-eslint/no-unused-vars strings?: | TemplateStringsArray - | (Omit & { - imports?: Import[] - }), + | (GlobalCssProps & AdditionalGlobalCssProps) + | Record< + string, + DevupCommonProps & DevupSelectorProps & DevupThemeSelectorProps + >, ): void { throw new Error('Cannot run on the runtime') } diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index f4911405..42005190 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -4,7 +4,8 @@ "vite/client", "vitest/importMeta", "vitest/globals", - "@testing-library/jest-dom" + "@testing-library/jest-dom", + "node" ], "strict": true, "target": "ESNext", diff --git a/packages/webpack-plugin/src/__tests__/css-loader.test.ts b/packages/webpack-plugin/src/__tests__/css-loader.test.ts index a151173f..51f8eba9 100644 --- a/packages/webpack-plugin/src/__tests__/css-loader.test.ts +++ b/packages/webpack-plugin/src/__tests__/css-loader.test.ts @@ -5,7 +5,10 @@ import { getCss } from '@devup-ui/wasm' import devupUICssLoader from '../css-loader' vi.mock('node:path') -vi.mock('@devup-ui/wasm') +vi.mock('@devup-ui/wasm', () => ({ + registerTheme: vi.fn(), + getCss: vi.fn(), +})) beforeEach(() => { vi.resetAllMocks() diff --git a/packages/webpack-plugin/src/__tests__/loader.test.ts b/packages/webpack-plugin/src/__tests__/loader.test.ts index 7e620a5e..6d3183f6 100644 --- a/packages/webpack-plugin/src/__tests__/loader.test.ts +++ b/packages/webpack-plugin/src/__tests__/loader.test.ts @@ -7,11 +7,12 @@ import { exportFileMap, exportSheet, getCss, + importClassMap, + importFileMap, + importSheet, registerTheme, } from '@devup-ui/wasm' -import devupUILoader from '../loader' - vi.mock('@devup-ui/wasm') vi.mock('node:fs/promises') vi.mock('node:path', async (original: any) => { @@ -24,6 +25,7 @@ vi.mock('node:path', async (original: any) => { beforeEach(() => { vi.resetAllMocks() + vi.resetModules() Date.now = vi.fn().mockReturnValue(0) }) @@ -33,6 +35,7 @@ describe('devupUILoader', () => { updatedBaseStyle: [true, false], }), )('should extract code with css', async (options) => { + const { default: devupUILoader } = await import('../loader') const _compiler = { __DEVUP_CACHE: '', } @@ -102,7 +105,8 @@ describe('devupUILoader', () => { }) }) - it('should extract code without css', () => { + it('should extract code without css', async () => { + const { default: devupUILoader } = await import('../loader') const t = { getOptions: () => ({ package: 'package', @@ -141,7 +145,8 @@ describe('devupUILoader', () => { }) }) - it('should handle error', () => { + it('should handle error', async () => { + const { default: devupUILoader } = await import('../loader') const t = { getOptions: () => ({ package: 'package', @@ -162,7 +167,8 @@ describe('devupUILoader', () => { expect(t.async()).toHaveBeenCalledWith(new Error('error')) }) - it('should load with date now on watch', () => { + it('should load with date now on watch', async () => { + const { default: devupUILoader } = await import('../loader') const t = { getOptions: () => ({ package: 'package', @@ -197,7 +203,8 @@ describe('devupUILoader', () => { ) }) - it('should load with nowatch', () => { + it('should load with nowatch', async () => { + const { default: devupUILoader } = await import('../loader') const t = { getOptions: () => ({ package: 'package', @@ -221,7 +228,8 @@ describe('devupUILoader', () => { vi.mocked(relative).mockReturnValue('./foo/index.tsx') devupUILoader.bind(t as any)(Buffer.from('code'), '/foo/index.tsx') }) - it('should load with theme', () => { + it('should load with theme', async () => { + const { default: devupUILoader } = await import('../loader') const t = { getOptions: () => ({ package: 'package', @@ -255,4 +263,51 @@ describe('devupUILoader', () => { }, }) }) + + it('should register theme on init', async () => { + const { default: devupUILoader } = await import('../loader') + const t = { + getOptions: () => ({ + package: 'package', + cssDir: 'cssFile', + watch: false, + singleCss: true, + theme: { + colors: { + primary: '#000', + }, + }, + defaultClassMap: { + button: 'button', + }, + defaultFileMap: { + button: 'button', + }, + defaultSheet: { + button: 'button', + }, + }), + async: vi.fn().mockReturnValue(vi.fn()), + resourcePath: 'index.tsx', + addDependency: vi.fn(), + } + devupUILoader.bind(t as any)(Buffer.from('code'), 'index.tsx') + expect(registerTheme).toHaveBeenCalledTimes(1) + expect(importClassMap).toHaveBeenCalledWith({ + button: 'button', + }) + expect(importFileMap).toHaveBeenCalledWith({ + button: 'button', + }) + expect(importSheet).toHaveBeenCalledWith({ + button: 'button', + }) + + devupUILoader.bind(t as any)(Buffer.from('code'), 'index.tsx') + + expect(registerTheme).toHaveBeenCalledTimes(1) + expect(importClassMap).toHaveBeenCalledTimes(1) + expect(importFileMap).toHaveBeenCalledTimes(1) + expect(importSheet).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/webpack-plugin/src/loader.ts b/packages/webpack-plugin/src/loader.ts index ee91f231..3ee7077a 100644 --- a/packages/webpack-plugin/src/loader.ts +++ b/packages/webpack-plugin/src/loader.ts @@ -7,6 +7,9 @@ import { exportFileMap, exportSheet, getCss, + importClassMap, + importFileMap, + importSheet, registerTheme, } from '@devup-ui/wasm' import type { RawLoaderDefinitionFunction } from 'webpack' @@ -19,7 +22,11 @@ export interface DevupUILoaderOptions { fileMapFile: string watch: boolean singleCss: boolean + // turbo theme?: object + defaultSheet: object + defaultClassMap: object + defaultFileMap: object } let init = false @@ -34,21 +41,26 @@ const devupUILoader: RawLoaderDefinitionFunction = fileMapFile, singleCss, theme, + defaultClassMap, + defaultFileMap, + defaultSheet, } = this.getOptions() const callback = this.async() const id = this.resourcePath - if (theme && !init) { + if (!init) { init = true - registerTheme(theme) + if (defaultFileMap) importFileMap(defaultFileMap) + if (defaultClassMap) importClassMap(defaultClassMap) + if (defaultSheet) importSheet(defaultSheet) + if (theme) registerTheme(theme) } try { - let rel = relative(dirname(this.resourcePath), cssDir).replaceAll( - '\\', - '/', - ) + let relCssDir = relative(dirname(id), cssDir).replaceAll('\\', '/') + + const relativePath = relative(process.cwd(), id) - if (!rel.startsWith('./')) rel = `./${rel}` + if (!relCssDir.startsWith('./')) relCssDir = `./${relCssDir}` const { code, css = '', @@ -56,10 +68,10 @@ const devupUILoader: RawLoaderDefinitionFunction = cssFile, updatedBaseStyle, } = codeExtract( - id, + relativePath, source.toString(), libPackage, - rel, + relCssDir, singleCss, false, true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c0bf275..f2faad63 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -100,7 +100,7 @@ importers: version: 1.3.11(react@19.2.0) next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -135,6 +135,9 @@ importers: '@types/react-syntax-highlighter': specifier: ^15.5 version: 15.5.13 + babel-plugin-react-compiler: + specifier: ^1.0 + version: 1.0.0 typescript: specifier: ^5 version: 5.9.3 @@ -146,7 +149,7 @@ importers: version: link:../../packages/react next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -270,7 +273,7 @@ importers: version: 11.14.0(@types/react@19.2.2)(react@19.2.0) next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) next-themes: specifier: ^0.4 version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -304,7 +307,7 @@ importers: version: link:../../packages/react next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -335,7 +338,38 @@ importers: version: link:../../packages/react next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: + specifier: ^19.2 + version: 19.2.0 + react-dom: + specifier: ^19.2 + version: 19.2.0(react@19.2.0) + devDependencies: + '@devup-ui/next-plugin': + specifier: workspace:* + version: link:../../packages/next-plugin + '@types/node': + specifier: ^24 + version: 24.9.1 + '@types/react': + specifier: ^19 + version: 19.2.2 + '@types/react-dom': + specifier: ^19 + version: 19.2.2(@types/react@19.2.2) + typescript: + specifier: ^5 + version: 5.9.3 + + benchmark/next-devup-ui-single-turbo: + dependencies: + '@devup-ui/react': + specifier: workspace:* + version: link:../../packages/react + next: + specifier: ^16.0 + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -363,10 +397,10 @@ importers: dependencies: '@kuma-ui/core': specifier: ^1.5 - version: 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + version: 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -376,7 +410,7 @@ importers: devDependencies: '@kuma-ui/next-plugin': specifier: ^1.3 - version: 1.3.3(@babel/core@7.28.4)(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1) + version: 1.3.3(@babel/core@7.28.4)(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1) '@types/node': specifier: ^24 version: 24.9.1 @@ -403,7 +437,7 @@ importers: version: 7.3.4(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react@19.2.0))(@types/react@19.2.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -431,7 +465,7 @@ importers: dependencies: next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -468,7 +502,7 @@ importers: version: 1.0.0(react@19.2.0) next: specifier: '16.0' - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: '19.2' version: 19.2.0 @@ -496,7 +530,7 @@ importers: version: 0.16.2 '@stylexjs/nextjs-plugin': specifier: ^0.11 - version: 0.11.1(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) + version: 0.11.1(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) '@types/node': specifier: '24.9' version: 24.9.1 @@ -535,7 +569,44 @@ importers: dependencies: next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: + specifier: ^19.2 + version: 19.2.0 + react-dom: + specifier: ^19.2 + version: 19.2.0(react@19.2.0) + react-icons: + specifier: ^5.5 + version: 5.5.0(react@19.2.0) + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.1 + version: 4.1.16 + '@types/node': + specifier: ^24 + version: 24.9.1 + '@types/react': + specifier: ^19 + version: 19.2.2 + '@types/react-dom': + specifier: ^19 + version: 19.2.2(@types/react@19.2.2) + postcss: + specifier: ^8.5 + version: 8.5.6 + tailwindcss: + specifier: ^4.1 + version: 4.1.16 + typescript: + specifier: ^5 + version: 5.9.3 + + benchmark/next-tailwind-turbo: + dependencies: + next: + specifier: ^16.0 + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -575,7 +646,7 @@ importers: version: 1.17.4(babel-plugin-macros@3.1.0) next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2 version: 19.2.0 @@ -597,7 +668,7 @@ importers: version: 19.2.2(@types/react@19.2.2) '@vanilla-extract/next-plugin': specifier: ^2.4 - version: 2.4.14(babel-plugin-macros@3.1.0)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(webpack@5.102.1) + version: 2.4.14(babel-plugin-macros@3.1.0)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(webpack@5.102.1) typescript: specifier: ^5 version: 5.9.3 @@ -691,7 +762,7 @@ importers: version: link:../webpack-plugin next: specifier: ^16.0 - version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) devDependencies: '@types/webpack': specifier: ^5.28 @@ -3800,6 +3871,9 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-react-compiler@1.0.0: + resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -8687,10 +8761,10 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@kuma-ui/babel-plugin@1.2.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': + '@kuma-ui/babel-plugin@1.2.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': dependencies: '@babel/core': 7.28.4 - '@kuma-ui/core': 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@kuma-ui/core': 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) '@kuma-ui/sheet': 1.3.1 '@kuma-ui/system': 1.7.6 transitivePeerDependencies: @@ -8699,11 +8773,11 @@ snapshots: - react - supports-color - '@kuma-ui/compiler@1.3.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': + '@kuma-ui/compiler@1.3.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': dependencies: '@babel/core': 7.28.4 - '@kuma-ui/babel-plugin': 1.2.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) - '@kuma-ui/core': 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@kuma-ui/babel-plugin': 1.2.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@kuma-ui/core': 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) '@kuma-ui/sheet': 1.3.1 '@kuma-ui/system': 1.7.6 '@kuma-ui/wasm': 1.0.3 @@ -8714,7 +8788,7 @@ snapshots: - react - supports-color - '@kuma-ui/core@1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': + '@kuma-ui/core@1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': dependencies: '@kuma-ui/sheet': 1.3.1 '@kuma-ui/system': 1.7.6 @@ -8723,18 +8797,18 @@ snapshots: stylis: 4.3.6 optionalDependencies: '@types/react': 19.2.2 - next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@kuma-ui/next-plugin@1.3.3(@babel/core@7.28.4)(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1)': + '@kuma-ui/next-plugin@1.3.3(@babel/core@7.28.4)(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1)': dependencies: '@babel/preset-env': 7.28.3(@babel/core@7.28.4) '@babel/preset-react': 7.27.1(@babel/core@7.28.4) '@babel/preset-typescript': 7.27.1(@babel/core@7.28.4) - '@kuma-ui/core': 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) - '@kuma-ui/webpack-plugin': 1.4.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1) + '@kuma-ui/core': 1.5.9(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@kuma-ui/webpack-plugin': 1.4.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1) babel-loader: 9.2.1(@babel/core@7.28.4)(webpack@5.102.1) browserslist: 4.21.5 - next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: 19.2.0 webpack: 5.102.1 optionalDependencies: @@ -8754,9 +8828,9 @@ snapshots: '@kuma-ui/wasm@1.0.3': {} - '@kuma-ui/webpack-plugin@1.4.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1)': + '@kuma-ui/webpack-plugin@1.4.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(webpack@5.102.1)': dependencies: - '@kuma-ui/compiler': 1.3.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@kuma-ui/compiler': 1.3.3(@types/react@19.2.2)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) '@kuma-ui/sheet': 1.3.1 '@kuma-ui/system': 1.7.6 esbuild: 0.18.20 @@ -9560,14 +9634,14 @@ snapshots: micromatch: 4.0.8 postcss-value-parser: 4.2.0 - '@stylexjs/nextjs-plugin@0.11.1(next@16.0.0(@babel/core@7.28.4)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': + '@stylexjs/nextjs-plugin@0.11.1(next@16.0.0(@babel/core@7.28.4)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.28.4) '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) '@stylexjs/babel-plugin': 0.11.1 - next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) transitivePeerDependencies: - supports-color @@ -10080,10 +10154,10 @@ snapshots: - babel-plugin-macros - supports-color - '@vanilla-extract/next-plugin@2.4.14(babel-plugin-macros@3.1.0)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(webpack@5.102.1)': + '@vanilla-extract/next-plugin@2.4.14(babel-plugin-macros@3.1.0)(next@16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(webpack@5.102.1)': dependencies: '@vanilla-extract/webpack-plugin': 2.3.22(babel-plugin-macros@3.1.0)(webpack@5.102.1) - next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + next: 16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -11082,6 +11156,10 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-react-compiler@1.0.0: + dependencies: + '@babel/types': 7.28.4 + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -13366,7 +13444,7 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - next@16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + next@16.0.0(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@next/env': 16.0.0 '@swc/helpers': 0.5.15 @@ -13384,6 +13462,7 @@ snapshots: '@next/swc-linux-x64-musl': 16.0.0 '@next/swc-win32-arm64-msvc': 16.0.0 '@next/swc-win32-x64-msvc': 16.0.0 + babel-plugin-react-compiler: 1.0.0 sharp: 0.34.4 transitivePeerDependencies: - '@babel/core'