From 0b7d5b2d81776169585708431d08a12940d53b2c Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 17:14:23 +0900 Subject: [PATCH 01/11] Support Turbopack --- apps/landing/package.json | 2 +- packages/next-plugin/src/find-root.ts | 19 ++++++++ packages/next-plugin/src/plugin.ts | 69 ++++++++++++++++++--------- packages/next-plugin/src/preload.ts | 38 +++++++++++++++ packages/webpack-plugin/src/loader.ts | 30 ++++++++---- 5 files changed, 126 insertions(+), 32 deletions(-) create mode 100644 packages/next-plugin/src/find-root.ts create mode 100644 packages/next-plugin/src/preload.ts diff --git a/apps/landing/package.json b/apps/landing/package.json index c87515f6..aaec7a09 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" }, diff --git a/packages/next-plugin/src/find-root.ts b/packages/next-plugin/src/find-root.ts new file mode 100644 index 00000000..36011b03 --- /dev/null +++ b/packages/next-plugin/src/find-root.ts @@ -0,0 +1,19 @@ +import { existsSync } from 'node:fs' +import { dirname, join } from 'node:path' + +export function findRoot(dir: string) { + let root = dir + let prev = null + const collectecd: string[] = [] + while (prev === null || root !== prev) { + if (existsSync(join(root, 'package.json')) && !collectecd.includes(root)) { + collectecd.push(root) + } + prev = root + root = dirname(root) + } + if (collectecd.length > 0) { + return collectecd.pop() ?? process.cwd() + } + return process.cwd() +} diff --git a/packages/next-plugin/src/plugin.ts b/packages/next-plugin/src/plugin.ts index 9f63af06..6d3a6bd7 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,23 @@ export function DevupUI( recursive: true, }) if (!existsSync(gitignoreFile)) writeFileSync(gitignoreFile, '*') + const theme = existsSync(devupFile) + ? JSON.parse(readFileSync(devupFile, 'utf-8'))?.['theme'] + : undefined // 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') { + process.env.TURBOPACK_DEBUG_JS = '*' + process.env.NODE_OPTIONS ??= '' + process.env.NODE_OPTIONS += ' --inspect-brk' + } else { + preload(excludeRegex, libPackage, singleCss, theme, cssDir) + } const rules: NonNullable = { [`./${relative(process.cwd(), cssDir).replaceAll('\\', '/')}/*.css`]: [ @@ -65,24 +82,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..4f0dae12 --- /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/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, From a8a110ad3c11e4548b6f8a69ecb23313c6bacfa7 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 17:44:19 +0900 Subject: [PATCH 02/11] Support Turbopack --- .changeset/tired-berries-wonder.md | 6 +++ .github/workflows/publish.yml | 39 ++++++++++++-- benchmark.js | 18 +++++++ benchmark/next-chakra-ui/tsconfig.json | 5 +- .../next-devup-ui-single-turbo/.gitignore | 41 ++++++++++++++ .../next-devup-ui-single-turbo/README.md | 1 + .../next-devup-ui-single-turbo/next.config.ts | 7 +++ .../next-devup-ui-single-turbo/package.json | 25 +++++++++ .../public/file.svg | 1 + .../public/globe.svg | 1 + .../public/next.svg | 1 + .../public/vercel.svg | 1 + .../public/window.svg | 1 + .../src/app/favicon.ico | Bin 0 -> 25931 bytes .../src/app/layout.tsx | 18 +++++++ .../src/app/page.tsx | 51 ++++++++++++++++++ .../next-devup-ui-single-turbo/tsconfig.json | 34 ++++++++++++ benchmark/next-devup-ui-single/tsconfig.json | 5 +- benchmark/next-devup-ui/tsconfig.json | 5 +- benchmark/next-kuma-ui/tsconfig.json | 5 +- benchmark/next-mui/tsconfig.json | 5 +- benchmark/next-panda-css/tsconfig.json | 5 +- benchmark/next-stylex/tsconfig.json | 5 +- benchmark/next-tailwind-turbo/.gitignore | 41 ++++++++++++++ benchmark/next-tailwind-turbo/README.md | 1 + benchmark/next-tailwind-turbo/next.config.mjs | 1 + benchmark/next-tailwind-turbo/package.json | 27 ++++++++++ .../next-tailwind-turbo/postcss.config.mjs | 7 +++ benchmark/next-tailwind-turbo/public/file.svg | 1 + .../next-tailwind-turbo/public/globe.svg | 1 + benchmark/next-tailwind-turbo/public/next.svg | 1 + .../next-tailwind-turbo/public/vercel.svg | 1 + .../next-tailwind-turbo/public/window.svg | 1 + .../next-tailwind-turbo/src/app/favicon.ico | Bin 0 -> 25931 bytes .../next-tailwind-turbo/src/app/global.css | 1 + .../next-tailwind-turbo/src/app/layout.tsx | 20 +++++++ .../next-tailwind-turbo/src/app/page.tsx | 37 +++++++++++++ benchmark/next-tailwind-turbo/tsconfig.json | 34 ++++++++++++ benchmark/next-tailwind/tsconfig.json | 5 +- benchmark/next-vanilla-extract/tsconfig.json | 5 +- packages/next-plugin/src/plugin.ts | 2 +- packages/next-plugin/src/preload.ts | 4 +- 42 files changed, 444 insertions(+), 26 deletions(-) create mode 100644 .changeset/tired-berries-wonder.md create mode 100644 benchmark/next-devup-ui-single-turbo/.gitignore create mode 100644 benchmark/next-devup-ui-single-turbo/README.md create mode 100644 benchmark/next-devup-ui-single-turbo/next.config.ts create mode 100644 benchmark/next-devup-ui-single-turbo/package.json create mode 100644 benchmark/next-devup-ui-single-turbo/public/file.svg create mode 100644 benchmark/next-devup-ui-single-turbo/public/globe.svg create mode 100644 benchmark/next-devup-ui-single-turbo/public/next.svg create mode 100644 benchmark/next-devup-ui-single-turbo/public/vercel.svg create mode 100644 benchmark/next-devup-ui-single-turbo/public/window.svg create mode 100644 benchmark/next-devup-ui-single-turbo/src/app/favicon.ico create mode 100644 benchmark/next-devup-ui-single-turbo/src/app/layout.tsx create mode 100644 benchmark/next-devup-ui-single-turbo/src/app/page.tsx create mode 100644 benchmark/next-devup-ui-single-turbo/tsconfig.json create mode 100644 benchmark/next-tailwind-turbo/.gitignore create mode 100644 benchmark/next-tailwind-turbo/README.md create mode 100644 benchmark/next-tailwind-turbo/next.config.mjs create mode 100644 benchmark/next-tailwind-turbo/package.json create mode 100644 benchmark/next-tailwind-turbo/postcss.config.mjs create mode 100644 benchmark/next-tailwind-turbo/public/file.svg create mode 100644 benchmark/next-tailwind-turbo/public/globe.svg create mode 100644 benchmark/next-tailwind-turbo/public/next.svg create mode 100644 benchmark/next-tailwind-turbo/public/vercel.svg create mode 100644 benchmark/next-tailwind-turbo/public/window.svg create mode 100644 benchmark/next-tailwind-turbo/src/app/favicon.ico create mode 100644 benchmark/next-tailwind-turbo/src/app/global.css create mode 100644 benchmark/next-tailwind-turbo/src/app/layout.tsx create mode 100644 benchmark/next-tailwind-turbo/src/app/page.tsx create mode 100644 benchmark/next-tailwind-turbo/tsconfig.json 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/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 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 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/plugin.ts b/packages/next-plugin/src/plugin.ts index 6d3a6bd7..8a87e2b2 100644 --- a/packages/next-plugin/src/plugin.ts +++ b/packages/next-plugin/src/plugin.ts @@ -60,7 +60,7 @@ export function DevupUI( if (!existsSync(gitignoreFile)) writeFileSync(gitignoreFile, '*') const theme = existsSync(devupFile) ? JSON.parse(readFileSync(devupFile, 'utf-8'))?.['theme'] - : undefined + : {} // disable turbo parallel const excludeRegex = new RegExp( `node_modules(?!.*(${['@devup-ui', ...include] diff --git a/packages/next-plugin/src/preload.ts b/packages/next-plugin/src/preload.ts index 4f0dae12..480fa9d4 100644 --- a/packages/next-plugin/src/preload.ts +++ b/packages/next-plugin/src/preload.ts @@ -9,7 +9,7 @@ export function preload( excludeRegex: RegExp, libPackage: string, singleCss: boolean, - theme: object, + theme: object | undefined, cssDir: string, ) { const projectRoot = findRoot(process.cwd()) @@ -18,7 +18,7 @@ export function preload( cwd: projectRoot, exclude: (filename) => excludeRegex.test(filename), }) - registerTheme(theme) + if (theme) registerTheme(theme) for (const file of collected) { const filePath = relative(process.cwd(), join(projectRoot, file)) const { cssFile, css } = codeExtract( From 5741737059865aad43b389504d1de3c4addfbaef Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 18:06:21 +0900 Subject: [PATCH 03/11] Implement test code --- .../next-plugin/src/__tests__/plugin.test.ts | 161 +++++++++++++----- packages/next-plugin/src/plugin.ts | 2 + packages/next-plugin/src/preload.ts | 4 +- .../src/__tests__/loader.test.ts | 19 ++- 4 files changed, 137 insertions(+), 49 deletions(-) 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/plugin.ts b/packages/next-plugin/src/plugin.ts index 8a87e2b2..0d678188 100644 --- a/packages/next-plugin/src/plugin.ts +++ b/packages/next-plugin/src/plugin.ts @@ -69,10 +69,12 @@ export function DevupUI( ) 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) } diff --git a/packages/next-plugin/src/preload.ts b/packages/next-plugin/src/preload.ts index 480fa9d4..4f0dae12 100644 --- a/packages/next-plugin/src/preload.ts +++ b/packages/next-plugin/src/preload.ts @@ -9,7 +9,7 @@ export function preload( excludeRegex: RegExp, libPackage: string, singleCss: boolean, - theme: object | undefined, + theme: object, cssDir: string, ) { const projectRoot = findRoot(process.cwd()) @@ -18,7 +18,7 @@ export function preload( cwd: projectRoot, exclude: (filename) => excludeRegex.test(filename), }) - if (theme) registerTheme(theme) + registerTheme(theme) for (const file of collected) { const filePath = relative(process.cwd(), join(projectRoot, file)) const { cssFile, css } = codeExtract( diff --git a/packages/webpack-plugin/src/__tests__/loader.test.ts b/packages/webpack-plugin/src/__tests__/loader.test.ts index 7e620a5e..b886e166 100644 --- a/packages/webpack-plugin/src/__tests__/loader.test.ts +++ b/packages/webpack-plugin/src/__tests__/loader.test.ts @@ -10,8 +10,6 @@ import { 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 +22,7 @@ vi.mock('node:path', async (original: any) => { beforeEach(() => { vi.resetAllMocks() + vi.resetModules() Date.now = vi.fn().mockReturnValue(0) }) @@ -33,6 +32,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 +102,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 +142,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 +164,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 +200,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 +225,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', From feff212f15dfadf2e9213fb2ec224ff7647fcd1b Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 18:48:39 +0900 Subject: [PATCH 04/11] Support turbopack --- .../src/__tests__/find-root.test.ts | 146 +++++++++++ .../next-plugin/src/__tests__/preload.test.ts | 238 ++++++++++++++++++ packages/next-plugin/src/find-root.ts | 4 +- packages/next-plugin/src/preload.ts | 2 +- .../src/__tests__/css-loader.test.ts | 5 +- .../src/__tests__/loader.test.ts | 50 ++++ 6 files changed, 441 insertions(+), 4 deletions(-) create mode 100644 packages/next-plugin/src/__tests__/find-root.test.ts create mode 100644 packages/next-plugin/src/__tests__/preload.test.ts 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..12e40ace --- /dev/null +++ b/packages/next-plugin/src/__tests__/find-root.test.ts @@ -0,0 +1,146 @@ +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 Windows-style paths', () => { + const mockDir = 'C:\\project\\src\\components' + const expectedRoot = 'C:\\project' + + vi.mocked(existsSync) + .mockReturnValueOnce(false) // C:\project\src\components\package.json + .mockReturnValueOnce(false) // C:\project\src\package.json + .mockReturnValueOnce(true) // C:\project\package.json + .mockReturnValueOnce(false) // C:\package.json + + const result = findRoot(mockDir) + + expect(result).toBe(expectedRoot) + }) + + it('should handle relative paths', () => { + const mockDir = './src/components' + const expectedRoot = '.' + + vi.mocked(existsSync) + .mockReturnValueOnce(false) // ./src/components/package.json + .mockReturnValueOnce(false) // ./src/package.json + .mockReturnValueOnce(true) // ./package.json + .mockReturnValueOnce(false) // ../package.json + + const result = findRoot(mockDir) + + expect(result).toBe(expectedRoot) + }) + + it('should stop at filesystem root', () => { + const mockDir = '/some/path' + + // 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__/preload.test.ts b/packages/next-plugin/src/__tests__/preload.test.ts new file mode 100644 index 00000000..9f0e139f --- /dev/null +++ b/packages/next-plugin/src/__tests__/preload.test.ts @@ -0,0 +1,238 @@ +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', + ) + }) +}) diff --git a/packages/next-plugin/src/find-root.ts b/packages/next-plugin/src/find-root.ts index 36011b03..a370ebaa 100644 --- a/packages/next-plugin/src/find-root.ts +++ b/packages/next-plugin/src/find-root.ts @@ -1,7 +1,7 @@ import { existsSync } from 'node:fs' import { dirname, join } from 'node:path' -export function findRoot(dir: string) { +export function findRoot(dir: string): string { let root = dir let prev = null const collectecd: string[] = [] @@ -13,7 +13,7 @@ export function findRoot(dir: string) { root = dirname(root) } if (collectecd.length > 0) { - return collectecd.pop() ?? process.cwd() + return collectecd.pop()! } return process.cwd() } diff --git a/packages/next-plugin/src/preload.ts b/packages/next-plugin/src/preload.ts index 4f0dae12..206eb1b8 100644 --- a/packages/next-plugin/src/preload.ts +++ b/packages/next-plugin/src/preload.ts @@ -16,7 +16,7 @@ export function preload( const collected = globSync(['**/*.tsx', '**/*.ts', '**/*.js', '**/*.mjs'], { cwd: projectRoot, - exclude: (filename) => excludeRegex.test(filename), + exclude: excludeRegex.test, }) registerTheme(theme) for (const file of collected) { 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 b886e166..6d3183f6 100644 --- a/packages/webpack-plugin/src/__tests__/loader.test.ts +++ b/packages/webpack-plugin/src/__tests__/loader.test.ts @@ -7,6 +7,9 @@ import { exportFileMap, exportSheet, getCss, + importClassMap, + importFileMap, + importSheet, registerTheme, } from '@devup-ui/wasm' @@ -260,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) + }) }) From fc2cea8f49edaf72083b40586122cd13ed499dc6 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 18:55:15 +0900 Subject: [PATCH 05/11] Apply react compiler --- apps/landing/next.config.ts | 5 ++--- apps/landing/package.json | 7 ++++--- apps/landing/src/app/(detail)/docs/RightIndex.tsx | 8 ++++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/landing/next.config.ts b/apps/landing/next.config.ts index 3a14b62b..32b53a9f 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,7 @@ export default withMDX( DevupUI({ pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], output: 'export', + reactCompiler: true, + cacheComponents: true, }), ) diff --git a/apps/landing/package.json b/apps/landing/package.json index aaec7a09..07455d64 100644 --- a/apps/landing/package.json +++ b/apps/landing/package.json @@ -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} ))} From 898d691d2f6098048fe5fd213626c07e252a6b75 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 19:04:09 +0900 Subject: [PATCH 06/11] Update lock --- pnpm-lock.yaml | 147 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 113 insertions(+), 34 deletions(-) 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' From c60294b8f9aa2dda20c3632a5564993fc838f4c1 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 19:13:43 +0900 Subject: [PATCH 07/11] Fix find root --- packages/next-plugin/src/find-root.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/next-plugin/src/find-root.ts b/packages/next-plugin/src/find-root.ts index a370ebaa..dfd3e621 100644 --- a/packages/next-plugin/src/find-root.ts +++ b/packages/next-plugin/src/find-root.ts @@ -4,16 +4,13 @@ import { dirname, join } from 'node:path' export function findRoot(dir: string): string { let root = dir let prev = null - const collectecd: string[] = [] + let result: string = process.cwd() while (prev === null || root !== prev) { - if (existsSync(join(root, 'package.json')) && !collectecd.includes(root)) { - collectecd.push(root) + if (existsSync(join(root, 'package.json'))) { + result = root } prev = root root = dirname(root) } - if (collectecd.length > 0) { - return collectecd.pop()! - } - return process.cwd() + return result } From 0eecb265a4ce1bf153cbfbae63a37e3c9e39c107 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 19:20:07 +0900 Subject: [PATCH 08/11] Fix find root --- .../src/__tests__/find-root.test.ts | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/packages/next-plugin/src/__tests__/find-root.test.ts b/packages/next-plugin/src/__tests__/find-root.test.ts index 12e40ace..abd468a8 100644 --- a/packages/next-plugin/src/__tests__/find-root.test.ts +++ b/packages/next-plugin/src/__tests__/find-root.test.ts @@ -81,30 +81,15 @@ describe('findRoot', () => { expect(result).toBe(expectedRoot) }) - it('should handle Windows-style paths', () => { - const mockDir = 'C:\\project\\src\\components' - const expectedRoot = 'C:\\project' + it('should handle paths', () => { + const mockDir = join('a', 'b', 'c', 'd') + const expectedRoot = join('a', 'b') vi.mocked(existsSync) - .mockReturnValueOnce(false) // C:\project\src\components\package.json - .mockReturnValueOnce(false) // C:\project\src\package.json - .mockReturnValueOnce(true) // C:\project\package.json - .mockReturnValueOnce(false) // C:\package.json - - const result = findRoot(mockDir) - - expect(result).toBe(expectedRoot) - }) - - it('should handle relative paths', () => { - const mockDir = './src/components' - const expectedRoot = '.' - - vi.mocked(existsSync) - .mockReturnValueOnce(false) // ./src/components/package.json - .mockReturnValueOnce(false) // ./src/package.json - .mockReturnValueOnce(true) // ./package.json - .mockReturnValueOnce(false) // ../package.json + .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) @@ -112,7 +97,7 @@ describe('findRoot', () => { }) it('should stop at filesystem root', () => { - const mockDir = '/some/path' + const mockDir = join('a', 'b', 'c') // Mock existsSync to return false for all calls, simulating no package.json found vi.mocked(existsSync).mockReturnValue(false) From d2c6b4afa976f417bc8abc365a3738a9102038b1 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 19:43:57 +0900 Subject: [PATCH 09/11] Fix next --- apps/landing/next.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/landing/next.config.ts b/apps/landing/next.config.ts index 32b53a9f..4476e8f9 100644 --- a/apps/landing/next.config.ts +++ b/apps/landing/next.config.ts @@ -10,6 +10,5 @@ export default withMDX( pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], output: 'export', reactCompiler: true, - cacheComponents: true, }), ) From e8b81dc43dfcd9516b156aaeed405aba9a28d3eb Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 19:54:31 +0900 Subject: [PATCH 10/11] Fix test code --- .../next-plugin/src/__tests__/preload.test.ts | 21 +++++++++++++++++++ packages/next-plugin/src/preload.ts | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/next-plugin/src/__tests__/preload.test.ts b/packages/next-plugin/src/__tests__/preload.test.ts index 9f0e139f..52248489 100644 --- a/packages/next-plugin/src/__tests__/preload.test.ts +++ b/packages/next-plugin/src/__tests__/preload.test.ts @@ -235,4 +235,25 @@ describe('preload', () => { '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/preload.ts b/packages/next-plugin/src/preload.ts index 206eb1b8..8fb52fc5 100644 --- a/packages/next-plugin/src/preload.ts +++ b/packages/next-plugin/src/preload.ts @@ -16,7 +16,7 @@ export function preload( const collected = globSync(['**/*.tsx', '**/*.ts', '**/*.js', '**/*.mjs'], { cwd: projectRoot, - exclude: excludeRegex.test, + exclude: (fileName) => excludeRegex.test(fileName), }) registerTheme(theme) for (const file of collected) { From 3c8e1e8c3900b62d6faa5f268897f0f453468396 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Tue, 28 Oct 2025 20:14:12 +0900 Subject: [PATCH 11/11] Fix layout --- apps/landing/src/app/layout.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/landing/src/app/layout.tsx b/apps/landing/src/app/layout.tsx index f11af852..3c2a13a1 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', + }, code: { fontFamily: 'D2Coding', fontSize: ['13px', '15px'], @@ -35,9 +38,6 @@ globalCss({ lineHeight: '1.5', letterSpacing: '-0.03em', }, - pre: { - borderRadius: '10px', - }, }) export default function RootLayout({