From 4bbb3f44fb0a7e2a97d4eef76bf165d247a1c96d Mon Sep 17 00:00:00 2001 From: daishi Date: Sun, 29 Dec 2024 22:09:23 +0900 Subject: [PATCH] 05_compiler and fixes --- examples/05_compiler/.gitignore | 7 +++ examples/05_compiler/package.json | 26 +++++++++ examples/05_compiler/postcss.config.js | 7 +++ .../05_compiler/public/images/favicon.png | Bin 0 -> 5713 bytes .../05_compiler/src/components/counter.tsx | 26 +++++++++ .../05_compiler/src/components/footer.tsx | 18 ++++++ .../05_compiler/src/components/header.tsx | 11 ++++ examples/05_compiler/src/pages/_layout.tsx | 39 +++++++++++++ examples/05_compiler/src/pages/about.tsx | 32 +++++++++++ examples/05_compiler/src/pages/index.tsx | 35 ++++++++++++ examples/05_compiler/src/styles.css | 4 ++ examples/05_compiler/tailwind.config.js | 4 ++ examples/05_compiler/tsconfig.json | 15 +++++ examples/05_compiler/waku.config.ts | 21 +++++++ packages/waku/src/lib/builder/build.ts | 47 ++++++---------- .../src/lib/middleware/dev-server-impl.ts | 22 +++----- packages/waku/src/lib/utils/vite-config.ts | 41 ++++++++++++++ pnpm-lock.yaml | 52 ++++++++++++++++-- 18 files changed, 359 insertions(+), 48 deletions(-) create mode 100644 examples/05_compiler/.gitignore create mode 100644 examples/05_compiler/package.json create mode 100644 examples/05_compiler/postcss.config.js create mode 100644 examples/05_compiler/public/images/favicon.png create mode 100644 examples/05_compiler/src/components/counter.tsx create mode 100644 examples/05_compiler/src/components/footer.tsx create mode 100644 examples/05_compiler/src/components/header.tsx create mode 100644 examples/05_compiler/src/pages/_layout.tsx create mode 100644 examples/05_compiler/src/pages/about.tsx create mode 100644 examples/05_compiler/src/pages/index.tsx create mode 100644 examples/05_compiler/src/styles.css create mode 100644 examples/05_compiler/tailwind.config.js create mode 100644 examples/05_compiler/tsconfig.json create mode 100644 examples/05_compiler/waku.config.ts create mode 100644 packages/waku/src/lib/utils/vite-config.ts diff --git a/examples/05_compiler/.gitignore b/examples/05_compiler/.gitignore new file mode 100644 index 000000000..ad583432d --- /dev/null +++ b/examples/05_compiler/.gitignore @@ -0,0 +1,7 @@ +node_modules +dist +.env* +*.tsbuildinfo +.cache +.DS_Store +*.pem diff --git a/examples/05_compiler/package.json b/examples/05_compiler/package.json new file mode 100644 index 000000000..4cdb38682 --- /dev/null +++ b/examples/05_compiler/package.json @@ -0,0 +1,26 @@ +{ + "name": "05_compiler", + "version": "0.1.0", + "type": "module", + "private": true, + "scripts": { + "dev": "waku dev", + "build": "waku build", + "start": "waku start" + }, + "dependencies": { + "react": "19.0.0", + "react-dom": "19.0.0", + "react-server-dom-webpack": "19.0.0", + "waku": "0.21.11" + }, + "devDependencies": { + "@types/react": "19.0.2", + "@types/react-dom": "19.0.2", + "@vitejs/plugin-react": "4.3.4", + "autoprefixer": "10.4.20", + "babel-plugin-react-compiler": "19.0.0-beta-b2e8e9c-20241220", + "tailwindcss": "3.4.17", + "typescript": "5.7.2" + } +} diff --git a/examples/05_compiler/postcss.config.js b/examples/05_compiler/postcss.config.js new file mode 100644 index 000000000..709af5d83 --- /dev/null +++ b/examples/05_compiler/postcss.config.js @@ -0,0 +1,7 @@ +/** @type {import('postcss-load-config').Config} */ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/examples/05_compiler/public/images/favicon.png b/examples/05_compiler/public/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd90d79081c0c40519bb3c583f5b43357b3fcd3b GIT binary patch literal 5713 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 DW2Q3= literal 0 HcmV?d00001 diff --git a/examples/05_compiler/src/components/counter.tsx b/examples/05_compiler/src/components/counter.tsx new file mode 100644 index 000000000..b541d088e --- /dev/null +++ b/examples/05_compiler/src/components/counter.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { useState } from 'react'; + +const Hello = () => { + return

Hello (now={Date.now()})

; +}; + +export const Counter = () => { + const [count, setCount] = useState(0); + + const handleIncrement = () => setCount((c) => c + 1); + + return ( +
+
Count: {count}
+ + +
+ ); +}; diff --git a/examples/05_compiler/src/components/footer.tsx b/examples/05_compiler/src/components/footer.tsx new file mode 100644 index 000000000..8cfd9c897 --- /dev/null +++ b/examples/05_compiler/src/components/footer.tsx @@ -0,0 +1,18 @@ +export const Footer = () => { + return ( + + ); +}; diff --git a/examples/05_compiler/src/components/header.tsx b/examples/05_compiler/src/components/header.tsx new file mode 100644 index 000000000..1b03ba54d --- /dev/null +++ b/examples/05_compiler/src/components/header.tsx @@ -0,0 +1,11 @@ +import { Link } from 'waku'; + +export const Header = () => { + return ( +
+

+ Waku starter +

+
+ ); +}; diff --git a/examples/05_compiler/src/pages/_layout.tsx b/examples/05_compiler/src/pages/_layout.tsx new file mode 100644 index 000000000..6d227c9f6 --- /dev/null +++ b/examples/05_compiler/src/pages/_layout.tsx @@ -0,0 +1,39 @@ +import '../styles.css'; + +import type { ReactNode } from 'react'; + +import { Header } from '../components/header'; +import { Footer } from '../components/footer'; + +type RootLayoutProps = { children: ReactNode }; + +export default async function RootLayout({ children }: RootLayoutProps) { + const data = await getData(); + + return ( +
+ + +
+
+ {children} +
+
+
+ ); +} + +const getData = async () => { + const data = { + description: 'An internet website!', + icon: '/images/favicon.png', + }; + + return data; +}; + +export const getConfig = async () => { + return { + render: 'static', + } as const; +}; diff --git a/examples/05_compiler/src/pages/about.tsx b/examples/05_compiler/src/pages/about.tsx new file mode 100644 index 000000000..15d4c90e1 --- /dev/null +++ b/examples/05_compiler/src/pages/about.tsx @@ -0,0 +1,32 @@ +import { Link } from 'waku'; + +export default async function AboutPage() { + const data = await getData(); + + return ( +
+ {data.title} +

{data.headline}

+

{data.body}

+ + Return home + +
+ ); +} + +const getData = async () => { + const data = { + title: 'About', + headline: 'About Waku', + body: 'The minimal React framework', + }; + + return data; +}; + +export const getConfig = async () => { + return { + render: 'static', + } as const; +}; diff --git a/examples/05_compiler/src/pages/index.tsx b/examples/05_compiler/src/pages/index.tsx new file mode 100644 index 000000000..889b9d5f4 --- /dev/null +++ b/examples/05_compiler/src/pages/index.tsx @@ -0,0 +1,35 @@ +import { Link } from 'waku'; + +import { Counter } from '../components/counter'; + +export default async function HomePage() { + const data = await getData(); + + return ( +
+ {data.title} +

{data.headline}

+

{data.body}

+ + + About page + +
+ ); +} + +const getData = async () => { + const data = { + title: 'Waku', + headline: 'Waku', + body: 'Hello world!', + }; + + return data; +}; + +export const getConfig = async () => { + return { + render: 'static', + } as const; +}; diff --git a/examples/05_compiler/src/styles.css b/examples/05_compiler/src/styles.css new file mode 100644 index 000000000..4cb5445ab --- /dev/null +++ b/examples/05_compiler/src/styles.css @@ -0,0 +1,4 @@ +@import url('https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,400;0,700;1,400;1,700&display=swap'); +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/examples/05_compiler/tailwind.config.js b/examples/05_compiler/tailwind.config.js new file mode 100644 index 000000000..df5c92956 --- /dev/null +++ b/examples/05_compiler/tailwind.config.js @@ -0,0 +1,4 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{js,jsx,ts,tsx}'], +}; diff --git a/examples/05_compiler/tsconfig.json b/examples/05_compiler/tsconfig.json new file mode 100644 index 000000000..84d0d542f --- /dev/null +++ b/examples/05_compiler/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "strict": true, + "target": "esnext", + "downlevelIteration": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "skipLibCheck": true, + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + "types": ["react/experimental"], + "jsx": "react-jsx" + } +} diff --git a/examples/05_compiler/waku.config.ts b/examples/05_compiler/waku.config.ts new file mode 100644 index 000000000..18efa8c21 --- /dev/null +++ b/examples/05_compiler/waku.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from 'waku/config'; +import react from '@vitejs/plugin-react'; + +const ReactCompilerConfig = {}; + +const getConfig = () => ({ + plugins: [ + react({ + babel: { + plugins: [['babel-plugin-react-compiler', ReactCompilerConfig]], + }, + }), + ], +}); + +export default defineConfig({ + unstable_viteConfigs: { + 'dev-main': getConfig, + 'build-client': getConfig, + }, +}); diff --git a/packages/waku/src/lib/builder/build.ts b/packages/waku/src/lib/builder/build.ts index d81e88f32..232224574 100644 --- a/packages/waku/src/lib/builder/build.ts +++ b/packages/waku/src/lib/builder/build.ts @@ -1,11 +1,7 @@ import { Readable } from 'node:stream'; import { pipeline } from 'node:stream/promises'; -import { - build as buildVite, - resolveConfig as resolveViteConfig, - mergeConfig as mergeViteConfig, -} from 'vite'; +import { build as buildVite, resolveConfig as resolveViteConfig } from 'vite'; import viteReact from '@vitejs/plugin-react'; import type { LoggingFunction, RollupLog } from 'rollup'; import type { ReactNode } from 'react'; @@ -24,6 +20,7 @@ import { fileURLToFilePath, joinPath, } from '../utils/path.js'; +import { extendViteConfig } from '../utils/vite-config.js'; import { appendFile, createWriteStream, @@ -124,7 +121,7 @@ const analyzeEntries = async (rootDir: string, config: ResolvedConfig) => { } } await buildVite( - mergeViteConfig( + extendViteConfig( { mode: 'production', plugins: [ @@ -155,10 +152,8 @@ const analyzeEntries = async (rootDir: string, config: ResolvedConfig) => { }, }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['build-analyze']?.(), - }, + config, + 'build-analyze', ), ); const clientEntryFiles = Object.fromEntries( @@ -168,7 +163,7 @@ const analyzeEntries = async (rootDir: string, config: ResolvedConfig) => { ]), ); await buildVite( - mergeViteConfig( + extendViteConfig( { mode: 'production', plugins: [ @@ -190,10 +185,8 @@ const analyzeEntries = async (rootDir: string, config: ResolvedConfig) => { }, }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['build-analyze']?.(), - }, + config, + 'build-analyze', ), ); const serverEntryFiles = Object.fromEntries( @@ -221,7 +214,7 @@ const buildServerBundle = async ( partial: boolean, ) => { const serverBuildOutput = await buildVite( - mergeViteConfig( + extendViteConfig( { mode: 'production', plugins: [ @@ -302,10 +295,8 @@ const buildServerBundle = async ( }, }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['build-server']?.(), - }, + config, + 'build-server', ), ); if (!('output' in serverBuildOutput)) { @@ -328,7 +319,7 @@ const buildSsrBundle = async ( type === 'asset' && fileName.endsWith('.css') ? [fileName] : [], ); await buildVite( - mergeViteConfig( + extendViteConfig( { mode: 'production', base: config.basePath, @@ -382,10 +373,8 @@ const buildSsrBundle = async ( }, }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['build-ssr']?.(), - }, + config, + 'build-ssr', ), ); }; @@ -405,7 +394,7 @@ const buildClientBundle = async ( ); const cssAssets = nonJsAssets.filter((asset) => asset.endsWith('.css')); const clientBuildOutput = await buildVite( - mergeViteConfig( + extendViteConfig( { mode: 'production', base: config.basePath, @@ -442,10 +431,8 @@ const buildClientBundle = async ( }, }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['build-client']?.(), - }, + config, + 'build-client', ), ); if (!('output' in clientBuildOutput)) { diff --git a/packages/waku/src/lib/middleware/dev-server-impl.ts b/packages/waku/src/lib/middleware/dev-server-impl.ts index e317da962..37cfcca02 100644 --- a/packages/waku/src/lib/middleware/dev-server-impl.ts +++ b/packages/waku/src/lib/middleware/dev-server-impl.ts @@ -1,10 +1,7 @@ import { Readable, Writable } from 'node:stream'; import { Server } from 'node:http'; import { AsyncLocalStorage } from 'node:async_hooks'; -import { - createServer as createViteServer, - mergeConfig as mergeViteConfig, -} from 'vite'; +import { createServer as createViteServer } from 'vite'; import viteReact from '@vitejs/plugin-react'; import type { EntriesDev } from '../types.js'; @@ -15,6 +12,7 @@ import { fileURLToFilePath, filePathToFileURL, } from '../utils/path.js'; +import { extendViteConfig } from '../utils/vite-config.js'; import { patchReactRefresh } from '../plugins/patch-react-refresh.js'; import { nonjsResolvePlugin } from '../plugins/vite-plugin-nonjs-resolve.js'; import { devCommonJsPlugin } from '../plugins/vite-plugin-dev-commonjs.js'; @@ -87,7 +85,7 @@ const createMainViteServer = ( ) => { const vitePromise = configPromise.then(async (config) => { const vite = await createViteServer( - mergeViteConfig( + extendViteConfig( { // Since we have multiple instances of vite, different ones might overwrite the others' cache. cacheDir: 'node_modules/.vite/waku-dev-server-main', @@ -133,10 +131,8 @@ const createMainViteServer = ( appType: 'mpa', server: { middlewareMode: true }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['dev-main']?.(), - }, + config, + 'dev-main', ), ); registerHotUpdateCallback((payload) => hotUpdate(vite, payload)); @@ -232,7 +228,7 @@ const createRscViteServer = ( const vitePromise = configPromise.then(async (config) => { const vite = await createViteServer( - mergeViteConfig( + extendViteConfig( { // Since we have multiple instances of vite, different ones might overwrite the others' cache. cacheDir: 'node_modules/.vite/waku-dev-server-rsc', @@ -278,10 +274,8 @@ const createRscViteServer = ( appType: 'custom', server: { middlewareMode: true, hmr: { server: dummyServer } }, }, - { - ...config.unstable_viteConfigs?.['common']?.(), - ...config.unstable_viteConfigs?.['dev-rsc']?.(), - }, + config, + 'dev-rsc', ), ); return vite; diff --git a/packages/waku/src/lib/utils/vite-config.ts b/packages/waku/src/lib/utils/vite-config.ts new file mode 100644 index 000000000..cf060b02a --- /dev/null +++ b/packages/waku/src/lib/utils/vite-config.ts @@ -0,0 +1,41 @@ +import { mergeConfig } from 'vite'; +import type { UserConfig } from 'vite'; + +import type { ResolvedConfig } from '../config.js'; + +const areProbablySamePlugins = (a: unknown, b: unknown): boolean => { + if (typeof a !== 'object' || a === null) { + return false; + } + if (typeof b !== 'object' || b === null) { + return false; + } + if (Array.isArray(a) && Array.isArray(b)) { + return ( + a.length === b.length && + a.every((item, index) => areProbablySamePlugins(item, b[index])) + ); + } + return 'name' in a && 'name' in b && a.name === b.name; +}; + +export const extendViteConfig = ( + viteConfig: UserConfig, + resolvedConfig: ResolvedConfig, + key: Exclude< + keyof NonNullable, + 'common' + >, +) => { + const mergedConfig = mergeConfig(viteConfig, { + // shallow merge + ...resolvedConfig.unstable_viteConfigs?.['common']?.(), + ...resolvedConfig.unstable_viteConfigs?.[key]?.(), + }); + // remove duplicate plugins (latter wins) + mergedConfig.plugins = (mergedConfig as UserConfig).plugins?.filter( + (plugin, index, arr) => + arr.findLastIndex((p) => areProbablySamePlugins(p, plugin)) === index, + ); + return mergedConfig; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ace7c794..7f602af14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -602,6 +602,43 @@ importers: specifier: 5.7.2 version: 5.7.2 + examples/05_compiler: + dependencies: + react: + specifier: 19.0.0 + version: 19.0.0 + react-dom: + specifier: 19.0.0 + version: 19.0.0(react@19.0.0) + react-server-dom-webpack: + specifier: 19.0.0 + version: 19.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(webpack@5.97.1) + waku: + specifier: 0.21.11 + version: link:../../packages/waku + devDependencies: + '@types/react': + specifier: 19.0.2 + version: 19.0.2 + '@types/react-dom': + specifier: 19.0.2 + version: 19.0.2(@types/react@19.0.2) + '@vitejs/plugin-react': + specifier: 4.3.4 + version: 4.3.4(vite@6.0.6(@types/node@22.10.2)(jiti@2.4.2)(terser@5.37.0)(yaml@2.6.1)) + autoprefixer: + specifier: 10.4.20 + version: 10.4.20(postcss@8.4.49) + babel-plugin-react-compiler: + specifier: 19.0.0-beta-b2e8e9c-20241220 + version: 19.0.0-beta-b2e8e9c-20241220 + tailwindcss: + specifier: 3.4.17 + version: 3.4.17 + typescript: + specifier: 5.7.2 + version: 5.7.2 + examples/11_fs-router: dependencies: react: @@ -1117,7 +1154,7 @@ importers: version: 7.4.3 tsup: specifier: ^8.3.5 - version: 8.3.5(@swc/core@1.10.3(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.6.1) + version: 8.3.5(@swc/core@1.10.3)(jiti@2.4.2)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.6.1) update-check: specifier: ^1.5.4 version: 1.5.4 @@ -2922,6 +2959,9 @@ packages: b4a@1.6.7: resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==} + babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220: + resolution: {integrity: sha512-aigv5VrOTLUOCeq/t1fuZvvs9Ze1GUfxnleWfiGoZcR0Lo34w3JcGgNiJBoxqlWfFiVnZhzaja9Aa1p6PWAtPg==} + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} @@ -7363,6 +7403,10 @@ snapshots: b4a@1.6.7: {} + babel-plugin-react-compiler@19.0.0-beta-b2e8e9c-20241220: + dependencies: + '@babel/types': 7.26.3 + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -7973,7 +8017,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.2(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.18.2(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)): dependencies: debug: 3.2.7 optionalDependencies: @@ -7995,7 +8039,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.17.0(jiti@2.4.2) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.2(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.17.0(jiti@2.4.2)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.18.2(eslint@9.17.0(jiti@2.4.2))(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.17.0(jiti@2.4.2)))(eslint@9.17.0(jiti@2.4.2)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -10240,7 +10284,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.3.5(@swc/core@1.10.3(@swc/helpers@0.5.15))(jiti@2.4.2)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.6.1): + tsup@8.3.5(@swc/core@1.10.3)(jiti@2.4.2)(postcss@8.4.49)(typescript@5.7.2)(yaml@2.6.1): dependencies: bundle-require: 5.1.0(esbuild@0.24.2) cac: 6.7.14