google / traceur-compiler

Traceur is a JavaScript.next-to-JavaScript-of-today compiler
Apache License 2.0
8.17k stars 580 forks source link

New module `instantiate` loading behaviour? #2086

Closed pflannery closed 8 years ago

pflannery commented 8 years ago

It's been a few months since I last compiled with Traceur so I'm a little out of touch on the changes. I'm finding with Traceur v0.0.102 and SystemJS v0.19.22 that a compiled file doesn't execute the root module any more and I'm wondering if this intentional or a bug.

Originally these steps used to work:

But this doesn't work anymore in 0.0.102 and I now get the following error: Error: Multiple anonymous System.register calls in module http://192.168.56.1:8080/out/compiled.js. If loading a bundle, ensure all the System.register calls are named

I then changed the compile line to ensure that all System.register calls are given a module name traceur --modules instantiate --moduleName true --out ./out/compiled.js ./src/app.js

I again load the compiled.js file in the browser and this time there is no error but there is also nothing in the module returned by the System.import method. SystemJS registers all the modules but doesn't execute the root module.

That means to access the root module I have to do this:

<script>
  'use strict';
  System.import('./out/compiled.js').then(() => {
    System.import("./src/app.js").then(module => {
      const AppClass = module.App;

      let app = new AppClass();
      app.record("hello");
      app.record("I'm working now");
      app.playback();
    });
  });
</script>

and this also works

<script type="application/javascript" src="./out/compiled.js"></script>
<script>
  'use strict';
  System.import("./src/app.js").then(module => {
    const AppClass = module.App;

    let app = new AppClass();
    app.record("hello");
    app.record("I'm working now");
    app.playback();
  });
</script>

But I doesnt seem right that I have to use the './src' folder prefix to access the root module in my app.

I'm guessing I'm missing something here. What am I doing wrong? thanks

arv commented 8 years ago

@johnjbarton @guybedford Do you know what changed in this area?

guybedford commented 8 years ago

The mechanisms above are all correct, is it the module naming format that is being question here or that? The fact that it is written into the bundle as ./src/app.js is part of the naming conventions Traceur derives from the inputs, which may be possible to re-evaluate.

pflannery commented 8 years ago

I expected it to load identically to how SystemJS loads ES6 directly in the browser. i.e. the root module to be returned by System.import. Like:

<script>
  'use strict';
  System.import('./out/compiled.js').then(module => {
      const App = module.App;

      let app = new App();
      app.record("hello");
      app.record("I'm working now");
      app.playback();
  });
</script>

Could -> IsRootModule be used here to let SystemJS know what the root module is for traceur compiled files?

guybedford commented 8 years ago

The bundle is a collection of modules, and doesn't by default take a value from those modules. This way a bundle and a module remain completely distinct concepts. We could "arbitrarily" let the first module defined by the bundle be also the value of the bundle module itself, but I think that would be blurring the important distinction between the two types of files.

pflannery commented 8 years ago

traceur compiled to amd or commonjs is having the same problem too.

guybedford commented 8 years ago

CommonJS doesn't provide a named transport. You probably want to be doing a separate file compile for each module, or a full inlined build.

pflannery commented 8 years ago

Didn't see your comment before my last comment.

I think the problem with having collections that dont expose the root module is that the user of the collection would need to know extra specifics to access the root module or the vendor would have to provide an extra entry point file for direct access.

When I've compiled a library to amd or commonjs pre-es6 days I never needed to create an addition entry point file to access the root module.

Anyway I will attempt inlining instead. thanks for your feedback.

guybedford commented 8 years ago

@pflannery AMD has exactly the same pattern when requiring a bundle created by the r.js optimizer. It does require some thought though to distinguish between builds and bundles. Once these two concepts are completely clear for everyone I think modularity will be much easier to reason about.

pflannery commented 8 years ago

@guybedford What throws me in this scenario is that the ./src folder is the namespace in which someone has to specify to access the library. (This library has a single entry point module that exposes it's exports to the user) It would be nice to define a namespace in the bundle so that

  1. make it simple to access, and
  2. create non-duplicates with other registered bundles.

Any ideas how we can specify namespaces in our bundles?

Also just looking at the inline option and it declares things like $___46__46__47_src_47_app_46_js__ that get exposed on to the global object in the browser.

guybedford commented 8 years ago

@pflannery defining the namespace is exactly what Traceur can provide options to assist with to ensure there aren't things like the ./src prefix. There should be an option to do this, perhaps @johnjbarton can advise.

pflannery commented 8 years ago

Thanks. I'm re-opening this.

pflannery commented 8 years ago

turns out the inline es6 transformation module I added last year works great for this scenario.

I inline the lib keeping es6 format

traceur --modules inline --outputLanguage=es6 --out ./out/lib-compiled.js ./src/lib.js

Then bundle the inlined lib for systemjs

traceur --modules instantiate --out ./dist/lib-for-systemjs.js ./out/lib-compiled.js

I now can load the library via System.import directly without errors. I'm happy to close. @guybedford thanks for your help

johnjbarton commented 8 years ago

Thanks for the update.