UNPKG

rwsdk

Version:

Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime

196 lines (195 loc) 8.3 kB
import debug from "debug"; import { ROOT_DIR } from "../lib/constants.mjs"; import { ensureAliasArray } from "./ensureAliasArray.mjs"; import { ENV_RESOLVERS } from "./envResolvers.mjs"; const log = debug("rwsdk:vite:known-deps-resolver-plugin"); const KNOWN_PREFIXES = [ "react", "react-dom", "react-server-dom-webpack", "rwsdk", ]; export const ENV_PREDEFINED_IMPORTS = { worker: [ "react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime", "react-server-dom-webpack/server.edge", ], ssr: [ "react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime", "react-dom/server.edge", "react-dom/server", "react-server-dom-webpack/client.edge", ], client: [ "react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime", "react-server-dom-webpack/client.browser", "react-server-dom-webpack/client.edge", ], }; function resolveKnownImport(id, envName, projectRootDir, isPrefixedImport = false) { if (!isPrefixedImport) { const isKnownImport = KNOWN_PREFIXES.some((prefix) => id === prefix || id.startsWith(`${prefix}/`)); if (!isKnownImport) { return undefined; } } let resolved; try { resolved = ENV_RESOLVERS[envName](projectRootDir, id) || undefined; process.env.VERBOSE && log("Successfully resolved %s to %s for env=%s from project root", id, resolved, envName); } catch { process.env.VERBOSE && log("Failed to resolve %s for env=%s from project root, trying ROOT_DIR", id, envName); try { resolved = ENV_RESOLVERS[envName](ROOT_DIR, id) || undefined; process.env.VERBOSE && log("Successfully resolved %s to %s for env=%s from rwsdk root", id, resolved, envName); } catch { process.env.VERBOSE && log("Failed to resolve %s for env=%s", id, envName); } } return resolved; } function resolvePredefinedEnvImportMappings(env, projectRootDir) { process.env.VERBOSE && log("Resolving environment import mappings for env=%s", env); const mappings = new Map(); const predefinedImports = ENV_PREDEFINED_IMPORTS[env]; for (const importRequest of predefinedImports) { const resolved = resolveKnownImport(importRequest, env, projectRootDir, true); if (resolved) { mappings.set(importRequest, resolved); process.env.VERBOSE && log("Added mapping for %s -> %s in env=%s", importRequest, resolved, env); } } process.env.VERBOSE && log("Environment import mappings complete for env=%s: %d mappings", env, mappings.size); return mappings; } export const knownDepsResolverPlugin = ({ projectRootDir, }) => { log("Initializing known dependencies resolver plugin"); let isBuild = false; const ENV_IMPORT_MAPPINGS = Object.fromEntries(Object.keys(ENV_RESOLVERS).map((env) => [ env, resolvePredefinedEnvImportMappings(env, projectRootDir), ])); // Log a clean summary instead of all the individual mappings const totalMappings = Object.values(ENV_IMPORT_MAPPINGS).reduce((sum, mappings) => sum + mappings.size, 0); log("Known dependencies resolver configured with %d total mappings across %d environments", totalMappings, Object.keys(ENV_IMPORT_MAPPINGS).length); function createEsbuildResolverPlugin(envName, mappings) { if (!mappings) { return null; } return { name: `rwsdk:known-dependencies-resolver-esbuild-${envName}`, setup(build) { build.onResolve({ filter: /.*/ }, (args) => { let resolved = mappings.get(args.path); if (!resolved) { resolved = resolveKnownImport(args.path, envName, projectRootDir); } if (resolved && args.importer !== "") { if (args.path === "react-server-dom-webpack/client.edge") { return; } return { path: resolved, }; } }); }, }; } return [ { name: "rwsdk:known-dependencies-resolver:config", enforce: "post", config(config, { command }) { isBuild = command === "build"; log("Configuring plugin for command=%s", command); }, configResolved(config) { log("Setting up resolve aliases and optimizeDeps for each environment"); // Set up aliases and optimizeDeps for each environment for (const [envName, mappings] of Object.entries(ENV_IMPORT_MAPPINGS)) { const predefinedImports = ENV_PREDEFINED_IMPORTS[envName]; // Ensure environment config exists if (!config.environments) { config.environments = {}; } if (!config.environments[envName]) { config.environments[envName] = {}; } const envConfig = config.environments[envName]; const esbuildPlugin = createEsbuildResolverPlugin(envName, mappings); if (esbuildPlugin && mappings) { envConfig.optimizeDeps ??= {}; envConfig.optimizeDeps.esbuildOptions ??= {}; envConfig.optimizeDeps.esbuildOptions.define ??= {}; envConfig.optimizeDeps.esbuildOptions.define["process.env.NODE_ENV"] = JSON.stringify(process.env.NODE_ENV); envConfig.optimizeDeps.esbuildOptions.plugins ??= []; envConfig.optimizeDeps.esbuildOptions.plugins.push(esbuildPlugin); envConfig.optimizeDeps.include ??= []; envConfig.optimizeDeps.include.push(...predefinedImports); log("Added esbuild plugin and optimizeDeps includes for environment: %s", envName); } const aliases = ensureAliasArray(envConfig); for (const [find, replacement] of mappings) { const findRegex = new RegExp(`^${find.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&")}$`); aliases.push({ find: findRegex, replacement }); process.env.VERBOSE && log("Added alias for env=%s: %s -> %s", envName, find, replacement); } log("Environment %s configured with %d aliases and %d optimizeDeps includes", envName, mappings.size, predefinedImports.length); } }, }, { name: "rwsdk:known-dependencies-resolver:resolveId", enforce: "pre", async resolveId(id, importer) { // Skip during directive scanning to avoid performance issues if (process.env.RWSDK_DIRECTIVE_SCAN_ACTIVE) { return; } if (!isBuild) { return; } const envName = this.environment?.name; if (!envName) { return; } const mappings = ENV_IMPORT_MAPPINGS[envName]; if (!mappings) { process.env.VERBOSE && log("No mappings found for environment: %s", envName); return; } let resolved = mappings.get(id); if (!resolved) { resolved = resolveKnownImport(id, envName, projectRootDir); } if (resolved) { process.env.VERBOSE && log("Resolved %s -> %s for env=%s", id, resolved, envName); return resolved; } }, }, ]; };