Exports Parser (parse-exports.js)
Examine the abstract syntax tree exports parser, module reflection tools, and custom compiler proxies.
Key File Location: ./dinou/core/parse-exports.js💡 Overview
In React Server Components (RSC), the loader must determine which functions are exported by Client Components (files starting with "use client") and Server Functions (files starting with "use server"). This allows the compiler to generate proxy wrappers that bridge process and network boundaries.
The parse-exports.js utility handles this by parsing the file into an Abstract Syntax Tree (AST) and extracting all exported identifiers.
📊 AST Traversal Flow
The flowchart below shows how different export structures are traversed and collected:
⚡ AST Analysis & Compilation Hooks
The utility handles export collection using targeted AST traversal:
- Babel AST Parser: Parses code containing JSX and TypeScript type notations into a semantic node tree.
- Export Identification: Traverses named and default exports, variable declarations, and custom specifiers to collect all exported modules.
⚙️ Complete Code Walkthrough
Below is the full, complete code of parse-exports.js:
const parser = require("@babel/parser");
const traverse = require("@babel/traverse");
function parseExports(code) {
// 1. Parse JavaScript/TypeScript source code into Abstract Syntax Tree (AST)
const ast = parser.parse(code, {
sourceType: "module",
plugins: ["jsx", "typescript"],
});
const exports = new Set();
// 2. Traverse the AST tree nodes and collect export identifiers
traverse.default(ast, {
ExportDefaultDeclaration() {
exports.add("default");
},
ExportNamedDeclaration(p) {
if (p.node.declaration) {
// Collect exported functions/classes: export function foo()
if (
p.node.declaration.type === "FunctionDeclaration" ||
p.node.declaration.type === "ClassDeclaration"
) {
exports.add(p.node.declaration.id.name);
// Collect exported variable constants: export const bar = 1, baz = 2
} else if (p.node.declaration.type === "VariableDeclaration") {
p.node.declaration.declarations.forEach((d) => {
if (d.id.type === "Identifier") {
exports.add(d.id.name);
}
});
}
} else if (p.node.specifiers) {
// Collect named export statements: export { foo, bar }
p.node.specifiers.forEach((s) => {
if (s.type === "ExportSpecifier") {
exports.add(s.exported.name);
}
});
}
},
});
// 3. Return unique exports list array
return [...exports];
}
module.exports = parseExports;