寻求识别module.exports的正确Babel AST检测类型
module.exports with Babel AST Great question! The issue here is that module.exports falls under CommonJS syntax, which uses completely different AST node types than ES module exports like export default or export const—that’s why your existing checks for ExportDefaultDeclaration and ExportNamedDeclaration aren’t picking it up. The DeclareModuleExports type you tried is actually for TypeScript declaration statements (like declare module.exports: MyType), so it won’t work for regular CommonJS assignment code.
Here’s how to properly detect different forms of module.exports and exports using Babel’s AST types:
1. Direct module.exports assignment (e.g. module.exports = myValue)
This maps to an AssignmentExpression node. To confirm it’s a module.exports assignment, you need to check that the left-hand side is a MemberExpression where:
- The
objectis anIdentifiernamedmodule - The
propertyis anIdentifiernamedexports
Example AST structure for module.exports = foo:
{ type: "AssignmentExpression", left: { type: "MemberExpression", object: { type: "Identifier", name: "module" }, property: { type: "Identifier", name: "exports" } }, right: { type: "Identifier", name: "foo" } // The value being exported }
2. Named exports via module.exports (e.g. module.exports.myFunc = myFunc)
This is also an AssignmentExpression, but the left-hand side is a nested MemberExpression: the outer MemberExpression has an object of module.exports (another MemberExpression) and a property matching the export name (e.g. myFunc).
3. Direct exports assignments (e.g. exports.myVar = 123 or exports = { ... })
Similar to module.exports, this uses AssignmentExpression:
- For
exports.myVar = 123: The left-hand side is aMemberExpressionwhere the object is anIdentifiernamedexports - For
exports = { ... }: The left-hand side is simply anIdentifiernamedexports(note: this pattern is less common because it overrides theexportsreference, breaking links tomodule.exports)
Example Detection Code
Here’s a practical snippet using Babel’s traverse API to detect all export types (ES and CommonJS):
const babel = require('@babel/core'); const t = require('@babel/types'); const sampleCode = ` // CommonJS exports module.exports = { hello: 'world' }; module.exports.greet = () => 'hi'; exports.foo = 'bar'; // ES module exports export default 'es-default'; export const esNamed = 'es-named'; `; babel.transform(sampleCode, {}, (err, result) => { if (err) throw err; babel.traverse(result.ast, { // Detect ES module default exports ExportDefaultDeclaration(path) { console.log('ES Default Export:', path.node.declaration); }, // Detect ES module named exports ExportNamedDeclaration(path) { console.log('ES Named Export:', path.node.declaration); }, // Detect CommonJS exports AssignmentExpression(path) { const leftNode = path.node.left; // Check for module.exports = ... if (t.isMemberExpression(leftNode) && t.isIdentifier(leftNode.object, { name: 'module' }) && t.isIdentifier(leftNode.property, { name: 'exports' })) { console.log('CommonJS Default Export:', path.node.right); } // Check for module.exports.NAME = ... else if (t.isMemberExpression(leftNode) && t.isMemberExpression(leftNode.object) && t.isIdentifier(leftNode.object.object, { name: 'module' }) && t.isIdentifier(leftNode.object.property, { name: 'exports' })) { console.log(`CommonJS Named Export (module.exports.${leftNode.property.name}):`, path.node.right); } // Check for exports.NAME = ... else if (t.isMemberExpression(leftNode) && t.isIdentifier(leftNode.object, { name: 'exports' })) { console.log(`CommonJS Named Export (exports.${leftNode.property.name}):`, path.node.right); } // Check for exports = ... else if (t.isIdentifier(leftNode, { name: 'exports' })) { console.log('CommonJS Exports Assignment:', path.node.right); } } }); });
Key Notes
- Always use Babel’s
@babel/typesutility functions (liket.isMemberExpression) instead of checkingtypedirectly—they validate additional properties and make your code more robust. - Keep in mind that
module.exportscan be assigned to any expression (functions, classes, objects, literals), so you’ll need to handle therightside of theAssignmentExpressionbased on your use case. - If you’re working with mixed ES and CommonJS code, this approach will cover all export patterns you’re likely to encounter.
内容的提问来源于stack exchange,提问作者ChoclateLove

