google / closure-compiler

A JavaScript checker and optimizer.
https://developers.google.com/closure/compiler/
Apache License 2.0
7.37k stars 1.14k forks source link

ES6 circular dependencies #1883

Open 2beers opened 8 years ago

2beers commented 8 years ago

I have the following files

//test1.js
import {Test2} from 'test2';
export class Test1 {
    constructor() {
        console.log(new Test2());
    }
}

//test2.js
import {Test1} from 'test1';
export class Test2 {
    constructor() {
        console.log(new Test1());
    }
}

//main.js
import {Test1} from 'test1';
console.log(new Test1());

on compiling in Advanced mode I get this error:

test2.js:1: ERROR - required "module$test1" namespace not provided yet import {Test1} from 'test1';

Is this a bug or am I doing something wrong? If I comment the import line in test2.js it compiles but not with the result I want:

function a() {
  console.log(new Test1); // !!!! who is Test1 ????
}
;console.log(new function() {
  console.log(new a);
});
MatrixFrog commented 8 years ago

I don't think we have a good answer for this right now. (We do for goog.module though)

If you can, move both classes into a single module? Lots of Google code has one class per file (like Java) and as modules become more common I've been encouraging people to move away from that where it makes sense.

2beers commented 8 years ago

Is this something that's going to be fixed in future versions? I know I can put them in the same file, but I encounter this error in a much more complicated situation. I just minimized it to this simple example. What's the solution for goog.module?

MatrixFrog commented 8 years ago

For goog.module, I believe you goog.require the module but then use goog.module.get before actually using anything from that module.

alexeagle commented 7 years ago

I ran into this issue as well. Trying to make an example of using moment.js with closure dependency management, to resolve https://github.com/alexeagle/closure-compiler-angular-bundling/issues/22

https://github.com/moment/moment/blob/develop/src/lib/create/from-string.js

import { configFromStringAndFormat } from './from-string-and-format';

https://github.com/moment/moment/blob/develop/src/lib/create/from-string-and-format.js

import { configFromISO, configFromRFC2822 } from './from-string';
alexeagle commented 7 years ago

@ChadKillingsworth is this on your radar? Maybe I'll take a stab at it?

ChadKillingsworth commented 7 years ago

No not really. Have at it.

simonsarris commented 7 years ago

For goog.module, I believe you goog.require the module but then use goog.module.get before actually using anything from that module.

@MatrixFrog Can you give a small example of this?

MatrixFrog commented 7 years ago

Contrived example, but here you go. https://github.com/MatrixFrog/closure-module-example

rconnamacher commented 7 years ago

Running into this issue as well.

For my project this mainly happens with type annotations, so I've adopted the C-style solution of generating "header" interface files declaring the public API (using @interface), and then have the main class @implement it. I'm then using the @interface file for all type annotations. As long as there's no circular type reference among the interfaces themselves, it works.

But then there are a few places where there's a circular reference in type annotations on public methods as well, so I've had to pick one to remove the type checks from (replacing the @param annotation's type with {?}).