@vitejs/plugin-rsc
Version:
React Server Components (RSC) support for Vite.
110 lines (107 loc) • 4.17 kB
JavaScript
import { t as createDebug } from "./dist-BRSdGcl7.js";
import { n as parseIdQuery } from "./shared-AtH_QTi7.js";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import * as esModuleLexer from "es-module-lexer";
import MagicString from "magic-string";
import { parseAstAsync } from "vite";
import { findClosestPkgJsonPath } from "vitefu";
import { walk } from "estree-walker";
import { analyze } from "periscopic";
//#region src/transforms/cjs.ts
const CJS_INTEROP_HELPER = `function __cjs_interop__(m) { return m.__cjs_module_runner_transform ? m.default : m; }`;
function transformCjsToEsm(code, ast, options) {
const output = new MagicString(code);
const analyzed = analyze(ast);
const parentNodes = [];
const hoistedCodes = [];
let hoistIndex = 0;
walk(ast, {
enter(node) {
parentNodes.push(node);
if (node.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "require" && node.arguments.length === 1) {
let isTopLevel = true;
for (const parent of parentNodes) {
if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration" || parent.type === "ArrowFunctionExpression") isTopLevel = false;
const scope = analyzed.map.get(parent);
if (scope && scope.declarations.has("require")) return;
}
if (isTopLevel) {
output.update(node.start, node.callee.end, "(__cjs_interop__(await import");
output.appendRight(node.end, "))");
} else {
const hoisted = `__cjs_to_esm_hoist_${hoistIndex}`;
const importee = code.slice(node.arguments[0].start, node.arguments[0].end);
hoistedCodes.push(`const ${hoisted} = __cjs_interop__(await import(${importee}));\n`);
output.update(node.start, node.end, hoisted);
hoistIndex++;
}
}
},
leave() {
parentNodes.pop();
}
});
for (const hoisted of hoistedCodes.reverse()) output.prepend(hoisted);
if (output.hasChanged()) output.prepend(`${CJS_INTEROP_HELPER}\n`);
output.prepend(`let exports = {}; const module = { exports };\n`);
const __filename = fileURLToPath(pathToFileURL(options.id).href);
const __dirname = path.dirname(__filename);
output.prepend(`let __filename = ${JSON.stringify(__filename)}; let __dirname = ${JSON.stringify(__dirname)};\n`);
output.append(`
;__vite_ssr_exportAll__(module.exports);
export default module.exports;
export const __cjs_module_runner_transform = true;
`);
return { output };
}
//#endregion
//#region src/plugins/cjs.ts
const debug = createDebug("vite-rsc:cjs");
function cjsModuleRunnerPlugin() {
const warnedPackages = /* @__PURE__ */ new Set();
return [{
name: "cjs-module-runner-transform",
apply: "serve",
applyToEnvironment: (env) => env.config.dev.moduleRunnerTransform,
async transform(code, id) {
if (id.includes("/node_modules/") && !id.startsWith(this.environment.config.cacheDir) && /\b(require|exports)\b/.test(code)) {
id = parseIdQuery(id).filename;
if (!/\.[cm]?js$/.test(id)) return;
if (id.endsWith(".mjs")) return;
if (id.endsWith(".js")) {
const pkgJsonPath = await findClosestPkgJsonPath(path.dirname(id));
if (pkgJsonPath) {
if (JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8")).type === "module") return;
}
}
const [, , , hasModuleSyntax] = esModuleLexer.parse(code);
if (hasModuleSyntax) return;
const packageKey = extractPackageKey(id);
if (!warnedPackages.has(packageKey)) {
debug(`non-optimized CJS dependency in '${this.environment.name}' environment: ${id}`);
warnedPackages.add(packageKey);
}
const output = transformCjsToEsm(code, await parseAstAsync(code), { id }).output;
return {
code: output.toString(),
map: output.generateMap({ hires: "boundary" })
};
}
}
}];
}
function extractPackageKey(id) {
const yarnMatch = id.match(/\/.yarn\/cache\/([^/]+)/);
if (yarnMatch) return yarnMatch[1];
if (id.includes("/node_modules")) {
id = id.split("/node_modules/").at(-1);
let [x, y] = id.split("/");
if (x.startsWith("@")) return `${x}/${y}`;
return x;
}
return id;
}
//#endregion
export { cjsModuleRunnerPlugin as t };