Skip to content

Commit 5f77afe

Browse files
committed
ES6 parser, ES6 modules
1 parent 2f33d5e commit 5f77afe

23 files changed

Lines changed: 579 additions & 7 deletions

examples/harmony/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
2+
# example.js
3+
4+
``` javascript
5+
import { increment as inc } from './increment';
6+
var a = 1;
7+
inc(a); // 2
8+
```
9+
10+
# increment.js
11+
12+
``` javascript
13+
import { add } from './math';
14+
export function increment(val) {
15+
return add(val, 1);
16+
};
17+
```
18+
19+
# js/output.js
20+
21+
``` javascript
22+
/******/ (function(modules) { // webpackBootstrap
23+
/******/ // The module cache
24+
/******/ var installedModules = {};
25+
/******/
26+
/******/ // The require function
27+
/******/ function __webpack_require__(moduleId) {
28+
/******/
29+
/******/ // Check if module is in cache
30+
/******/ if(installedModules[moduleId])
31+
/******/ return installedModules[moduleId].exports;
32+
/******/
33+
/******/ // Create a new module (and put it into the cache)
34+
/******/ var module = installedModules[moduleId] = {
35+
/******/ exports: {},
36+
/******/ id: moduleId,
37+
/******/ loaded: false
38+
/******/ };
39+
/******/
40+
/******/ // Execute the module function
41+
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
42+
/******/
43+
/******/ // Flag the module as loaded
44+
/******/ module.loaded = true;
45+
/******/
46+
/******/ // Return the exports of the module
47+
/******/ return module.exports;
48+
/******/ }
49+
/******/
50+
/******/
51+
/******/ // expose the modules object (__webpack_modules__)
52+
/******/ __webpack_require__.m = modules;
53+
/******/
54+
/******/ // expose the module cache
55+
/******/ __webpack_require__.c = installedModules;
56+
/******/
57+
/******/ // __webpack_public_path__
58+
/******/ __webpack_require__.p = "js/";
59+
/******/
60+
/******/ // Load entry module and return exports
61+
/******/ return __webpack_require__(0);
62+
/******/ })
63+
/************************************************************************/
64+
/******/ ([
65+
/* 0 */
66+
/*!********************!*\
67+
!*** ./example.js ***!
68+
\********************/
69+
/***/ function(module, exports, __webpack_require__) {
70+
71+
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__increment__ = __webpack_require__(/*! ./increment */ 1);
72+
var a = 1;
73+
/* harmony import */ __WEBPACK_IMPORTED_MODULE_0__increment__["increment"](a); // 2
74+
75+
/***/ },
76+
/* 1 */
77+
/*!**********************!*\
78+
!*** ./increment.js ***!
79+
\**********************/
80+
/***/ function(module, exports, __webpack_require__) {
81+
82+
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__math__ = __webpack_require__(/*! ./math */ 2);
83+
/* harmony export declaration */function increment(val) {
84+
return /* harmony import */ __WEBPACK_IMPORTED_MODULE_0__math__["add"](val, 1);
85+
}/* harmony export */ Object.defineProperty(exports, "increment", {configurable: false, enumerable: true, get: function() { return increment; }});;
86+
87+
88+
/***/ },
89+
/* 2 */
90+
/*!*****************!*\
91+
!*** ./math.js ***!
92+
\*****************/
93+
/***/ function(module, exports, __webpack_require__) {
94+
95+
/* harmony export declaration */function add() {
96+
var sum = 0, i = 0, args = arguments, l = args.length;
97+
while (i < l) {
98+
sum += args[i++];
99+
}
100+
return sum;
101+
}/* harmony export */ Object.defineProperty(exports, "add", {configurable: false, enumerable: true, get: function() { return add; }});
102+
103+
104+
/***/ }
105+
/******/ ])
106+
```
107+
108+
# Info
109+
110+
## Uncompressed
111+
112+
```
113+
Hash: 2cddb2c302ef93d23ea9
114+
Version: webpack 1.4.15
115+
Time: 47ms
116+
Asset Size Chunks Chunk Names
117+
output.js 2792 0 [emitted] main
118+
chunk {0} output.js (main) 309 [rendered]
119+
> main [0] ./example.js
120+
[0] ./example.js 73 {0} [built]
121+
[1] ./increment.js 94 {0} [built]
122+
harmony import ./increment [0] ./example.js 1:0-47
123+
[2] ./math.js 142 {0} [built]
124+
harmony import ./math [1] ./increment.js 1:0-29
125+
```
126+
127+
## Minimized (uglify-js, no zip)
128+
129+
```
130+
Hash: 810b804d71afd4672772
131+
Version: webpack 1.4.15
132+
Time: 141ms
133+
Asset Size Chunks Chunk Names
134+
output.js 585 0 [emitted] main
135+
chunk {0} output.js (main) 309 [rendered]
136+
> main [0] ./example.js
137+
[0] ./example.js 73 {0} [built]
138+
[1] ./increment.js 94 {0} [built]
139+
harmony import ./increment [0] ./example.js 1:0-47
140+
[2] ./math.js 142 {0} [built]
141+
harmony import ./math [1] ./increment.js 1:0-29
142+
```

