google / google/closure-compiler

Support multiline ES6 `export ... from` syntax

Open
#3,025 5 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
7.7k
Forks
1.2k
Avg merge
2d 12h
Merged PRs (30d)
6

Description

### Description of problem

When parsing ES6 code of the form `export ... from`, the compiler fails to generate the correct `goog.require` statement.

### Steps to reproduce

Given the following files:

```js
//greet.js
export default function greet(m) {
document.write("\nHello, " + m);
};
```
```js
//hello.js
export {
default as helloGreet
} from "./greet";
```

Execute:
```
java -jar $JAR -O BUNDLE --formatting PRETTY_PRINT --module_resolution NODE --js_output_file=/dev/stdout -W VERBOSE --debug --dependency_mode STRICT --entry_point hello.js greet.js hello.js | grep -A 11 -E 'greet|hello'
```

### Expected outcome

Closure compiler should detect `greet.js` as a dependency of `hello.js` and output them both under strict dependency mode.

```js
//greet.js
$jscomp.registerAndLoadModule(function($$require, $$exports, $$module) {
"use strict";
Object.defineProperties($$exports, {"default":{enumerable:true, get:function() {
return greet;
}}});
function greet(m) {
document.write("\nHello, " + m);
}
}, "greet.js", []);

//hello.js
$jscomp.registerAndLoadModule(function($$require, $$exports, $$module) {
"use strict";
Object.defineProperties($$exports, {helloGreet:{enumerable:true, get:function() {
return module$greet["default"];
}}});
var module$greet = $$require("greet.js");
}, "hello.js", ["greet.js"]);

```

### Actual outcome

[`JsFileParser`](/src/com/google/javascript/jscomp/deps/JsFileParser.java) fails compute the list of requires.

```js
//hello.js
$jscomp.registerAndLoadModule(function($$require, $$exports, $$module) {
"use strict";
Object.defineProperties($$exports, {helloGreet:{enumerable:true, get:function() {
return module$greet["default"];
}}});
var module$greet = $$require("greet.js");
}, "hello.js", ["greet.js"]);

```

### Workaround/patches

Condensing the export to a single line works around the issue but may be infeasible for third party libs (e.g. from NPM).

Avoiding `JsFileParser` also fixes the problem:

```patch
diff --git a/src/com/google/javascript/jscomp/CompilerInput.java b/src/com/google/javascript/jscomp/CompilerInput.java
index 62609562b..4e4d3e3dc 100644
--- a/src/com/google/javascript/jscomp/CompilerInput.java
+++ b/src/com/google/javascript/jscomp/CompilerInput.java
@@ -285,7 +285,7 @@ public class CompilerInput extends DependencyInfo.Base implements SourceAst {

// If the code is a JsAst, then it was originally JS code, and is compatible with the
// regex-based parsing of JsFileParser.
- if (ast instanceof JsAst && JsFileParser.isSupported()) {
+ if (false && ast instanceof JsAst && JsFileParser.isSupported()) {
// Look at the source code.
// Note: it's OK to use getName() instead of
// getPathRelativeToClosureBase() here because we're not using
```

### Analysis

Due to the line parsing nature of `JsFileParser`, it fails to look ahead when faced with a line that starts with export (or import) but doesn't contain a semicolon. In fact, under shortcut mode, it appears to halt the parser.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.