Skip to content

Commit 754cda3

Browse files
authored
Merge pull request webpack#6050 from webpack/bugfix/import-cjs
handle non-esm correctly in import()
2 parents 803664e + 3803c8a commit 754cda3

File tree

43 files changed

+396
-64
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+396
-64
lines changed

lib/ContextModule.js

Lines changed: 112 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class ContextModule extends Module {
6666

6767
identifier() {
6868
let identifier = this.context;
69+
if(this.options.resourceQuery)
70+
identifier += ` ${this.options.resourceQuery}`;
6971
if(this.options.mode)
7072
identifier += ` ${this.options.mode}`;
7173
if(!this.options.recursive)
@@ -78,12 +80,18 @@ class ContextModule extends Module {
7880
identifier += ` include: ${this.options.include}`;
7981
if(this.options.exclude)
8082
identifier += ` exclude: ${this.options.exclude}`;
83+
if(this.options.namespaceObject === "strict")
84+
identifier += " strict namespace object";
85+
else if(this.options.namespaceObject)
86+
identifier += " namespace object";
8187

8288
return identifier;
8389
}
8490

8591
readableIdentifier(requestShortener) {
8692
let identifier = requestShortener.shorten(this.context);
93+
if(this.options.resourceQuery)
94+
identifier += ` ${this.options.resourceQuery}`;
8795
if(this.options.mode)
8896
identifier += ` ${this.options.mode}`;
8997
if(!this.options.recursive)
@@ -96,6 +104,10 @@ class ContextModule extends Module {
96104
identifier += ` include: ${this.prettyRegExp(this.options.include + "")}`;
97105
if(this.options.exclude)
98106
identifier += ` exclude: ${this.prettyRegExp(this.options.exclude + "")}`;
107+
if(this.options.namespaceObject === "strict")
108+
identifier += " strict namespace object";
109+
else if(this.options.namespaceObject)
110+
identifier += " namespace object";
99111

100112
return identifier;
101113
}
@@ -214,18 +226,60 @@ class ContextModule extends Module {
214226
}, Object.create(null));
215227
}
216228

229+
getFakeMap(dependencies) {
230+
if(!this.options.namespaceObject) return false;
231+
// if we filter first we get a new array
232+
// therefor we dont need to create a clone of dependencies explicitly
233+
// therefore the order of this is !important!
234+
let hasNonHarmony = false;
235+
let hasHarmony = false;
236+
const fakeMap = dependencies
237+
.filter(dependency => dependency.module)
238+
.sort((a, b) => {
239+
return b.module.id - a.module.id;
240+
}).reduce((map, dep) => {
241+
const harmonyModule = dep.module.meta && dep.module.meta.harmonyModule;
242+
if(!harmonyModule) hasNonHarmony = true;
243+
if(harmonyModule) hasHarmony = true;
244+
map[dep.module.id] = harmonyModule ? 0 : 1;
245+
return map;
246+
}, Object.create(null));
247+
if(hasHarmony && !hasNonHarmony) return false;
248+
if(!hasHarmony && hasNonHarmony) return true;
249+
return fakeMap;
250+
}
251+
252+
getModuleObjectSource(fakeMap, fakeMapDataExpression = "fakeMap[id]") {
253+
const strict = this.options.namespaceObject === "strict";
254+
if(strict) {
255+
if(fakeMap === true) return "/* fake namespace object */ { \"default\": module }";
256+
if(fakeMap) return `${fakeMapDataExpression} ? /* fake namespace object */ { "default": module } : module`;
257+
} else {
258+
if(fakeMap === true) return "typeof module !== \"object\" || !module.__esModule ? /* fake namespace object */ { \"default\": module } : module;";
259+
if(fakeMap) return `${fakeMapDataExpression} && (typeof module !== "object" || !module.__esModule) ? /* fake namespace object */ { "default": module } : module;`;
260+
}
261+
return "module";
262+
}
263+
217264
getSyncSource(dependencies, id) {
218265
const map = this.getUserRequestMap(dependencies);
266+
const fakeMap = this.getFakeMap(dependencies);
267+
const returnModuleObject = `return ${this.getModuleObjectSource(fakeMap)};`;
268+
219269
return `var map = ${JSON.stringify(map, null, "\t")};
270+
${typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : ""}
271+
220272
function webpackContext(req) {
221-
return __webpack_require__(webpackContextResolve(req));
222-
};
273+
var id = webpackContextResolve(req);
274+
var module = __webpack_require__(id);
275+
${returnModuleObject}
276+
}
223277
function webpackContextResolve(req) {
224278
var id = map[req];
225279
if(!(id + 1)) // check for number or string
226280
throw new Error("Cannot find module '" + req + "'.");
227281
return id;
228-
};
282+
}
229283
webpackContext.keys = function webpackContextKeys() {
230284
return Object.keys(map);
231285
};
@@ -236,19 +290,25 @@ webpackContext.id = ${JSON.stringify(id)};`;
236290

237291
getWeakSyncSource(dependencies, id) {
238292
const map = this.getUserRequestMap(dependencies);
293+
const fakeMap = this.getFakeMap(dependencies);
294+
const returnModuleObject = `return ${this.getModuleObjectSource(fakeMap)};`;
295+
239296
return `var map = ${JSON.stringify(map, null, "\t")};
297+
${typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : ""}
298+
240299
function webpackContext(req) {
241300
var id = webpackContextResolve(req);
242301
if(!__webpack_require__.m[id])
243302
throw new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)");
244-
return __webpack_require__(id);
245-
};
303+
var module = __webpack_require__(id);
304+
${returnModuleObject}
305+
}
246306
function webpackContextResolve(req) {
247307
var id = map[req];
248308
if(!(id + 1)) // check for number or string
249309
throw new Error("Cannot find module '" + req + "'.");
250310
return id;
251-
};
311+
}
252312
webpackContext.keys = function webpackContextKeys() {
253313
return Object.keys(map);
254314
};
@@ -259,15 +319,20 @@ module.exports = webpackContext;`;
259319

260320
getAsyncWeakSource(dependencies, id) {
261321
const map = this.getUserRequestMap(dependencies);
322+
const fakeMap = this.getFakeMap(dependencies);
323+
const returnModuleObject = `return ${this.getModuleObjectSource(fakeMap)};`;
262324

263325
return `var map = ${JSON.stringify(map, null, "\t")};
326+
${typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : ""}
327+
264328
function webpackAsyncContext(req) {
265329
return webpackAsyncContextResolve(req).then(function(id) {
266330
if(!__webpack_require__.m[id])
267331
throw new Error("Module '" + req + "' ('" + id + "') is not available (weak dependency)");
268-
return __webpack_require__(id);
332+
var module = __webpack_require__(id);
333+
${returnModuleObject}
269334
});
270-
};
335+
}
271336
function webpackAsyncContextResolve(req) {
272337
// Here Promise.resolve().then() is used instead of new Promise() to prevent
273338
// uncatched exception popping up in devtools
@@ -277,7 +342,7 @@ function webpackAsyncContextResolve(req) {
277342
throw new Error("Cannot find module '" + req + "'.");
278343
return id;
279344
});
280-
};
345+
}
281346
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
282347
return Object.keys(map);
283348
};
@@ -288,10 +353,19 @@ module.exports = webpackAsyncContext;`;
288353

289354
getEagerSource(dependencies, id) {
290355
const map = this.getUserRequestMap(dependencies);
356+
const fakeMap = this.getFakeMap(dependencies);
357+
const thenFunction = fakeMap ?
358+
`function(id) {
359+
var module = __webpack_require__(id);
360+
return ${this.getModuleObjectSource(fakeMap)};
361+
}` :
362+
"__webpack_require__";
291363
return `var map = ${JSON.stringify(map, null, "\t")};
364+
${typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : ""}
365+
292366
function webpackAsyncContext(req) {
293-
return webpackAsyncContextResolve(req).then(__webpack_require__);
294-
};
367+
return webpackAsyncContextResolve(req).then(${thenFunction});
368+
}
295369
function webpackAsyncContextResolve(req) {
296370
// Here Promise.resolve().then() is used instead of new Promise() to prevent
297371
// uncatched exception popping up in devtools
@@ -301,7 +375,7 @@ function webpackAsyncContextResolve(req) {
301375
throw new Error("Cannot find module '" + req + "'.");
302376
return id;
303377
});
304-
};
378+
}
305379
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
306380
return Object.keys(map);
307381
};
@@ -313,18 +387,28 @@ module.exports = webpackAsyncContext;`;
313387
getLazyOnceSource(block, dependencies, id, outputOptions, requestShortener) {
314388
const promise = DepBlockHelpers.getDepBlockPromise(block, outputOptions, requestShortener, "lazy-once context");
315389
const map = this.getUserRequestMap(dependencies);
390+
const fakeMap = this.getFakeMap(dependencies);
391+
const thenFunction = fakeMap ?
392+
`function(id) {
393+
var module = __webpack_require__(id);
394+
return ${this.getModuleObjectSource(fakeMap)};
395+
}` :
396+
"__webpack_require__";
397+
316398
return `var map = ${JSON.stringify(map, null, "\t")};
399+
${typeof fakeMap === "object" ? `var fakeMap = ${JSON.stringify(fakeMap, null, "\t")};` : ""}
400+
317401
function webpackAsyncContext(req) {
318-
return webpackAsyncContextResolve(req).then(__webpack_require__);
319-
};
402+
return webpackAsyncContextResolve(req).then(${thenFunction});
403+
}
320404
function webpackAsyncContextResolve(req) {
321405
return ${promise}.then(function() {
322406
var id = map[req];
323407
if(!(id + 1)) // check for number or string
324408
throw new Error("Cannot find module '" + req + "'.");
325409
return id;
326410
});
327-
};
411+
}
328412
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
329413
return Object.keys(map);
330414
};
@@ -335,6 +419,7 @@ module.exports = webpackAsyncContext;`;
335419

336420
getLazySource(blocks, id) {
337421
let hasMultipleOrNoChunks = false;
422+
const fakeMap = this.getFakeMap(blocks.map(b => b.dependencies[0]));
338423
const map = blocks
339424
.filter(block => block.dependencies[0].module)
340425
.map((block) => ({
@@ -349,25 +434,31 @@ module.exports = webpackAsyncContext;`;
349434
if(chunks.length !== 1) {
350435
hasMultipleOrNoChunks = true;
351436
}
352-
map[item.userRequest] = [item.dependency.module.id]
437+
const arrayStart = [item.dependency.module.id];
438+
if(typeof fakeMap === "object")
439+
arrayStart.push(fakeMap[item.dependency.module.id]);
440+
map[item.userRequest] = arrayStart
353441
.concat(chunks.map(chunk => chunk.id));
354442

355443
return map;
356444
}, Object.create(null));
357445

446+
const chunksStartPosition = typeof fakeMap === "object" ? 2 : 1;
358447
const requestPrefix = hasMultipleOrNoChunks ?
359-
"Promise.all(ids.slice(1).map(__webpack_require__.e))" :
360-
"__webpack_require__.e(ids[1])";
448+
`Promise.all(ids.slice(${chunksStartPosition}).map(__webpack_require__.e))` :
449+
`__webpack_require__.e(ids[${chunksStartPosition}])`;
450+
const returnModuleObject = `return ${this.getModuleObjectSource(fakeMap, "ids[1]")};`;
361451

362452
return `var map = ${JSON.stringify(map, null, "\t")};
363453
function webpackAsyncContext(req) {
364454
var ids = map[req];
365455
if(!ids)
366-
return Promise.reject(new Error("Cannot find module '" + req + "'."));
456+
return Promise.resolve().then(function() { throw new Error("Cannot find module '" + req + "'."); });
367457
return ${requestPrefix}.then(function() {
368-
return __webpack_require__(ids[0]);
458+
var module = __webpack_require__(ids[0]);
459+
${returnModuleObject}
369460
});
370-
};
461+
}
371462
webpackAsyncContext.keys = function webpackAsyncContextKeys() {
372463
return Object.keys(map);
373464
};

lib/dependencies/ContextDependencyTemplateAsRequireCall.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const Template = require("../Template");
99
class ContextDependencyTemplateAsRequireCall {
1010

1111
apply(dep, source, outputOptions, requestShortener) {
12-
const comment = outputOptions.pathinfo ? Template.toComment(requestShortener.shorten(dep.request)) + " " : "";
12+
const comment = outputOptions.pathinfo ? Template.toComment(requestShortener.shorten(dep.options.request)) + " " : "";
1313

1414
const containsDeps = dep.module && dep.module.dependencies && dep.module.dependencies.length > 0;
1515
const isAsync = dep.options.mode !== "sync" && dep.options.mode !== "weak";

lib/dependencies/DepBlockHelpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ DepBlockHelpers.getDepBlockPromise = (depBlock, outputOptions, requestShortener,
3232
return `Promise.all${name}(${pathChunkCheck ? Template.toComment(shortChunkName) : ""}[${chunks.map(requireChunkId).join(", ")}])`;
3333
}
3434
}
35-
return "new Promise(function(resolve) { resolve(); })";
35+
return "Promise.resolve()";
3636
};

lib/dependencies/ImportDependenciesBlock.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
77
const ImportDependency = require("./ImportDependency");
88

99
module.exports = class ImportDependenciesBlock extends AsyncDependenciesBlock {
10-
constructor(request, range, chunkName, module, loc) {
10+
constructor(request, range, chunkName, module, loc, originModule) {
1111
super(chunkName, module, loc);
1212
this.range = range;
13-
const dep = new ImportDependency(request, this);
13+
const dep = new ImportDependency(request, originModule, this);
1414
dep.loc = loc;
1515
this.addDependency(dep);
1616
}

lib/dependencies/ImportDependency.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ const DepBlockHelpers = require("./DepBlockHelpers");
99
const webpackMissingPromiseModule = require("./WebpackMissingModule").promise;
1010

1111
class ImportDependency extends ModuleDependency {
12-
constructor(request, block) {
12+
constructor(request, originModule, block) {
1313
super(request);
14+
this.originModule = originModule;
1415
this.block = block;
1516
}
1617

@@ -30,14 +31,19 @@ ImportDependency.Template = class ImportDependencyTemplate {
3031
}
3132

3233
getContent(promise, dep, comment) {
33-
if(promise && dep.module) {
34-
const stringifiedId = JSON.stringify(dep.module.id);
35-
return `${promise}.then(__webpack_require__.bind(null, ${comment}${stringifiedId}))`;
36-
}
34+
let getModuleFunction;
3735

3836
if(dep.module) {
3937
const stringifiedId = JSON.stringify(dep.module.id);
40-
return `new Promise(function(resolve) { resolve(__webpack_require__(${comment}${stringifiedId})); })`;
38+
if(dep.module.meta && dep.module.meta.harmonyModule) {
39+
getModuleFunction = `__webpack_require__.bind(null, ${comment}${stringifiedId})`;
40+
} else if(dep.originModule.meta.strictHarmonyModule) {
41+
getModuleFunction = `function() { return /* fake namespace object */ { "default": __webpack_require__(${comment}${stringifiedId}) }; }`;
42+
} else {
43+
getModuleFunction = `function() { var m = __webpack_require__(${comment}${stringifiedId}); return m && typeof m === "object" && m.__esModule ? m : /* fake namespace object */ { "default": m }; }`;
44+
}
45+
46+
return `${promise || "Promise.resolve()"}.then(${getModuleFunction})`;
4147
}
4248

4349
return webpackMissingPromiseModule(dep.request);

lib/dependencies/ImportParserPlugin.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class ImportParserPlugin {
7272
const dep = new ImportWeakDependency(param.string, expr.range);
7373
parser.state.current.addDependency(dep);
7474
} else {
75-
const depBlock = new ImportDependenciesBlock(param.string, expr.range, chunkName, parser.state.module, expr.loc);
75+
const depBlock = new ImportDependenciesBlock(param.string, expr.range, chunkName, parser.state.module, expr.loc, parser.state.module);
7676
parser.state.current.addBlock(depBlock);
7777
}
7878
return true;
@@ -89,7 +89,8 @@ class ImportParserPlugin {
8989
chunkName,
9090
include,
9191
exclude,
92-
mode
92+
mode,
93+
namespaceObject: parser.state.module.meta.strictHarmonyModule ? "strict" : true
9394
});
9495
if(!dep) return;
9596
dep.loc = expr.loc;

test/cases/chunks/import-context/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function testCase(load, done) {
2323
it("should be able to use expressions in import", function(done) {
2424
function load(name, expected, callback) {
2525
import("./dir/" + name).then(function(result) {
26-
result.should.be.eql(expected);
26+
result.should.be.eql({ default: expected });
2727
callback();
2828
}).catch(function(err) {
2929
done(err);
@@ -35,7 +35,7 @@ it("should be able to use expressions in import", function(done) {
3535
it("should be able to use expressions in System.import", function(done) {
3636
function load(name, expected, callback) {
3737
System.import("./dir2/" + name).then(function(result) {
38-
result.should.be.eql(expected);
38+
result.should.be.eql({ default: expected });
3939
callback();
4040
}).catch(function(err) {
4141
done(err);

test/cases/chunks/import/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
it("should be able to use import", function(done) {
22
import("./two").then(function(two) {
3-
two.should.be.eql(2);
3+
two.should.be.eql({ default: 2 });
44
done();
55
}).catch(function(err) {
66
done(err);
@@ -9,7 +9,7 @@ it("should be able to use import", function(done) {
99

1010
it("should be able to use System.import", function(done) {
1111
System.import("./two").then(function(two) {
12-
two.should.be.eql(2);
12+
two.should.be.eql({ default: 2 });
1313
done();
1414
}).catch(function(err) {
1515
done(err);

0 commit comments

Comments
 (0)