examples/harmony/build.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require("../build-common");

examples/harmony/example.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { increment as inc } from './increment';
2+
var a = 1;
3+
inc(a); // 2

examples/harmony/increment.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { add } from './math';
2+
export function increment(val) {
3+
return add(val, 1);
4+
};

examples/harmony/math.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function add() {
2+
var sum = 0, i = 0, args = arguments, l = args.length;
3+
while (i < l) {
4+
sum += args[i++];
5+
}
6+
return sum;
7+
}

examples/harmony/template.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
# example.js
3+
4+
``` javascript
5+
{{example.js}}
6+
```
7+
8+
# increment.js
9+
10+
``` javascript
11+
{{increment.js}}
12+
```
13+
14+
# js/output.js
15+
16+
``` javascript
17+
{{js/output.js}}
18+
```
19+
20+
# Info
21+
22+
## Uncompressed
23+
24+
```
25+
{{stdout}}
26+
```
27+
28+
## Minimized (uglify-js, no zip)
29+
30+
```
31+
{{min:stdout}}
32+
```

lib/Parser.js

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
MIT License http://www.opensource.org/licenses/mit-license.php
33
Author Tobias Koppers @sokra
44
*/
5-
var esprima = require("esprima");
5+
var esprima = require("esprima-fb");
66
var Tapable = require("tapable");
77
var BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
88

@@ -446,6 +446,75 @@ Parser.prototype.walkFunctionDeclaration = function walkFunctionDeclaration(stat
446446
}.bind(this));
447447
};
448448

449+
Parser.prototype.walkImportDeclaration = function walkImportDeclaration(statement) {
450+
var source = statement.source.value;
451+
this.applyPluginsBailResult("import", statement, source);
452+
statement.specifiers.forEach(function(specifier) {
453+
switch(specifier.type) {
454+
case "ImportDefaultSpecifier":
455+
var name = specifier.id.name;
456+
this.scope.renames["$"+name] = undefined;
457+
this.scope.definitions.push(name);
458+
this.applyPluginsBailResult("import specifier", statement, source, "default", name);
459+
break;
460+
case "ImportSpecifier":
461+
var name = (specifier.name || specifier.id).name;
462+
this.scope.renames["$"+name] = undefined;
463+
this.scope.definitions.push(name);
464+
this.applyPluginsBailResult("import specifier", statement, source, specifier.id.name, name);
465+
break;
466+
case "ImportNamespaceSpecifier":
467+
var name = specifier.id.name;
468+
this.scope.renames["$"+name] = undefined;
469+
this.scope.definitions.push(name);
470+
this.applyPluginsBailResult("import specifier", statement, source, null, name);
471+
break;
472+
}
473+
}, this);
474+
};
475+
476+
Parser.prototype.walkExportDeclaration = function walkExportDeclaration(statement) {
477+
if(statement.source) {
478+
var source = statement.source.value;
479+
this.applyPluginsBailResult("export import", statement, source);
480+
} else {
481+
this.applyPluginsBailResult("export", statement);
482+
}
483+
if(statement.declaration) {
484+
if(/Expression$/.test(statement.declaration.type)) {
485+
if(!this.applyPluginsBailResult("export expression", statement, statement.declaration)) {
486+
this.walkExpression(statement.declaration);
487+
this.applyPluginsBailResult("export specifier", statement, statement.declaration, "default");
488+
}
489+
} else {
490+
if(!this.applyPluginsBailResult("export declaration", statement, statement.declaration)) {
491+
var pos = this.scope.definitions.length;
492+
this.walkStatement(statement.declaration);
493+
var newDefs = this.scope.definitions.slice(pos);
494+
newDefs.forEach(function(def) {
495+
this.applyPluginsBailResult("export specifier", statement, def, statement["default"] ? "default" : def);
496+
}, this);
497+
}
498+
}
499+
}
500+
if(statement.specifiers) {
501+
statement.specifiers.forEach(function(specifier) {
502+
switch(specifier.type) {
503+
case "ExportSpecifier":
504+
var name = (specifier.name || specifier.id).name;
505+
if(source)
506+
this.applyPluginsBailResult("export import specifier", statement, source, specifier.id.name, name);
507+
else
508+
this.applyPluginsBailResult("export specifier", statement, specifier.id.name, name);
509+
break;
510+
case "ExportBatchSpecifier":
511+
this.applyPluginsBailResult("export import specifier", statement, source, null, null);
512+
break;
513+
}
514+
}, this);
515+
}
516+
};
517+
449518
Parser.prototype.walkVariableDeclaration = function walkVariableDeclaration(statement) {
450519
if(statement.declarations)
451520
this.walkVariableDeclarators(statement.declarations);
@@ -774,7 +843,7 @@ Parser.prototype.parseCalculatedString = function parseCalculatedString(expressi
774843
});
775844

