From 431bd289c49fe61f16e980dd101baff348e68226 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 28 Aug 2021 07:14:06 +0200 Subject: [PATCH] Preserve context for amd/cjs dynamic non-arrow requires Resolves #3092 --- src/ast/nodes/ImportExpression.ts | 72 ++++++++++++------- src/utils/generateCodeSnippets.ts | 54 +++++--------- src/utils/systemJsRendering.ts | 15 ++-- .../_expected/amd/main.js | 2 +- .../_expected/cjs/main.js | 2 +- .../_expected/amd/main.js | 4 +- .../_expected/cjs/main.js | 4 +- .../dynamic-import-this-arrow/_config.js | 12 ++++ .../_expected/amd.js | 37 ++++++++++ .../_expected/cjs.js | 37 ++++++++++ .../dynamic-import-this-arrow/_expected/es.js | 15 ++++ .../_expected/iife.js | 22 ++++++ .../_expected/system.js | 24 +++++++ .../_expected/umd.js | 23 ++++++ .../samples/dynamic-import-this-arrow/main.js | 13 ++++ .../dynamic-import-this-function/_config.js | 12 ++++ .../_expected/amd.js | 37 ++++++++++ .../_expected/cjs.js | 37 ++++++++++ .../_expected/es.js | 15 ++++ .../_expected/iife.js | 22 ++++++ .../_expected/system.js | 24 +++++++ .../_expected/umd.js | 23 ++++++ .../dynamic-import-this-function/main.js | 13 ++++ .../_expected/amd.js | 6 +- .../_expected/cjs.js | 6 +- .../import-expression/_expected/amd.js | 2 +- .../import-expression/_expected/cjs.js | 2 +- .../interop-per-dependency/_expected/amd.js | 4 +- .../interop-per-dependency/_expected/cjs.js | 4 +- .../dynamic-import-this-arrow/_config.js | 26 +++++++ .../samples/dynamic-import-this-arrow/main.js | 13 ++++ .../dynamic-import-this-function/_config.js | 26 +++++++ .../dynamic-import-this-function/main.js | 13 ++++ 33 files changed, 534 insertions(+), 87 deletions(-) create mode 100644 test/form/samples/dynamic-import-this-arrow/_config.js create mode 100644 test/form/samples/dynamic-import-this-arrow/_expected/amd.js create mode 100644 test/form/samples/dynamic-import-this-arrow/_expected/cjs.js create mode 100644 test/form/samples/dynamic-import-this-arrow/_expected/es.js create mode 100644 test/form/samples/dynamic-import-this-arrow/_expected/iife.js create mode 100644 test/form/samples/dynamic-import-this-arrow/_expected/system.js create mode 100644 test/form/samples/dynamic-import-this-arrow/_expected/umd.js create mode 100644 test/form/samples/dynamic-import-this-arrow/main.js create mode 100644 test/form/samples/dynamic-import-this-function/_config.js create mode 100644 test/form/samples/dynamic-import-this-function/_expected/amd.js create mode 100644 test/form/samples/dynamic-import-this-function/_expected/cjs.js create mode 100644 test/form/samples/dynamic-import-this-function/_expected/es.js create mode 100644 test/form/samples/dynamic-import-this-function/_expected/iife.js create mode 100644 test/form/samples/dynamic-import-this-function/_expected/system.js create mode 100644 test/form/samples/dynamic-import-this-function/_expected/umd.js create mode 100644 test/form/samples/dynamic-import-this-function/main.js create mode 100644 test/function/samples/dynamic-import-this-arrow/_config.js create mode 100644 test/function/samples/dynamic-import-this-arrow/main.js create mode 100644 test/function/samples/dynamic-import-this-function/_config.js create mode 100644 test/function/samples/dynamic-import-this-function/main.js diff --git a/src/ast/nodes/ImportExpression.ts b/src/ast/nodes/ImportExpression.ts index f72a413e3a1..a9bc1edd05b 100644 --- a/src/ast/nodes/ImportExpression.ts +++ b/src/ast/nodes/ImportExpression.ts @@ -126,8 +126,19 @@ export default class ImportExpression extends NodeBase { private getDynamicImportMechanismAndHelper( resolution: Module | ExternalModule | string | null, exportMode: 'none' | 'named' | 'default' | 'external', - { compact, dynamicImportFunction, format, interop }: NormalizedOutputOptions, - { _, getDirectReturnFunctionLeft, directReturnFunctionRight }: GenerateCodeSnippets, + { + compact, + dynamicImportFunction, + format, + generatedCode: { arrowFunctions }, + interop + }: NormalizedOutputOptions, + { + _, + directReturnFunctionRight, + getDirectReturnFunctionLeft, + getDirectReturnIifeLeft + }: GenerateCodeSnippets, pluginDriver: PluginDriver ): { helper: string | null; mechanism: DynamicImportMechanism | null } { const mechanism = pluginDriver.hookFirstSync('renderDynamicImport', [ @@ -142,24 +153,31 @@ export default class ImportExpression extends NodeBase { if (mechanism) { return { helper: null, mechanism }; } + const hasDynamicTarget = !this.resolution || typeof this.resolution === 'string'; switch (format) { case 'cjs': { - const leftStart = `Promise.resolve().then(${getDirectReturnFunctionLeft([], { + const helper = getInteropHelper(resolution, exportMode, interop); + let left = `require(`; + let right = `)`; + if (helper) { + left = `/*#__PURE__*/${helper}(${left}`; + right += ')'; + } + left = `Promise.resolve().then(${getDirectReturnFunctionLeft([], { functionReturn: true, name: null - })}`; - const helper = getInteropHelper(resolution, exportMode, interop); + })}${left}`; + right += `${directReturnFunctionRight})`; + if (!arrowFunctions && hasDynamicTarget) { + left = getDirectReturnIifeLeft(['t'], `${left}t${right}`, { + needsArrowReturnParens: false, + needsWrappedFunction: true + }); + right = ')'; + } return { helper, - mechanism: helper - ? { - left: `${leftStart}/*#__PURE__*/${helper}(require(`, - right: `))${directReturnFunctionRight})` - } - : { - left: `${leftStart}require(`, - right: `)${directReturnFunctionRight})` - } + mechanism: { left, right } }; } case 'amd': { @@ -172,15 +190,21 @@ export default class ImportExpression extends NodeBase { name: null })}${resolve}(/*#__PURE__*/${helper}(m))${directReturnFunctionRight}` : resolve; + let left = `new Promise(${getDirectReturnFunctionLeft([resolve, reject], { + functionReturn: false, + name: null + })}require([`; + let right = `],${_}${resolveNamespace},${_}${reject})${directReturnFunctionRight})`; + if (!arrowFunctions && hasDynamicTarget) { + left = getDirectReturnIifeLeft(['t'], `${left}t${right}`, { + needsArrowReturnParens: false, + needsWrappedFunction: true + }); + right = ')'; + } return { helper, - mechanism: { - left: `new Promise(${getDirectReturnFunctionLeft([resolve, reject], { - functionReturn: false, - name: null - })}require([`, - right: `],${_}${resolveNamespace},${_}${reject})${directReturnFunctionRight})` - } + mechanism: { left, right } }; } case 'system': @@ -225,9 +249,3 @@ const accessedImportGlobals: Record = { cjs: ['require'], system: ['module'] }; - -// TODO Lukas consider fixing context issue for non-arrow resolutions IF it is dynamic: -// import(this.foo) -> -// (function (arg) { -// return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(arg)) -// })} (this.foo)) diff --git a/src/utils/generateCodeSnippets.ts b/src/utils/generateCodeSnippets.ts index 84fc7446346..741e322ed75 100644 --- a/src/utils/generateCodeSnippets.ts +++ b/src/utils/generateCodeSnippets.ts @@ -1,4 +1,3 @@ -import MagicString from 'magic-string'; import { NormalizedOutputOptions } from '../rollup/types'; import { RESERVED_NAMES } from './reservedNames'; @@ -12,23 +11,20 @@ export interface GenerateCodeSnippets { params: string[], options: { functionReturn: boolean; name: string | null } ): string; - getFunctionIntro(params: string[], options: { isAsync: boolean; name: string | null }): string; - getObject( - fields: [key: string | null, value: string][], - options: { indent: string; lineBreaks: boolean } - ): string; - getPropertyAccess(name: string): string; - renderDirectReturnIife( + getDirectReturnIifeLeft( params: string[], returned: string, - code: MagicString, - argStart: number, - argEnd: number, options: { needsArrowReturnParens: boolean | undefined; needsWrappedFunction: boolean | undefined; } - ): void; + ): string; + getFunctionIntro(params: string[], options: { isAsync: boolean; name: string | null }): string; + getObject( + fields: [key: string | null, value: string][], + options: { indent: string; lineBreaks: boolean } + ): string; + getPropertyAccess(name: string): string; } export function getGenerateCodeSnippets({ @@ -70,6 +66,17 @@ export function getGenerateCodeSnippets({ _, directReturnFunctionRight, getDirectReturnFunctionLeft, + getDirectReturnIifeLeft: (params, returned, { needsArrowReturnParens, needsWrappedFunction }) => + `${wrapIfNeeded( + `${getDirectReturnFunctionLeft(params, { + functionReturn: true, + name: null + })}${wrapIfNeeded( + returned, + arrowFunctions && needsArrowReturnParens + )}${directReturnFunctionRight}`, + arrowFunctions || needsWrappedFunction + )}(`, getFunctionIntro, getObject(fields, { indent, lineBreaks }) { const prefix = `${lineBreaks ? n : ''}${indent}`; @@ -87,29 +94,6 @@ export function getGenerateCodeSnippets({ isValidPropName(name) ? `.${name}` : `[${JSON.stringify(name)}]`, n, namedDirectReturnFunctionRight: `${directReturnFunctionRight}${arrowFunctions ? ';' : ''}`, - renderDirectReturnIife: ( - params, - returned, - code, - argStart, - argEnd, - { needsArrowReturnParens, needsWrappedFunction } - ) => { - code.prependRight( - argStart, - `${wrapIfNeeded( - `${getDirectReturnFunctionLeft(params, { - functionReturn: true, - name: null - })}${wrapIfNeeded( - returned, - arrowFunctions && needsArrowReturnParens - )}${directReturnFunctionRight}`, - arrowFunctions || needsWrappedFunction - )}(` - ); - code.appendLeft(argEnd, ')'); - }, s }; } diff --git a/src/utils/systemJsRendering.ts b/src/utils/systemJsRendering.ts index 89945ffe477..9241a173699 100644 --- a/src/utils/systemJsRendering.ts +++ b/src/utils/systemJsRendering.ts @@ -48,15 +48,16 @@ export function renderSystemExportFunction( code: MagicString, options: RenderOptions ): void { - const { _, renderDirectReturnIife } = options.snippets; - renderDirectReturnIife( - ['v'], - `${getSystemExportStatement(exportedVariables, options)},${_}v`, - code, + const { _, getDirectReturnIifeLeft } = options.snippets; + code.prependRight( expressionStart, - expressionEnd, - { needsArrowReturnParens: true, needsWrappedFunction: needsParens } + getDirectReturnIifeLeft( + ['v'], + `${getSystemExportStatement(exportedVariables, options)},${_}v`, + { needsArrowReturnParens: true, needsWrappedFunction: needsParens } + ) ); + code.appendLeft(expressionEnd, ')'); } export function renderSystemExportSequenceAfterExpression( diff --git a/test/chunking-form/samples/dynamic-import-dynamic/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-dynamic/_expected/amd/main.js index 949169b2dce..8562084a3d0 100644 --- a/test/chunking-form/samples/dynamic-import-dynamic/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-dynamic/_expected/amd/main.js @@ -20,6 +20,6 @@ define(['require'], (function (require) { 'use strict'; var dep = 'dep'; - new Promise(function (resolve, reject) { require([dep], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(dep); })); diff --git a/test/chunking-form/samples/dynamic-import-dynamic/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-dynamic/_expected/cjs/main.js index bcb0696ac33..03ca7fb54cc 100644 --- a/test/chunking-form/samples/dynamic-import-dynamic/_expected/cjs/main.js +++ b/test/chunking-form/samples/dynamic-import-dynamic/_expected/cjs/main.js @@ -20,4 +20,4 @@ function _interopNamespace(e) { var dep = 'dep'; -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(dep)); }); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(dep); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js index c4d91625075..142ab7c0440 100644 --- a/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/amd/main.js @@ -40,9 +40,9 @@ define(['require', './direct-relative-external', 'to-indirect-relative-external' new Promise(function (resolve, reject) { require(['direct-absolute-external'], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); new Promise(function (resolve, reject) { require(['to-indirect-absolute-external'], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); - new Promise(function (resolve, reject) { require(['dynamic-direct-external' + unknown], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })('dynamic-direct-external' + unknown); new Promise(function (resolve, reject) { require(['to-dynamic-indirect-external'], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); Promise.resolve().then(function () { return existing; }); - new Promise(function (resolve, reject) { require(['my' + 'replacement'], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })('my' + 'replacement'); })); diff --git a/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js b/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js index 04fd32660ff..fa4f8e25132 100644 --- a/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js +++ b/test/chunking-form/samples/resolve-dynamic-import/_expected/cjs/main.js @@ -45,7 +45,7 @@ Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(requi Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('direct-absolute-external')); }); Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('to-indirect-absolute-external')); }); -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('dynamic-direct-external' + unknown)); }); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })('dynamic-direct-external' + unknown); Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('to-dynamic-indirect-external')); }); Promise.resolve().then(function () { return existing; }); -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('my' + 'replacement')); }); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })('my' + 'replacement'); diff --git a/test/form/samples/dynamic-import-this-arrow/_config.js b/test/form/samples/dynamic-import-this-arrow/_config.js new file mode 100644 index 00000000000..53ad52318f0 --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_config.js @@ -0,0 +1,12 @@ +const assert = require('assert'); + +module.exports = { + description: 'uses correct "this" in dynamic imports when using arrow functions', + options: { + external: ['input', 'output'], + output: { + generatedCode: { arrowFunctions: true }, + name: 'bundle' + } + } +}; diff --git a/test/form/samples/dynamic-import-this-arrow/_expected/amd.js b/test/form/samples/dynamic-import-this-arrow/_expected/amd.js new file mode 100644 index 00000000000..be311696102 --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_expected/amd.js @@ -0,0 +1,37 @@ +define(['require', 'exports', 'input'], ((require, exports, input) => { 'use strict'; + + function _interopNamespace(e) { + if (e && e.__esModule) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(k => { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: () => e[k] + }); + } + }); + } + n["default"] = e; + return Object.freeze(n); + } + + class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return new Promise((resolve, reject) => require([this.outputPath], m => resolve(/*#__PURE__*/_interopNamespace(m)), reject)); + } + } + + const promise = new Importer().getImport(); + + exports.promise = promise; + + Object.defineProperty(exports, '__esModule', { value: true }); + +})); diff --git a/test/form/samples/dynamic-import-this-arrow/_expected/cjs.js b/test/form/samples/dynamic-import-this-arrow/_expected/cjs.js new file mode 100644 index 00000000000..f12098a1f68 --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_expected/cjs.js @@ -0,0 +1,37 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var input = require('input'); + +function _interopNamespace(e) { + if (e && e.__esModule) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(k => { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: () => e[k] + }); + } + }); + } + n["default"] = e; + return Object.freeze(n); +} + +class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return Promise.resolve().then(() => /*#__PURE__*/_interopNamespace(require(this.outputPath))); + } +} + +const promise = new Importer().getImport(); + +exports.promise = promise; diff --git a/test/form/samples/dynamic-import-this-arrow/_expected/es.js b/test/form/samples/dynamic-import-this-arrow/_expected/es.js new file mode 100644 index 00000000000..256926d1ce5 --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_expected/es.js @@ -0,0 +1,15 @@ +import { outputPath } from 'input'; + +class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return import(this.outputPath); + } +} + +const promise = new Importer().getImport(); + +export { promise }; diff --git a/test/form/samples/dynamic-import-this-arrow/_expected/iife.js b/test/form/samples/dynamic-import-this-arrow/_expected/iife.js new file mode 100644 index 00000000000..ac8fb6deadd --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_expected/iife.js @@ -0,0 +1,22 @@ +var bundle = ((exports, input) => { + 'use strict'; + + class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return import(this.outputPath); + } + } + + const promise = new Importer().getImport(); + + exports.promise = promise; + + Object.defineProperty(exports, '__esModule', { value: true }); + + return exports; + +})({}, input); diff --git a/test/form/samples/dynamic-import-this-arrow/_expected/system.js b/test/form/samples/dynamic-import-this-arrow/_expected/system.js new file mode 100644 index 00000000000..9e7d5ae67cf --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_expected/system.js @@ -0,0 +1,24 @@ +System.register('bundle', ['input'], ((exports, module) => { + 'use strict'; + var outputPath; + return { + setters: [(module => { + outputPath = module.outputPath; + })], + execute: (() => { + + class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return module.import(this.outputPath); + } + } + + const promise = exports('promise', new Importer().getImport()); + + }) + }; +})); diff --git a/test/form/samples/dynamic-import-this-arrow/_expected/umd.js b/test/form/samples/dynamic-import-this-arrow/_expected/umd.js new file mode 100644 index 00000000000..ce1d4c832e2 --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/_expected/umd.js @@ -0,0 +1,23 @@ +((global, factory) => { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('input')) : + typeof define === 'function' && define.amd ? define(['exports', 'input'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.bundle = {}, global.input)); +})(this, ((exports, input) => { 'use strict'; + + class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return import(this.outputPath); + } + } + + const promise = new Importer().getImport(); + + exports.promise = promise; + + Object.defineProperty(exports, '__esModule', { value: true }); + +})); diff --git a/test/form/samples/dynamic-import-this-arrow/main.js b/test/form/samples/dynamic-import-this-arrow/main.js new file mode 100644 index 00000000000..bfe419d7fef --- /dev/null +++ b/test/form/samples/dynamic-import-this-arrow/main.js @@ -0,0 +1,13 @@ +import { outputPath } from 'input'; + +class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return import(this.outputPath); + } +} + +export const promise = new Importer().getImport(); diff --git a/test/form/samples/dynamic-import-this-function/_config.js b/test/form/samples/dynamic-import-this-function/_config.js new file mode 100644 index 00000000000..a43e98dd4e1 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_config.js @@ -0,0 +1,12 @@ +const assert = require('assert'); + +module.exports = { + description: 'uses correct "this" in dynamic imports when not using arrow functions', + options: { + external: ['input', 'output'], + output: { + generatedCode: { arrowFunctions: false }, + name: 'bundle' + } + } +}; diff --git a/test/form/samples/dynamic-import-this-function/_expected/amd.js b/test/form/samples/dynamic-import-this-function/_expected/amd.js new file mode 100644 index 00000000000..23fcff09ce9 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_expected/amd.js @@ -0,0 +1,37 @@ +define(['require', 'exports', 'input'], (function (require, exports, input) { 'use strict'; + + function _interopNamespace(e) { + if (e && e.__esModule) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n["default"] = e; + return Object.freeze(n); + } + + class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(this.outputPath); + } + } + + const promise = new Importer().getImport(); + + exports.promise = promise; + + Object.defineProperty(exports, '__esModule', { value: true }); + +})); diff --git a/test/form/samples/dynamic-import-this-function/_expected/cjs.js b/test/form/samples/dynamic-import-this-function/_expected/cjs.js new file mode 100644 index 00000000000..117701b1226 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_expected/cjs.js @@ -0,0 +1,37 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var input = require('input'); + +function _interopNamespace(e) { + if (e && e.__esModule) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n["default"] = e; + return Object.freeze(n); +} + +class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return (function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(this.outputPath); + } +} + +const promise = new Importer().getImport(); + +exports.promise = promise; diff --git a/test/form/samples/dynamic-import-this-function/_expected/es.js b/test/form/samples/dynamic-import-this-function/_expected/es.js new file mode 100644 index 00000000000..256926d1ce5 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_expected/es.js @@ -0,0 +1,15 @@ +import { outputPath } from 'input'; + +class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return import(this.outputPath); + } +} + +const promise = new Importer().getImport(); + +export { promise }; diff --git a/test/form/samples/dynamic-import-this-function/_expected/iife.js b/test/form/samples/dynamic-import-this-function/_expected/iife.js new file mode 100644 index 00000000000..cae64e05522 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_expected/iife.js @@ -0,0 +1,22 @@ +var bundle = (function (exports, input) { + 'use strict'; + + class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return import(this.outputPath); + } + } + + const promise = new Importer().getImport(); + + exports.promise = promise; + + Object.defineProperty(exports, '__esModule', { value: true }); + + return exports; + +})({}, input); diff --git a/test/form/samples/dynamic-import-this-function/_expected/system.js b/test/form/samples/dynamic-import-this-function/_expected/system.js new file mode 100644 index 00000000000..5a9dab072b8 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_expected/system.js @@ -0,0 +1,24 @@ +System.register('bundle', ['input'], (function (exports, module) { + 'use strict'; + var outputPath; + return { + setters: [(function (module) { + outputPath = module.outputPath; + })], + execute: (function () { + + class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return module.import(this.outputPath); + } + } + + const promise = exports('promise', new Importer().getImport()); + + }) + }; +})); diff --git a/test/form/samples/dynamic-import-this-function/_expected/umd.js b/test/form/samples/dynamic-import-this-function/_expected/umd.js new file mode 100644 index 00000000000..012afb22eb7 --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/_expected/umd.js @@ -0,0 +1,23 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('input')) : + typeof define === 'function' && define.amd ? define(['exports', 'input'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.bundle = {}, global.input)); +})(this, (function (exports, input) { 'use strict'; + + class Importer { + constructor() { + this.outputPath = input.outputPath; + } + + getImport() { + return import(this.outputPath); + } + } + + const promise = new Importer().getImport(); + + exports.promise = promise; + + Object.defineProperty(exports, '__esModule', { value: true }); + +})); diff --git a/test/form/samples/dynamic-import-this-function/main.js b/test/form/samples/dynamic-import-this-function/main.js new file mode 100644 index 00000000000..bfe419d7fef --- /dev/null +++ b/test/form/samples/dynamic-import-this-function/main.js @@ -0,0 +1,13 @@ +import { outputPath } from 'input'; + +class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return import(this.outputPath); + } +} + +export const promise = new Importer().getImport(); diff --git a/test/form/samples/dynamic-import-unresolvable/_expected/amd.js b/test/form/samples/dynamic-import-unresolvable/_expected/amd.js index f12a44a7467..cd966c7cb78 100644 --- a/test/form/samples/dynamic-import-unresolvable/_expected/amd.js +++ b/test/form/samples/dynamic-import-unresolvable/_expected/amd.js @@ -18,9 +18,9 @@ define(['require'], (function (require) { 'use strict'; return Object.freeze(n); } - new Promise(function (resolve, reject) { require([`${globalThis.unknown}`], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); - new Promise(function (resolve, reject) { require([`My ${globalThis.unknown}`], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); - new Promise(function (resolve, reject) { require(['./seven.js'], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(`${globalThis.unknown}`); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(`My ${globalThis.unknown}`); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })('./seven.js'); new Promise(function (resolve, reject) { require(['./seven'], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })); diff --git a/test/form/samples/dynamic-import-unresolvable/_expected/cjs.js b/test/form/samples/dynamic-import-unresolvable/_expected/cjs.js index 215e075895f..b429a06c723 100644 --- a/test/form/samples/dynamic-import-unresolvable/_expected/cjs.js +++ b/test/form/samples/dynamic-import-unresolvable/_expected/cjs.js @@ -18,7 +18,7 @@ function _interopNamespace(e) { return Object.freeze(n); } -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(`${globalThis.unknown}`)); }); -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(`My ${globalThis.unknown}`)); }); -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('./seven.js')); }); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(`${globalThis.unknown}`); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(`My ${globalThis.unknown}`); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })('./seven.js'); Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('./seven.js')); }); diff --git a/test/form/samples/import-expression/_expected/amd.js b/test/form/samples/import-expression/_expected/amd.js index 5498b55471d..79f3a8027c6 100644 --- a/test/form/samples/import-expression/_expected/amd.js +++ b/test/form/samples/import-expression/_expected/amd.js @@ -18,7 +18,7 @@ define(['require', 'external'], (function (require, external) { 'use strict'; return Object.freeze(n); } - new Promise(function (resolve, reject) { require([external.join('a', 'b')], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(external.join('a', 'b')); console.log(external.join); })); diff --git a/test/form/samples/import-expression/_expected/cjs.js b/test/form/samples/import-expression/_expected/cjs.js index 0d3c03ebd3f..c4267c6cbea 100644 --- a/test/form/samples/import-expression/_expected/cjs.js +++ b/test/form/samples/import-expression/_expected/cjs.js @@ -20,5 +20,5 @@ function _interopNamespace(e) { return Object.freeze(n); } -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(external.join('a', 'b'))); }); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(external.join('a', 'b')); console.log(external.join); diff --git a/test/form/samples/interop-per-dependency/_expected/amd.js b/test/form/samples/interop-per-dependency/_expected/amd.js index 3a0530851fe..649176f2a55 100644 --- a/test/form/samples/interop-per-dependency/_expected/amd.js +++ b/test/form/samples/interop-per-dependency/_expected/amd.js @@ -34,7 +34,7 @@ define(['require', 'external-auto', 'external-default', 'external-defaultOnly', new Promise(function (resolve, reject) { require(['external-default'], function (m) { resolve(/*#__PURE__*/_interopNamespaceDefault(m)); }, reject); }).then(console.log); new Promise(function (resolve, reject) { require(['external-defaultOnly'], function (m) { resolve(/*#__PURE__*/_interopNamespaceDefaultOnly(m)); }, reject); }).then(console.log); new Promise(function (resolve, reject) { require(['external-esModule'], resolve, reject); }).then(console.log); - new Promise(function (resolve, reject) { require([globalThis.external1], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }).then(console.log); - new Promise(function (resolve, reject) { require([globalThis.external2], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }).then(console.log); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(globalThis.external1).then(console.log); + (function (t) { return new Promise(function (resolve, reject) { require([t], function (m) { resolve(/*#__PURE__*/_interopNamespace(m)); }, reject); }); })(globalThis.external2).then(console.log); })); diff --git a/test/form/samples/interop-per-dependency/_expected/cjs.js b/test/form/samples/interop-per-dependency/_expected/cjs.js index 17e8cfe232e..f3588f7f33e 100644 --- a/test/form/samples/interop-per-dependency/_expected/cjs.js +++ b/test/form/samples/interop-per-dependency/_expected/cjs.js @@ -39,5 +39,5 @@ Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(requi Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefault(require('external-default')); }).then(console.log); Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('external-defaultOnly')); }).then(console.log); Promise.resolve().then(function () { return require('external-esModule'); }).then(console.log); -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(globalThis.external1)); }).then(console.log); -Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(globalThis.external2)); }).then(console.log); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(globalThis.external1).then(console.log); +(function (t) { return Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require(t)); }); })(globalThis.external2).then(console.log); diff --git a/test/function/samples/dynamic-import-this-arrow/_config.js b/test/function/samples/dynamic-import-this-arrow/_config.js new file mode 100644 index 00000000000..0135981db4e --- /dev/null +++ b/test/function/samples/dynamic-import-this-arrow/_config.js @@ -0,0 +1,26 @@ +const assert = require('assert'); + +module.exports = { + description: 'uses correct "this" in dynamic imports when using arrow functions', + context: { + require(id) { + switch (id) { + case 'input': + return { outputPath: 'output' }; + case 'output': + return { foo: 42 }; + default: + throw new Error(`Unexpected require "${id}"`); + } + } + }, + exports({ promise }) { + return promise.then(({ foo }) => assert.strictEqual(foo, 42)); + }, + options: { + external: ['input', 'output'], + output: { + generatedCode: { arrowFunctions: true } + } + } +}; diff --git a/test/function/samples/dynamic-import-this-arrow/main.js b/test/function/samples/dynamic-import-this-arrow/main.js new file mode 100644 index 00000000000..bfe419d7fef --- /dev/null +++ b/test/function/samples/dynamic-import-this-arrow/main.js @@ -0,0 +1,13 @@ +import { outputPath } from 'input'; + +class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return import(this.outputPath); + } +} + +export const promise = new Importer().getImport(); diff --git a/test/function/samples/dynamic-import-this-function/_config.js b/test/function/samples/dynamic-import-this-function/_config.js new file mode 100644 index 00000000000..200aed65846 --- /dev/null +++ b/test/function/samples/dynamic-import-this-function/_config.js @@ -0,0 +1,26 @@ +const assert = require('assert'); + +module.exports = { + description: 'uses correct "this" in dynamic imports when not using arrow functions', + context: { + require(id) { + switch (id) { + case 'input': + return { outputPath: 'output' }; + case 'output': + return { foo: 42 }; + default: + throw new Error(`Unexpected require "${id}"`); + } + } + }, + exports({ promise }) { + return promise.then(({ foo }) => assert.strictEqual(foo, 42)); + }, + options: { + external: ['input', 'output'], + output: { + generatedCode: { arrowFunctions: false } + } + } +}; diff --git a/test/function/samples/dynamic-import-this-function/main.js b/test/function/samples/dynamic-import-this-function/main.js new file mode 100644 index 00000000000..bfe419d7fef --- /dev/null +++ b/test/function/samples/dynamic-import-this-function/main.js @@ -0,0 +1,13 @@ +import { outputPath } from 'input'; + +class Importer { + constructor() { + this.outputPath = outputPath; + } + + getImport() { + return import(this.outputPath); + } +} + +export const promise = new Importer().getImport();