From df130b86dcef8987e311e9134a11fad147155587 Mon Sep 17 00:00:00 2001 From: lazarv Date: Wed, 18 Sep 2024 14:23:17 +0200 Subject: [PATCH] feat: optimize deps enhancements --- examples/mantine/react-server.config.mjs | 9 -- examples/mantine/src/components/AppLayout.tsx | 2 - examples/mantine/src/components/AppLogo.tsx | 4 +- examples/mantine/src/components/MyDates.tsx | 33 +++++-- examples/todo/react-server.config.json | 5 - packages/react-server/lib/build/server.mjs | 91 +++++++++++++------ .../react-server/lib/dev/create-server.mjs | 1 + packages/react-server/lib/handlers/error.mjs | 17 +++- .../lib/plugins/optimize-deps.mjs | 43 ++++++++- packages/react-server/lib/utils/module.mjs | 39 +++++--- 10 files changed, 171 insertions(+), 73 deletions(-) delete mode 100644 examples/todo/react-server.config.json diff --git a/examples/mantine/react-server.config.mjs b/examples/mantine/react-server.config.mjs index d037ad5..5fbc5d5 100644 --- a/examples/mantine/react-server.config.mjs +++ b/examples/mantine/react-server.config.mjs @@ -4,15 +4,6 @@ export default { optimizeDeps: { exclude: ["@mantine/core"], }, - resolve: { - alias: [ - { - find: "highlight.js", - replacement: "highlight.js", - }, - ], - external: ["dayjs"], - }, build: { chunkSizeWarningLimit: 1000, rollupOptions: { diff --git a/examples/mantine/src/components/AppLayout.tsx b/examples/mantine/src/components/AppLayout.tsx index 64dbb37..9e9ccf3 100644 --- a/examples/mantine/src/components/AppLayout.tsx +++ b/examples/mantine/src/components/AppLayout.tsx @@ -40,11 +40,9 @@ export function AppLayout({ - - {children} ); diff --git a/examples/mantine/src/components/AppLogo.tsx b/examples/mantine/src/components/AppLogo.tsx index b8f9773..e66dd6a 100644 --- a/examples/mantine/src/components/AppLogo.tsx +++ b/examples/mantine/src/components/AppLogo.tsx @@ -1,4 +1,6 @@ -const SVGComponent = (props) => ( +import type { SVGProps } from "react"; + +const SVGComponent = (props: SVGProps) => ( (null); + const [locale, setLocale] = useState("en"); + return ( - + <> + Error + + diff --git a/packages/react-server/lib/plugins/optimize-deps.mjs b/packages/react-server/lib/plugins/optimize-deps.mjs index 2bf2f07..d78834c 100644 --- a/packages/react-server/lib/plugins/optimize-deps.mjs +++ b/packages/react-server/lib/plugins/optimize-deps.mjs @@ -1,6 +1,13 @@ +import { readFile } from "node:fs/promises"; + import { moduleAliases } from "../loader/module-alias.mjs"; import { applyAlias } from "../loader/utils.mjs"; -import { bareImportRE, isModule, tryStat } from "../utils/module.mjs"; +import { + bareImportRE, + isModule, + isRootModule, + tryStat, +} from "../utils/module.mjs"; const alias = moduleAliases(); @@ -17,6 +24,34 @@ export default function optimizeDeps() { ); const path = resolved?.id?.split("?")[0]; if ( + (this.environment.name === "rsc" || + this.environment.name === "ssr") && + /\.[cm]?js$/.test(path) && + (bareImportRE.test(specifier) || + (specifier[0] !== "." && specifier[0] !== "/")) && + applyAlias(alias, specifier) === specifier && + !isModule(path) && + tryStat(path)?.isFile() + ) { + try { + const content = await readFile(path, "utf-8"); + const ast = this.parse(content); + const hasImportExport = ast.body.some( + (node) => + node.type === "ImportDeclaration" || + node.type === "ExportNamedDeclaration" || + node.type === "ExportDefaultDeclaration" || + node.type === "ExportAllDeclaration" + ); + if (hasImportExport) { + return resolved; + } + } catch (e) { + console.log("error", path, e); + // ignore + } + return { externalize: specifier }; + } else if ( this.environment.name === "client" && !this.environment.depsOptimizer?.isOptimizedDepFile(specifier) && path && @@ -24,7 +59,7 @@ export default function optimizeDeps() { (bareImportRE.test(specifier) || (specifier[0] !== "." && specifier[0] !== "/")) && applyAlias(alias, specifier) === specifier && - !isModule(path) && + !isRootModule(path) && tryStat(path)?.isFile() ) { try { @@ -33,6 +68,9 @@ export default function optimizeDeps() { specifier, path ); + this.environment.depsOptimizer.metadata.discovered[specifier] = { + ...optimizedInfo, + }; return { id: this.environment.depsOptimizer.getOptimizedDepId( optimizedInfo @@ -45,7 +83,6 @@ export default function optimizeDeps() { return resolved || { externalize: specifier }; } catch { return { externalize: specifier }; - // ignore } }, }; diff --git a/packages/react-server/lib/utils/module.mjs b/packages/react-server/lib/utils/module.mjs index 71495b8..4b3867b 100644 --- a/packages/react-server/lib/utils/module.mjs +++ b/packages/react-server/lib/utils/module.mjs @@ -1,5 +1,5 @@ import { readdirSync, readFileSync, statSync } from "node:fs"; -import { dirname, join } from "node:path"; +import { dirname, join, relative } from "node:path"; import { fileURLToPath } from "node:url"; import * as sys from "../sys.mjs"; @@ -21,14 +21,18 @@ export function loadPackageData(pkgPath) { } const packagePathCache = new Map(); -export function findPackageRoot(basedir) { +export function findPackageRoot(basedir, isRoot = false) { const directoryStack = [basedir]; while (basedir) { if (packagePathCache.has(basedir)) { return packagePathCache.get(basedir); } const pkgPath = join(basedir, "package.json"); - if (tryStat(pkgPath)) { + const nextBasedir = dirname(basedir); + if ( + tryStat(pkgPath) && + (!isRoot || (isRoot && nextBasedir.endsWith("node_modules"))) + ) { try { const pkgRoot = dirname(pkgPath); while (directoryStack.length > 0) { @@ -40,7 +44,6 @@ export function findPackageRoot(basedir) { // noop } } - const nextBasedir = dirname(basedir); if (nextBasedir === basedir || nextBasedir === cwd) break; basedir = nextBasedir; directoryStack.push(basedir); @@ -49,7 +52,7 @@ export function findPackageRoot(basedir) { } const packageCache = new Map(); -export function findNearestPackageData(basedir) { +export function findNearestPackageData(basedir, isRoot = false) { const directoryStack = [basedir]; while (basedir) { if (packageCache.has(basedir)) { @@ -59,13 +62,15 @@ export function findNearestPackageData(basedir) { if (tryStat(pkgPath)) { try { const pkgData = loadPackageData(pkgPath); - const pkgRoot = dirname(pkgPath); - while (directoryStack.length > 0) { - const dir = directoryStack.pop(); - packageCache.set(dir, pkgData); - packagePathCache.set(dir, pkgRoot); + if (!isRoot || (isRoot && pkgData.name)) { + const pkgRoot = dirname(pkgPath); + while (directoryStack.length > 0) { + const dir = directoryStack.pop(); + packageCache.set(dir, pkgData); + packagePathCache.set(dir, pkgRoot); + } + return pkgData; } - return pkgData; } catch { // noop } @@ -79,7 +84,7 @@ export function findNearestPackageData(basedir) { } const packageTypeCache = new Map(); -export function isModule(filePath) { +export function isModule(filePath, isRoot = false) { if (packageTypeCache.has(filePath)) { return packageTypeCache.get(filePath); } else if (/\.m[jt]s$/.test(filePath)) { @@ -92,11 +97,11 @@ export function isModule(filePath) { const dir = dirname( filePath.startsWith("file://") ? fileURLToPath(filePath) : filePath ); - const root = findPackageRoot(dir); - const pkg = findNearestPackageData(dir); + const root = findPackageRoot(dir, isRoot); + const pkg = findNearestPackageData(dir, isRoot); const isModule = pkg?.type === "module" || - (pkg?.module && join(root, pkg?.module) === filePath); + (pkg?.module && !relative(root, filePath).startsWith("../")); //join(root, pkg?.module) === filePath); packageTypeCache.set(filePath, isModule); return isModule; } catch (e) { @@ -105,6 +110,10 @@ export function isModule(filePath) { } } +export function isRootModule(filePath) { + return isModule(filePath, true); +} + const clientComponentsCache = new Map(); export function hasClientComponents(filePath) { if (!filePath) return false;