Skip to content

Commit 84b3085

Browse files
authored
Define __esModule interop flag when requiring ES module from CommonJS (#2993)
1 parent a50ddd5 commit 84b3085

File tree

6 files changed

+47
-2
lines changed

6 files changed

+47
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require('./b');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default 2;

packages/core/integration-tests/test/scope-hoisting.js

+13
Original file line numberDiff line numberDiff line change
@@ -1204,5 +1204,18 @@ describe('scope hoisting', function() {
12041204
let output = await run(b);
12051205
assert.deepEqual(output, 42);
12061206
});
1207+
1208+
it('should insert __esModule interop flag when importing from an ES module', async function() {
1209+
let b = await bundle(
1210+
path.join(
1211+
__dirname,
1212+
'/integration/scope-hoisting/commonjs/interop-require-es-module/a.js'
1213+
)
1214+
);
1215+
1216+
let output = await run(b);
1217+
assert.equal(output.__esModule, true);
1218+
assert.equal(output.default, 2);
1219+
});
12071220
});
12081221
});

packages/core/parcel-bundler/src/Asset.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const syncPromise = require('./utils/syncPromise');
99
const logger = require('@parcel/logger');
1010
const Resolver = require('./Resolver');
1111
const objectHash = require('./utils/objectHash');
12+
const t = require('babel-types');
1213

1314
/**
1415
* An Asset represents a file in the dependency tree. Assets can have multiple
@@ -204,7 +205,7 @@ class Asset {
204205
if (!this.id) {
205206
this.id =
206207
this.options.production || this.options.scopeHoist
207-
? md5(this.relativeName, 'base64').slice(0, 4)
208+
? t.toIdentifier(md5(this.relativeName, 'base64')).slice(0, 4)
208209
: this.relativeName;
209210
}
210211

packages/core/parcel-bundler/src/builtins/helpers.js

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ function $parcel$interopDefault(a) {
44
: {d: a};
55
}
66

7+
function $parcel$defineInteropFlag(a) {
8+
Object.defineProperty(a, '__esModule', {value: true});
9+
}
10+
711
function $parcel$exportWildcard(dest, source) {
812
Object.keys(source).forEach(function(key) {
913
if(key === "default" || key === "__esModule") {

packages/core/parcel-bundler/src/scope-hoisting/concat.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const {getName, getIdentifier} = require('./utils');
99

1010
const EXPORTS_RE = /^\$([^$]+)\$exports$/;
1111

12+
const ESMODULE_TEMPLATE = template(`$parcel$defineInteropFlag(EXPORTS);`);
1213
const DEFAULT_INTEROP_TEMPLATE = template(
1314
'var NAME = $parcel$interopDefault(MODULE)'
1415
);
@@ -142,10 +143,11 @@ module.exports = (packager, ast) => {
142143
);
143144
}
144145

146+
let asset = assets.get(id.value);
145147
let mod = packager.resolveModule(id.value, source.value);
146148

147149
if (!mod) {
148-
if (assets.get(id.value).dependencies.get(source.value).optional) {
150+
if (asset.dependencies.get(source.value).optional) {
149151
path.replaceWith(
150152
THROW_TEMPLATE({MODULE: t.stringLiteral(source.value)})
151153
);
@@ -161,6 +163,29 @@ module.exports = (packager, ast) => {
161163
if (!isUnusedValue(path)) {
162164
let name = getName(mod, 'exports');
163165
node = t.identifier(replacements.get(name) || name);
166+
167+
// Insert __esModule interop flag if the required module is an ES6 module with a default export.
168+
// This ensures that code generated by Babel and other tools works properly.
169+
if (
170+
asset.cacheData.isCommonJS &&
171+
mod.cacheData.isES6Module &&
172+
mod.cacheData.exports.default
173+
) {
174+
let binding = path.scope.getBinding(name);
175+
if (binding && !binding.path.getData('hasESModuleFlag')) {
176+
if (binding.path.node.init) {
177+
binding.path
178+
.getStatementParent()
179+
.insertAfter(ESMODULE_TEMPLATE({EXPORTS: name}));
180+
}
181+
182+
for (let path of binding.constantViolations) {
183+
path.insertAfter(ESMODULE_TEMPLATE({EXPORTS: name}));
184+
}
185+
186+
binding.path.setData('hasESModuleFlag', true);
187+
}
188+
}
164189
}
165190

166191
// We need to wrap the module in a function when a require

0 commit comments

Comments
 (0)