From 8616d44cad222bab9206910b9ed78f3be3b5ecbc Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 2 Jul 2024 09:12:43 +0900 Subject: [PATCH] refactor: move code --- packages/react-server-next/src/vite/index.ts | 34 +--------------- packages/react-server-next/src/vite/meta.ts | 32 +++++++++++++++ packages/react-server/src/plugin/index.ts | 41 ++++---------------- packages/react-server/src/plugin/utils.tsx | 30 ++++++++++++++ 4 files changed, 71 insertions(+), 66 deletions(-) create mode 100644 packages/react-server-next/src/vite/meta.ts diff --git a/packages/react-server-next/src/vite/index.ts b/packages/react-server-next/src/vite/index.ts index e07075624..fbee3bb0f 100644 --- a/packages/react-server-next/src/vite/index.ts +++ b/packages/react-server-next/src/vite/index.ts @@ -1,4 +1,3 @@ -import { existsSync, readFileSync } from "node:fs"; import path from "node:path"; import { vitePluginReactServer } from "@hiogawa/react-server/plugin"; import { @@ -6,9 +5,10 @@ import { vitePluginSsrMiddleware, } from "@hiogawa/vite-plugin-ssr-middleware"; import react from "@vitejs/plugin-react"; -import type { Plugin, PluginOption } from "vite"; +import type { PluginOption } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; import { type AdapterType, adapterPlugin } from "./adapters"; +import { appFaviconPlugin } from "./meta"; export default function vitePluginReactServerNext(options?: { plugins?: PluginOption[]; @@ -57,33 +57,3 @@ export default function vitePluginReactServerNext(options?: { }, ]; } - -/** @todo https://nextjs.org/docs/app/api-reference/file-conventions/metadata/app-icons */ -function appFaviconPlugin(): Plugin { - // not sure what exactly Next.js does. - // for now, let's do quick workaround for app/favicon.ico - return { - name: appFaviconPlugin.name, - apply: (_config, env) => env.command === "serve" || !env.isSsrBuild, - configureServer(server) { - if (existsSync("app/favicon.ico")) { - server.middlewares.use((req, _res, next) => { - const url = new URL(req.url || "", "https://tmp.local"); - if (url.pathname === "/favicon.ico") { - req.url = "/app/favicon.ico"; - } - next(); - }); - } - }, - generateBundle() { - if (existsSync("app/favicon.ico")) { - this.emitFile({ - type: "asset", - fileName: "favicon.ico", - source: readFileSync("app/favicon.ico"), - }); - } - }, - }; -} diff --git a/packages/react-server-next/src/vite/meta.ts b/packages/react-server-next/src/vite/meta.ts new file mode 100644 index 000000000..aff7acf33 --- /dev/null +++ b/packages/react-server-next/src/vite/meta.ts @@ -0,0 +1,32 @@ +import { existsSync, readFileSync } from "fs"; +import type { Plugin } from "vite"; + +/** @todo https://nextjs.org/docs/app/api-reference/file-conventions/metadata/app-icons */ +export function appFaviconPlugin(): Plugin { + // not sure what exactly Next.js does. + // for now, let's do quick workaround for app/favicon.ico + return { + name: appFaviconPlugin.name, + apply: (_config, env) => env.command === "serve" || !env.isSsrBuild, + configureServer(server) { + if (existsSync("app/favicon.ico")) { + server.middlewares.use((req, _res, next) => { + const url = new URL(req.url || "", "https://tmp.local"); + if (url.pathname === "/favicon.ico") { + req.url = "/app/favicon.ico"; + } + next(); + }); + } + }, + generateBundle() { + if (existsSync("app/favicon.ico")) { + this.emitFile({ + type: "asset", + fileName: "favicon.ico", + source: readFileSync("app/favicon.ico"), + }); + } + }, + }; +} diff --git a/packages/react-server/src/plugin/index.ts b/packages/react-server/src/plugin/index.ts index a258fa35a..e8c731e35 100644 --- a/packages/react-server/src/plugin/index.ts +++ b/packages/react-server/src/plugin/index.ts @@ -46,6 +46,7 @@ import { ENTRY_CLIENT_WRAPPER, ENTRY_REACT_SERVER_WRAPPER, createVirtualPlugin, + validateImportPlugin, vitePluginSilenceDirectiveBuildWarning, } from "./utils"; @@ -192,7 +193,9 @@ export function vitePluginReactServer(options?: { ), validateImportPlugin({ - "client-only": `'client-only' is included in server build`, + "client-only": + manager.buildType === "scan" || + `'client-only' is included in server build`, "server-only": true, }), @@ -412,7 +415,9 @@ export function vitePluginReactServer(options?: { : []), validateImportPlugin({ "client-only": true, - "server-only": `'server-only' is included in client build`, + "server-only": + manager.buildType === "scan" || + `'server-only' is included in client build`, }), createVirtualPlugin(ENTRY_CLIENT_WRAPPER.slice("virtual:".length), () => { // dev @@ -439,35 +444,3 @@ export function vitePluginReactServer(options?: { }), ]; } - -// https://github.com/vercel/next.js/blob/90f564d376153fe0b5808eab7b83665ee5e08aaf/packages/next/src/build/webpack-config.ts#L1249-L1280 -// https://github.com/pcattori/vite-env-only/blob/68a0cc8546b9a37c181c0b0a025eb9b62dbedd09/src/deny-imports.ts -// https://github.com/sveltejs/kit/blob/84298477a014ec471839adf7a4448d91bc7949e4/packages/kit/src/exports/vite/index.js#L513 -function validateImportPlugin(entries: Record): Plugin { - return { - name: validateImportPlugin.name, - enforce: "pre", - resolveId(source, importer, options) { - const entry = entries[source]; - if (entry) { - // skip validation during optimizeDeps scan since for now - // we want to allow going through server/client boundary loosely - if ( - entry === true || - manager.buildType === "scan" || - ("scan" in options && options.scan) - ) { - return "\0virtual:validate-import"; - } - throw new Error(entry + ` (importer: ${importer ?? "unknown"})`); - } - return; - }, - load(id, _options) { - if (id === "\0virtual:validate-import") { - return "export {}"; - } - return; - }, - }; -} diff --git a/packages/react-server/src/plugin/utils.tsx b/packages/react-server/src/plugin/utils.tsx index 2a228eb06..676200156 100644 --- a/packages/react-server/src/plugin/utils.tsx +++ b/packages/react-server/src/plugin/utils.tsx @@ -86,3 +86,33 @@ export function vitePluginSilenceDirectiveBuildWarning(): Plugin { }, }; } + +// https://github.com/vercel/next.js/blob/90f564d376153fe0b5808eab7b83665ee5e08aaf/packages/next/src/build/webpack-config.ts#L1249-L1280 +// https://github.com/pcattori/vite-env-only/blob/68a0cc8546b9a37c181c0b0a025eb9b62dbedd09/src/deny-imports.ts +// https://github.com/sveltejs/kit/blob/84298477a014ec471839adf7a4448d91bc7949e4/packages/kit/src/exports/vite/index.js#L513 +export function validateImportPlugin( + entries: Record, +): Plugin { + return { + name: validateImportPlugin.name, + enforce: "pre", + resolveId(source, importer, options) { + const entry = entries[source]; + if (entry) { + // skip validation during optimizeDeps scan since for now + // we want to allow going through server/client boundary loosely + if (entry === true || ("scan" in options && options.scan)) { + return "\0virtual:validate-import"; + } + throw new Error(entry + ` (importer: ${importer ?? "unknown"})`); + } + return; + }, + load(id, _options) { + if (id === "\0virtual:validate-import") { + return "export {}"; + } + return; + }, + }; +}