Skip to content

Commit f44ed80

Browse files
committed
more reliable in parsing AMD stuff
fixes webpack#138
1 parent 6d7ac9e commit f44ed80

File tree

3 files changed

+77
-30
lines changed

3 files changed

+77
-30
lines changed

lib/dependencies/AMDDefineDependency.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
*/
55
var NullDependency = require("./NullDependency");
66

7-
function AMDDefineDependency(range, arrayRange, functionRange) {
7+
function AMDDefineDependency(range, arrayRange, functionRange, objectRange) {
88
NullDependency.call(this);
99
this.Class = AMDDefineDependency;
1010
this.range = range;
1111
this.arrayRange = arrayRange;
1212
this.functionRange = functionRange;
13+
this.objectRange = objectRange;
1314
}
1415
module.exports = AMDDefineDependency;
1516

@@ -19,20 +20,25 @@ AMDDefineDependency.prototype.type = "amd define";
1920
AMDDefineDependency.Template = function AMDRequireDependencyTemplate() {};
2021

2122
AMDDefineDependency.Template.prototype.apply = function(dep, source, outputOptions, requestShortener) {
22-
if(dep.arrayRange && !dep.functionRange) {
23-
source.replace(dep.range[0], dep.arrayRange[0]-1,
23+
if(dep.objectRange && !dep.functionRange) {
24+
source.replace(dep.range[0], dep.objectRange[0]-1,
2425
"(module.exports = ");
25-
source.replace(dep.arrayRange[1], dep.range[1]-1, ")");
26-
} else if(!dep.arrayRange && dep.functionRange) {
26+
source.replace(dep.objectRange[1], dep.range[1]-1, ")");
27+
} else if(!dep.arrayRange && dep.functionRange && !dep.objectRange) {
2728
source.replace(dep.range[0], dep.functionRange[0]-1,
2829
"(__WEBPACK_AMD_DEFINE_RESULT__ = (");
2930
source.insert(0, "var __WEBPACK_AMD_DEFINE_RESULT__;");
30-
source.replace(dep.functionRange[1], dep.range[1]-1, "(require, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))");
31-
} else if(dep.arrayRange && dep.functionRange) {
31+
source.replace(dep.functionRange[1], dep.range[1]-1, ".call(exports, require, exports, module)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))");
32+
} else if(dep.arrayRange && dep.functionRange && !dep.objectRange) {
3233
source.replace(dep.range[0], dep.arrayRange[0]-1,
3334
"(__WEBPACK_AMD_DEFINE_ARRAY__ = ");
3435
source.insert(0, "var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;");
3536
source.replace(dep.arrayRange[1], dep.functionRange[0]-1, ", __WEBPACK_AMD_DEFINE_RESULT__ = (");
3637
source.replace(dep.functionRange[1], dep.range[1]-1, ".apply(null, __WEBPACK_AMD_DEFINE_ARRAY__)), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))");
38+
} else if(dep.functionRange && dep.objectRange) {
39+
source.replace(dep.range[0], dep.functionRange[0]-1,
40+
"(__WEBPACK_AMD_DEFINE_FACTORY__ = (");
41+
source.insert(0, "var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;");
42+
source.replace(dep.functionRange[1], dep.range[1]-1, "), (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_RESULT__ = __WEBPACK_AMD_DEFINE_FACTORY__.call(null), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) : module.exports = __WEBPACK_AMD_DEFINE_FACTORY__))");
3743
}
3844
};

lib/dependencies/AMDDefineDependencyParserPlugin.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,48 @@ var ContextDependencyHelpers = require("./ContextDependencyHelpers");
1111

1212
module.exports = AbstractPlugin.create({
1313
"call define": function(expr) {
14-
var array, fn;
14+
var array, fn, obj;
1515
switch(expr.arguments.length) {
1616
case 1:
1717
if(expr.arguments[0].type == "FunctionExpression") {
1818
// define(f() {...})
1919
fn = expr.arguments[0];
20-
} else {
20+
} else if(expr.arguments[0].type === "ObjectExpression") {
2121
// define({...})
22-
var dep = new AMDDefineDependency(expr.range, expr.arguments[0].range);
23-
dep.loc = expr.loc;
24-
this.state.current.addDependency(dep);
25-
return true;
22+
obj = expr.arguments[0];
23+
} else {
24+
// define(expr)
25+
// unclear if function or object
26+
obj = fn = expr.arguments[0];
2627
}
2728
break;
2829
case 2:
2930
if(expr.arguments[0].type === "Literal") {
30-
if(expr.arguments[1].type == "FunctionExpression") {
31+
// define("...", ...)
32+
if(expr.arguments[1].type === "FunctionExpression") {
3133
// define("...", f() {...})
3234
fn = expr.arguments[1];
33-
} else {
35+
} else if(expr.arguments[1].type === "ObjectExpression") {
3436
// define("...", {...})
35-
var dep = new AMDDefineDependency(expr.range, expr.arguments[1].range);
36-
dep.loc = expr.loc;
37-
this.state.current.addDependency(dep);
38-
return true;
39-
}
40-
} else {
41-
if(expr.arguments[1].type == "FunctionExpression") {
42-
// define([...], f() {...})
43-
array = expr.arguments[0];
44-
fn = expr.arguments[1];
37+
obj = expr.arguments[1];
4538
} else {
46-
return;
39+
// define("...", expr)
40+
// unclear if function or object
41+
obj = fn = expr.arguments[1];
4742
}
43+
} else {
44+
// define([...], f() {})
45+
array = expr.arguments[0];
46+
fn = expr.arguments[1];
4847
}
4948
break;
5049
case 3:
5150
// define("...", [...], f() {...})
5251
array = expr.arguments[1];
5352
fn = expr.arguments[2];
5453
break;
54+
default: return;
5555
}
56-
if(!array && !fn) return;
5756
if(array) {
5857
var param = this.evaluateExpression(array);
5958
var result = this.applyPluginsBailResult("call define:amd:array", expr, param);
@@ -70,8 +69,10 @@ module.exports = AbstractPlugin.create({
7069
else
7170
this.walkExpression(fn.body);
7271
}.bind(this));
72+
} else if(fn || obj) {
73+
this.walkExpression(fn || obj);
7374
}
74-
var dep = new AMDDefineDependency(expr.range, array ? array.range : null, fn ? fn.range : null);
75+
var dep = new AMDDefineDependency(expr.range, array ? array.range : null, fn ? fn.range : null, obj ? obj.range : null);
7576
dep.loc = expr.loc;
7677
this.state.current.addDependency(dep);
7778
return true;

test/cases/parsing/extract-amd/index.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,36 +35,60 @@ it("should be able to use AMD-style require", function(done) {
3535
done();
3636
});
3737
});
38+
3839
it("should be able to use require.js-style define", function(done) {
3940
define("name", ["./circular"], function(circular) {
4041
circular.should.be.eql(1);
4142
done();
4243
});
4344
});
45+
4446
it("should be able to use require.js-style define, without name", function(done) {
4547
true && define(["./circular"], function(circular) {
4648
circular.should.be.eql(1);
4749
done();
4850
});
4951
});
52+
5053
it("should be able to use require.js-style define, with empty dependencies", function(done) {
5154
define("name", [], function() {
5255
done();
5356
});
5457
});
58+
59+
it("should be able to use require.js-style define, with empty dependencies, with a expression", function(done) {
60+
define([], done);
61+
});
62+
63+
it("should be able to use require.js-style define, with empty dependencies, with a expression and name", function(done) {
64+
define("name", [], done);
65+
});
66+
5567
it("should be able to use require.js-style define, without dependencies", function(done) {
5668
true && define("name", function() {
5769
done();
5870
});
5971
});
72+
73+
it("should be able to use require.js-style define, without dependencies, with a expression", function(done) {
74+
true && define("name", done);
75+
});
76+
6077
var obj = {};
6178
it("should be able to use require.js-style define, with an object", function() {
79+
module.exports = null;
80+
6281
true && define("blaaa", obj);
82+
83+
module.exports.should.be.equal(obj);
84+
module.exports = null;
85+
6386
define("blaaa", obj);
64-
});
65-
after(function() {
87+
6688
module.exports.should.be.equal(obj);
89+
module.exports = null;
6790
});
91+
6892
it("should offer AMD-style define for CommonJs", function(done) {
6993
var _test_require = require.valueOf();
7094
var _test_exports = exports;
@@ -78,19 +102,23 @@ it("should offer AMD-style define for CommonJs", function(done) {
78102
done();
79103
});
80104
});
105+
81106
it("should not crash on require.js require only with array", function() {
82107
require(["./circular"]);
83108
});
109+
84110
it("should be able to use AMD require without function expression (empty array)", function(done) {
85111
require([], done);
86112
});
113+
87114
it("should be able to use AMD require without function expression", function(done) {
88115
require(["./circular"], fn);
89116
function fn(c) {
90117
c.should.be.eql(1);
91118
done();
92119
}
93120
});
121+
94122
it("should create a chunk for require.js require", function(done) {
95123
var sameTick = true;
96124
require(["./c"], function(c) {
@@ -101,3 +129,15 @@ it("should create a chunk for require.js require", function(done) {
101129
});
102130
sameTick = false;
103131
});
132+
133+
it("should not fail #138", function(done) {
134+
(function (factory) {
135+
if (typeof define === 'function' && define.amd) {
136+
define([], factory); // AMD
137+
} else if (typeof exports === 'object') {
138+
module.exports = factory(); // Node
139+
} else {
140+
factory(); // Browser global
141+
}
142+
}(function () { done() }));
143+
});

0 commit comments

Comments
 (0)