mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
fix: avoid downleveled dynamic import closing over specifier expression (#49663)
* fix: evaluate dynamic import specifier expressions synchronously * refactor * Update src/compiler/transformers/module/module.ts Co-authored-by: Ron Buckton <ron.buckton@microsoft.com> * [Experiment] Co-authored-by: Ron Buckton <ron.buckton@microsoft.com>
This commit is contained in:
@@ -721,7 +721,7 @@ namespace ts {
|
||||
return createImportCallExpressionUMD(argument ?? factory.createVoidZero(), containsLexicalThis);
|
||||
case ModuleKind.CommonJS:
|
||||
default:
|
||||
return createImportCallExpressionCommonJS(argument, containsLexicalThis);
|
||||
return createImportCallExpressionCommonJS(argument);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,7 +745,7 @@ namespace ts {
|
||||
return factory.createConditionalExpression(
|
||||
/*condition*/ factory.createIdentifier("__syncRequire"),
|
||||
/*questionToken*/ undefined,
|
||||
/*whenTrue*/ createImportCallExpressionCommonJS(arg, containsLexicalThis),
|
||||
/*whenTrue*/ createImportCallExpressionCommonJS(arg),
|
||||
/*colonToken*/ undefined,
|
||||
/*whenFalse*/ createImportCallExpressionAMD(argClone, containsLexicalThis)
|
||||
);
|
||||
@@ -755,7 +755,7 @@ namespace ts {
|
||||
return factory.createComma(factory.createAssignment(temp, arg), factory.createConditionalExpression(
|
||||
/*condition*/ factory.createIdentifier("__syncRequire"),
|
||||
/*questionToken*/ undefined,
|
||||
/*whenTrue*/ createImportCallExpressionCommonJS(temp, containsLexicalThis),
|
||||
/*whenTrue*/ createImportCallExpressionCommonJS(temp, /* isInlineable */ true),
|
||||
/*colonToken*/ undefined,
|
||||
/*whenFalse*/ createImportCallExpressionAMD(temp, containsLexicalThis)
|
||||
));
|
||||
@@ -820,14 +820,25 @@ namespace ts {
|
||||
return promise;
|
||||
}
|
||||
|
||||
function createImportCallExpressionCommonJS(arg: Expression | undefined, containsLexicalThis: boolean): Expression {
|
||||
// import("./blah")
|
||||
function createImportCallExpressionCommonJS(arg: Expression | undefined, isInlineable?: boolean): Expression {
|
||||
// import(x)
|
||||
// emit as
|
||||
// Promise.resolve().then(function () { return require(x); }) /*CommonJs Require*/
|
||||
// var _a;
|
||||
// (_a = x, Promise.resolve().then(() => require(_a)) /*CommonJs Require*/
|
||||
// We have to wrap require in then callback so that require is done in asynchronously
|
||||
// if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
|
||||
const promiseResolveCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []);
|
||||
let requireCall: Expression = factory.createCallExpression(factory.createIdentifier("require"), /*typeArguments*/ undefined, arg ? [arg] : []);
|
||||
// If the arg is not inlineable, we have to evaluate it in the current scope with a temp var
|
||||
const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(hoistVariableDeclaration) : undefined;
|
||||
const promiseResolveCall = factory.createCallExpression(
|
||||
factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"),
|
||||
/*typeArguments*/ undefined,
|
||||
/*argumentsArray*/ [],
|
||||
);
|
||||
let requireCall: Expression = factory.createCallExpression(
|
||||
factory.createIdentifier("require"),
|
||||
/*typeArguments*/ undefined,
|
||||
temp ? [temp] : arg ? [arg] : [],
|
||||
);
|
||||
if (getESModuleInterop(compilerOptions)) {
|
||||
requireCall = emitHelpers().createImportStarHelper(requireCall);
|
||||
}
|
||||
@@ -851,16 +862,11 @@ namespace ts {
|
||||
/*parameters*/ [],
|
||||
/*type*/ undefined,
|
||||
factory.createBlock([factory.createReturnStatement(requireCall)]));
|
||||
|
||||
// if there is a lexical 'this' in the import call arguments, ensure we indicate
|
||||
// that this new function expression indicates it captures 'this' so that the
|
||||
// es2015 transformer will properly substitute 'this' with '_this'.
|
||||
if (containsLexicalThis) {
|
||||
setEmitFlags(func, EmitFlags.CapturesThis);
|
||||
}
|
||||
}
|
||||
|
||||
return factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);
|
||||
const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);
|
||||
|
||||
return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]);
|
||||
}
|
||||
|
||||
function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) {
|
||||
|
||||
Reference in New Issue
Block a user