Cannot get past "Must module.exports a string."
Opened this issue · 11 comments
babel-plugin-codegen
version: 3.0.0node
version: 10.15.0npm
(oryarn
) version: yarn 1.13.0babel
: 7.4.5babel-plugin-macros
: 2.5.1 (required by another dep)
Relevant code or config
// my.js
codegen`module.exports = ''`;
// babel.config.js
module.exports = {
presets: [
[
'@babel/env',
{
targets: {
browsers: [
'last 2 versions',
'ie 11',
]
},
useBuiltIns: 'usage',
corejs: 2,
},
],
],
plugins: [
'macros',
'codegen',
'@babel/plugin-syntax-dynamic-import',
],
};
What you did:
Try to compile my.js
What happened:
codegen: Must module.exports a string.
at getReplacement (node_modules/babel-plugin-codegen/dist/helpers.js:43:11)
at replace (node_modules/babel-plugin-codegen/dist/helpers.js:69:21)
at asFunction (node_modules/babel-plugin-codegen/dist/replace.js:57:5)
at asIdentifier (node_modules/babel-plugin-codegen/dist/replace.js:127:22)
at PluginPass.Identifier (node_modules/babel-plugin-codegen/dist/index.js:37:11)
at newFn (node_modules/@babel/traverse/lib/visitors.js:193:21)
at NodePath._call (node_modules/@babel/traverse/lib/path/context.js:53:20)
at NodePath.call (node_modules/@babel/traverse/lib/path/context.js:40:17)
at NodePath.visit (node_modules/@babel/traverse/lib/path/context.js:88:12)
at TraversalContext.visitQueue (node_modules/@babel/traverse/lib/context.js:118:16)
Reproduction repository:
Problem description:
I cannot seem to get past the Must module.exports a string
. I've tried using escaped backticks, double quotes and single quotes, joining arrays, concatenating strings some other way (e.g., with +
operator), etc.
What am I doing wrong?
Suggested solution:
n/a
Hi @foxbunny,
Interesting. Do you get this same error when your string is used to generate actual code?
If you could make a reproduction repository that would be very helpful.
@kentcdodds Yes. I get that with pretty much anything, string or no string.
I'll see if I can whip up a repro during the week.
@kentcdodds Here's the repo that contains the sample. Details are in the readme.
I can reproduce this. Thank you. Weird things are going on here. I'm wondering if it could be a regression bug in recent versions of babel.
I don't have time to look in it today, but I'll try this week sometime.
OK. Thanks for looking into this. I'm really excited about trying codegen. :)
I'm afraid that I don't personally have time to allocate to digging into this. Sorry :-/
No biggie. I'd look into it myself, but kinda similar situation time-wise. :)
this issue can be reproduced when use with "@babel/preset-env":
see error stacks below
Error: ~/babel-demo/src/index.js: codegen: Must module.exports a string.
at getReplacement (~/babel-demo/codegen/helpers.js:46:11)
at replace (~/babel-demo/codegen/helpers.js:67:23)
at asFunction (~/babel-demo/codegen/replace.js:144:5)
at asIdentifier (~/babel-demo/codegen/replace.js:67:18)
at PluginPass.Identifier (~/babel-demo/codegen/index.js:26:11)
at newFn (~/babel-demo/node_modules/@babel/traverse/lib/visitors.js:179:21)
at NodePath._call (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:55:20)
at NodePath.call (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:42:17)
at NodePath.visit (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:90:31)
at TraversalContext.visitQueue (~/babel-demo/node_modules/@babel/traverse/lib/context.js:112:16) {
code: 'BABEL_TRANSFORM_ERROR'
}
this line get the value with undefined:
const code = argumentsPaths[0].evaluate().value;
function asFunction(path, fileOpts) {
const argumentsPaths = path.get("arguments");
// variable code is undefined,
const code = argumentsPaths[0].evaluate().value;
replace(
{
path: argumentsPaths[0].parentPath,
code,
fileOpts
},
babel
);
}
function getReplacement({ code, fileOpts, args = [] }, babel) {
let module = requireFromString(code, fileOpts.filename);
// If a function is epxorted, call it with args
if (typeof module === "function") {
module = module(...args);
} else if (args.length) {
throw new Error(
`codegen module (${p.relative(
process.cwd(),
fileOpts.filename
)}) cannot accept arguments because it does not export a function. You passed the arguments: ${args.join(
", "
)}`
);
}
// Convert whatever we got now (hopefully a string) into AST form
if (typeof module !== "string") {
// console.log(typeof module);
throw new Error("codegen: Must module.exports a string.");
}
return babel.template(module, {
preserveComments: true,
placeholderPattern: false,
...fileOpts.parserOpts,
sourceType: "module"
})();
}
this issue can be reproduced when use with "@babel/preset-env":
see error stacks below
Error: ~/babel-demo/src/index.js: codegen: Must module.exports a string. at getReplacement (~/babel-demo/codegen/helpers.js:46:11) at replace (~/babel-demo/codegen/helpers.js:67:23) at asFunction (~/babel-demo/codegen/replace.js:144:5) at asIdentifier (~/babel-demo/codegen/replace.js:67:18) at PluginPass.Identifier (~/babel-demo/codegen/index.js:26:11) at newFn (~/babel-demo/node_modules/@babel/traverse/lib/visitors.js:179:21) at NodePath._call (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:55:20) at NodePath.call (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:42:17) at NodePath.visit (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:90:31) at TraversalContext.visitQueue (~/babel-demo/node_modules/@babel/traverse/lib/context.js:112:16) { code: 'BABEL_TRANSFORM_ERROR' }this line get the value with undefined:
const code = argumentsPaths[0].evaluate().value;
function asFunction(path, fileOpts) { const argumentsPaths = path.get("arguments"); // variable code is undefined, const code = argumentsPaths[0].evaluate().value; replace( { path: argumentsPaths[0].parentPath, code, fileOpts }, babel ); }function getReplacement({ code, fileOpts, args = [] }, babel) { let module = requireFromString(code, fileOpts.filename); // If a function is epxorted, call it with args if (typeof module === "function") { module = module(...args); } else if (args.length) { throw new Error( `codegen module (${p.relative( process.cwd(), fileOpts.filename )}) cannot accept arguments because it does not export a function. You passed the arguments: ${args.join( ", " )}` ); } // Convert whatever we got now (hopefully a string) into AST form if (typeof module !== "string") { // console.log(typeof module); throw new Error("codegen: Must module.exports a string."); } return babel.template(module, { preserveComments: true, placeholderPattern: false, ...fileOpts.parserOpts, sourceType: "module" })(); }
seems @babel/plugin-transform-template-literals
caused this issue, i have tested them one by one and combinations;
node_modules/@babel/preset-env/lib/index.js
const pluginOfPresetEnv =[];
for(let key of transformations .keys()){
pluginOfPresetEnv.push(key)
}
console.log('pluginOfPresetEnv',pluginOfPresetEnv)
//pluginOfPresetEnv [
// 'transform-template-literals',
// 'transform-literals',
// 'transform-function-name',
// 'transform-arrow-functions',
// 'transform-block-scoped-functions',
// 'transform-classes',
// 'transform-object-super',
// 'transform-shorthand-properties',
// 'transform-duplicate-keys',
// 'transform-computed-properties',
// 'transform-for-of',
// 'transform-sticky-regex',
// 'transform-dotall-regex',
// 'transform-unicode-regex',
// 'transform-spread',
// 'transform-parameters',
// 'transform-destructuring',
// 'transform-block-scoping',
// 'transform-typeof-symbol',
// 'transform-new-target',
// 'transform-regenerator',
// 'transform-exponentiation-operator',
// 'transform-async-to-generator',
// 'proposal-async-generator-functions',
// 'proposal-object-rest-spread',
// 'proposal-unicode-property-regex',
// 'proposal-json-strings',
// 'proposal-optional-catch-binding'
// ]
let pluginOfPresetEnvArray =[
// 'transform-template-literals',
'transform-literals',
'transform-function-name',
'transform-arrow-functions',
'transform-block-scoped-functions',
'transform-classes',
'transform-object-super',
'transform-shorthand-properties',
'transform-duplicate-keys',
'transform-computed-properties',
'transform-for-of',
'transform-sticky-regex',
'transform-dotall-regex',
'transform-unicode-regex',
'transform-spread',
'transform-parameters',
'transform-destructuring',
'transform-block-scoping',
'transform-typeof-symbol',
'transform-new-target',
'transform-regenerator',
'transform-exponentiation-operator',
'transform-async-to-generator',
'proposal-async-generator-functions',
'proposal-object-rest-spread',
'proposal-unicode-property-regex',
'proposal-json-strings',
'proposal-optional-catch-binding'
]
transformations.forEach(pluginName => {
if(pluginOfPresetEnvArray.includes(pluginName)){
const config ={ spec,loose, useBuiltIns: pluginUseBuiltIns}
plugins.push([getPlugin(pluginName), config])
}
});
const regenerator = transformations.has("transform-regenerator");
this issue can be reproduced when use with "@babel/preset-env":
see error stacks belowError: ~/babel-demo/src/index.js: codegen: Must module.exports a string. at getReplacement (~/babel-demo/codegen/helpers.js:46:11) at replace (~/babel-demo/codegen/helpers.js:67:23) at asFunction (~/babel-demo/codegen/replace.js:144:5) at asIdentifier (~/babel-demo/codegen/replace.js:67:18) at PluginPass.Identifier (~/babel-demo/codegen/index.js:26:11) at newFn (~/babel-demo/node_modules/@babel/traverse/lib/visitors.js:179:21) at NodePath._call (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:55:20) at NodePath.call (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:42:17) at NodePath.visit (~/babel-demo/node_modules/@babel/traverse/lib/path/context.js:90:31) at TraversalContext.visitQueue (~/babel-demo/node_modules/@babel/traverse/lib/context.js:112:16) { code: 'BABEL_TRANSFORM_ERROR' }this line get the value with undefined:
const code = argumentsPaths[0].evaluate().value;
function asFunction(path, fileOpts) { const argumentsPaths = path.get("arguments"); // variable code is undefined, const code = argumentsPaths[0].evaluate().value; replace( { path: argumentsPaths[0].parentPath, code, fileOpts }, babel ); }function getReplacement({ code, fileOpts, args = [] }, babel) { let module = requireFromString(code, fileOpts.filename); // If a function is epxorted, call it with args if (typeof module === "function") { module = module(...args); } else if (args.length) { throw new Error( `codegen module (${p.relative( process.cwd(), fileOpts.filename )}) cannot accept arguments because it does not export a function. You passed the arguments: ${args.join( ", " )}` ); } // Convert whatever we got now (hopefully a string) into AST form if (typeof module !== "string") { // console.log(typeof module); throw new Error("codegen: Must module.exports a string."); } return babel.template(module, { preserveComments: true, placeholderPattern: false, ...fileOpts.parserOpts, sourceType: "module" })(); }seems
@babel/plugin-transform-template-literals
caused this issue, i have tested them one by one and combinations;
node_modules/@babel/preset-env/lib/index.js
const pluginOfPresetEnv =[]; for(let key of transformations .keys()){ pluginOfPresetEnv.push(key) } console.log('pluginOfPresetEnv',pluginOfPresetEnv) //pluginOfPresetEnv [ // 'transform-template-literals', // 'transform-literals', // 'transform-function-name', // 'transform-arrow-functions', // 'transform-block-scoped-functions', // 'transform-classes', // 'transform-object-super', // 'transform-shorthand-properties', // 'transform-duplicate-keys', // 'transform-computed-properties', // 'transform-for-of', // 'transform-sticky-regex', // 'transform-dotall-regex', // 'transform-unicode-regex', // 'transform-spread', // 'transform-parameters', // 'transform-destructuring', // 'transform-block-scoping', // 'transform-typeof-symbol', // 'transform-new-target', // 'transform-regenerator', // 'transform-exponentiation-operator', // 'transform-async-to-generator', // 'proposal-async-generator-functions', // 'proposal-object-rest-spread', // 'proposal-unicode-property-regex', // 'proposal-json-strings', // 'proposal-optional-catch-binding' // ] let pluginOfPresetEnvArray =[ // 'transform-template-literals', 'transform-literals', 'transform-function-name', 'transform-arrow-functions', 'transform-block-scoped-functions', 'transform-classes', 'transform-object-super', 'transform-shorthand-properties', 'transform-duplicate-keys', 'transform-computed-properties', 'transform-for-of', 'transform-sticky-regex', 'transform-dotall-regex', 'transform-unicode-regex', 'transform-spread', 'transform-parameters', 'transform-destructuring', 'transform-block-scoping', 'transform-typeof-symbol', 'transform-new-target', 'transform-regenerator', 'transform-exponentiation-operator', 'transform-async-to-generator', 'proposal-async-generator-functions', 'proposal-object-rest-spread', 'proposal-unicode-property-regex', 'proposal-json-strings', 'proposal-optional-catch-binding' ] transformations.forEach(pluginName => { if(pluginOfPresetEnvArray.includes(pluginName)){ const config ={ spec,loose, useBuiltIns: pluginUseBuiltIns} plugins.push([getPlugin(pluginName), config]) } }); const regenerator = transformations.has("transform-regenerator");
here is the key codes :
https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-template-literals/src/index.js#L96
after this step, the codegen function visitor dead
Confirming this is still an issue.
That said, it can be circumvented by invoking codegen
directly instead of using a tagged template:
# Instead of
codegen`module.exports = ...`
# do
codegen(`module.exports = ...`)