776845
Parser.prototype.parse = function parse(source, initialState) {
777-
var ast = esprima.parse(source, {range: true, loc: true, raw: true});
846+
var ast = esprima.parse(source, {range: true, loc: true, raw: true, sourceType: "module"});
778847
if(!ast || typeof ast !== "object")
779848
throw new Error("Source couldn't be parsed");
780849
var oldScope = this.scope;

lib/WebpackOptionsApply.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin")
2727

2828
var LoaderPlugin = require("./dependencies/LoaderPlugin");
2929
var CommonJsPlugin = require("./dependencies/CommonJsPlugin");
30+
var HarmonyModulesPlugin = require("./dependencies/HarmonyModulesPlugin");
3031
var AMDPlugin = require("./dependencies/AMDPlugin");
3132
var LabeledModulesPlugin = require("./dependencies/LabeledModulesPlugin");
3233
var RequireContextPlugin = require("./dependencies/RequireContextPlugin");
@@ -249,7 +250,8 @@ WebpackOptionsApply.prototype.process = function(options, compiler) {
249250
new RequireEnsurePlugin(),
250251
new RequireContextPlugin(options.resolve.modulesDirectories, options.resolve.extensions),
251252
new AMDPlugin(options.module, options.amd || {}),
252-
new CommonJsPlugin(options.module)
253+
new CommonJsPlugin(options.module),
254+
new HarmonyModulesPlugin()
253255
);
254256

255257
compiler.apply(
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
var AbstractPlugin = require("../AbstractPlugin");
6+
var HarmonyExportExpressionDependency = require("./HarmonyExportExpressionDependency");
7+
var HarmonyExportSpecifierDependency = require("./HarmonyExportSpecifierDependency");
8+
var HarmonyImportDependency = require("./HarmonyImportDependency");
9+
var HarmonyModulesHelpers = require("./HarmonyModulesHelpers");
10+
11+
module.exports = AbstractPlugin.create({
12+
"export": function(statement) {
13+
var dep = new HarmonyExportExpressionDependency(null, statement.declaration && statement.declaration.range, statement.range);
14+
dep.loc = statement.loc;
15+
this.state.current.addDependency(dep);
16+
return true;
17+
},
18+
"export import": function(statement, source) {
19+
var dep = new HarmonyImportDependency(source, HarmonyModulesHelpers.getNewModuleVar(this.state, source), statement.range);
20+
dep.loc = statement.loc;
21+
this.state.current.addDependency(dep);
22+
return true;
23+
},
24+
"export expression": function(statement, expr) {
25+
var dep = new HarmonyExportExpressionDependency("default", expr.range, statement.range);
26+
dep.loc = statement.loc;
27+
this.state.current.addDependency(dep);
28+
return true;
29+
},
30+
"export declaration": function(statement, name) {
31+
},
32+
"export specifier": function(statement, id, name) {
33+
var dep = new HarmonyExportSpecifierDependency(null, id, name, statement.range[1] + 0.5);
34+
dep.loc = statement.loc;
35+
this.state.current.addDependency(dep);
36+
return true;
37+
},
38+
"export import specifier": function(statement, source, id, name) {
39+
var dep = new HarmonyExportSpecifierDependency(HarmonyModulesHelpers.getModuleVar(this.state, source), id, name, statement.range[1] + 0.5);
40+
dep.loc = statement.loc;
41+
this.state.current.addDependency(dep);
42+
return true;
43+
}
44+
});
45+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Tobias Koppers @sokra
4+
*/
5+
var NullDependency = require("./NullDependency");
6+
7+
function HarmonyExportExpressionDependency(name, range, rangeStatement) {
8+
NullDependency.call(this);
9+
this.Class = HarmonyExportExpressionDependency;
10+
this.name = name;
11+
this.range = range;
12+
this.rangeStatement = rangeStatement;
13+
}
14+
module.exports = HarmonyExportExpressionDependency;
15+
16+
HarmonyExportExpressionDependency.prototype = Object.create(NullDependency.prototype);
17+
HarmonyExportExpressionDependency.prototype.type = "harmony export expression";
18+
19+
HarmonyExportExpressionDependency.Template = function HarmonyExportDependencyTemplate() {};
20+
21+
HarmonyExportExpressionDependency.Template.prototype.apply = function(dep, source) {
22+
if(dep.name) {
23+
var content = "exports[" + JSON.stringify(dep.name) + "] = ";
24+
} else {
25+
var content = "/* harmony export declaration */";
26+
}
27+
source.replace(dep.rangeStatement[0], dep.range ? dep.range[0]-1 : dep.rangeStatement[1]-1, content);
28+
}

0 commit comments

Comments
 (0)