Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define __esModule interop flag when requiring ES module from CommonJS #2993

Merged
merged 2 commits into from May 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1 @@
module.exports = require('./b');
@@ -0,0 +1 @@
export default 2;
13 changes: 13 additions & 0 deletions packages/core/integration-tests/test/scope-hoisting.js
Expand Up @@ -1203,5 +1203,18 @@ describe('scope hoisting', function() {
let output = await run(b);
assert.deepEqual(output, 42);
});

it('should insert __esModule interop flag when importing from an ES module', async function() {
let b = await bundle(
path.join(
__dirname,
'/integration/scope-hoisting/commonjs/interop-require-es-module/a.js'
)
);

let output = await run(b);
assert.equal(output.__esModule, true);
assert.equal(output.default, 2);
});
});
});
3 changes: 2 additions & 1 deletion packages/core/parcel-bundler/src/Asset.js
Expand Up @@ -9,6 +9,7 @@ const syncPromise = require('./utils/syncPromise');
const logger = require('@parcel/logger');
const Resolver = require('./Resolver');
const objectHash = require('./utils/objectHash');
const t = require('babel-types');

/**
* An Asset represents a file in the dependency tree. Assets can have multiple
Expand Down Expand Up @@ -204,7 +205,7 @@ class Asset {
if (!this.id) {
this.id =
this.options.production || this.options.scopeHoist
? md5(this.relativeName, 'base64').slice(0, 4)
? t.toIdentifier(md5(this.relativeName, 'base64')).slice(0, 4)
: this.relativeName;
}

Expand Down
4 changes: 4 additions & 0 deletions packages/core/parcel-bundler/src/builtins/helpers.js
Expand Up @@ -4,6 +4,10 @@ function $parcel$interopDefault(a) {
: {d: a};
}

function $parcel$defineInteropFlag(a) {
Object.defineProperty(a, '__esModule', {value: true});
}

function $parcel$exportWildcard(dest, source) {
Object.keys(source).forEach(function(key) {
if(key === "default" || key === "__esModule") {
Expand Down
27 changes: 26 additions & 1 deletion packages/core/parcel-bundler/src/scope-hoisting/concat.js
Expand Up @@ -9,6 +9,7 @@ const {getName, getIdentifier} = require('./utils');

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

const ESMODULE_TEMPLATE = template(`$parcel$defineInteropFlag(EXPORTS);`);
const DEFAULT_INTEROP_TEMPLATE = template(
'var NAME = $parcel$interopDefault(MODULE)'
);
Expand Down Expand Up @@ -142,10 +143,11 @@ module.exports = (packager, ast) => {
);
}

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

if (!mod) {
if (assets.get(id.value).dependencies.get(source.value).optional) {
if (asset.dependencies.get(source.value).optional) {
path.replaceWith(
THROW_TEMPLATE({MODULE: t.stringLiteral(source.value)})
);
Expand All @@ -161,6 +163,29 @@ module.exports = (packager, ast) => {
if (!isUnusedValue(path)) {
let name = getName(mod, 'exports');
node = t.identifier(replacements.get(name) || name);

// Insert __esModule interop flag if the required module is an ES6 module with a default export.
// This ensures that code generated by Babel and other tools works properly.
if (
asset.cacheData.isCommonJS &&
mod.cacheData.isES6Module &&
mod.cacheData.exports.default
) {
let binding = path.scope.getBinding(name);
if (binding && !binding.path.getData('hasESModuleFlag')) {
if (binding.path.node.init) {
binding.path
.getStatementParent()
.insertAfter(ESMODULE_TEMPLATE({EXPORTS: name}));
}

for (let path of binding.constantViolations) {
path.insertAfter(ESMODULE_TEMPLATE({EXPORTS: name}));
}

binding.path.setData('hasESModuleFlag', true);
}
}
}

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