nw.js: Cannot compile es6 module source

NWJS Version : v0.26.6 Operating System : macOS 10.13.1 (HighSierra)

Now we already can use es6 module features in v0.26.6 (Chrome 62). One example is:

` -------------lib.js--------------

// lib.js class TestModule { foo() { console.log(‘—foo----’); } }

export {TestModule};

-----------testmodule.js---------------- // testmodule.js import {TestModule} from “./lib.js”;

var f = new TestModule(); f.foo();

-----------index.html----------------

<html>
<body>
    <script type="module" src="testmodule.js"></script>
    Hello.
</body>
</html>

----------package.json----------- { “name”: “helloworld”, “main”: “index.html”, “dependencies”: {} } `

The above example can work properly. However, nwjc tool cannot compile them to binary code. The error message is: ` $/Applications/nwjs/nwjc lib.js lib.bin

Failure compiling ‘lib.js’ (see above) `

What’s the correct procedure to use es6 module with nwjc? This is important for large scale application.

Thanks.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 1
  • Comments: 67 (21 by maintainers)

Commits related to this issue

Most upvoted comments

For people who are having problems loading the es6 modules, I leave here as I do in my app so that it can help them.

Estructure:

src |_ modulesES6   |_ mymodule_1.bin   |_ mymodule_2.bin   |_ mymodule_1.js (Erase this file for dist)   |_ mymodule_2.js (Erase this file for dist) |__ scripts   |__ myscript.bin   |__ myscript.js (Erase this file for dist) |__ views   |__ index.html

mymodule_1.js | mymodule_1.bin

export function person( name = "Manu", age = 37, height = 180 ) {
    return {
        name: name,
        age: age,
        height : height ,
    }
}

mymodule_2.js | mymodule_2.bin

import { person as Person } from "./mymodule_1.js";

class ClassRoom {
    constructor() {
         this.students = [];
    }

    set_student( name, age, height ) {
        this.stundents.push( Person( name, age, height ));
    }

    num_students() {
        return this.stundents.length;
    }
}

const classroom = new ClassRoom();
export { classroom };

myscript.js | myscript.bin

import { classroom as Classroom } from "./mymodule_2.js";

class App {
    constructor() {
        Classroom.set_student( "Manu", 37, 180 );
        document.querySelector( "h1" ).innerHTML = "Num of students in classroom: " + Classroom.num_students();
    }
}

const app = new App();
export { app };

index.html

<html>
    <head></head>
    <body>
        <h1></h1>

        <!-- Importing modules -->
        <script>nw.Window.get().evalNWBinModule( null, './src/modulesES6/mymodule_1.bin', './mymodule_1.js' );</script>
	<script>nw.Window.get().evalNWBinModule( null, './src/modulesES6/mymodule_2.bin', './mymodule_2.js' );</script>

        <!-- Importing scripts -->
	<script>nw.Window.get().evalNWBinModule( null, './src/scripts/myscript.bin', './myscript.js' );</script>

        <script type="module">
            import { app } from "./myscripts.js";
        </script>
    </body>
</html>

Note that the import in ** myscript.js **, I do not put the relative path to the module that I am importing, I put the base path of the app. Where would you have to write import { classroom as Classroom } from" ../ modulesES6 / mymodules_2.js ", write import { classroom as Classroom } from" ./mymodules_2.js ".

You just have to adapt it to the structure of your app and you should not have problems to make it work.

It may seem a bit cumbersome, but with a little skill, I have programmed a compiler that adjusts the import paths in the modules automatically when I compile the application, as well as changing me <script type="module" src=" ../ scripts / mysscript.js"></script> by <script nw.Window.get().evalNWBinModule(null, './src/scripts/myscript.bin', './myscript.js ');</script> in html files also automatically.

So with a single console command, the application is compiled, modifies imports in .js and scripts in html, packaged in exe and zip and uploaded to my repository on my server by FTP ready for users to download or when a user who already has it installed, receive automatic update and install.

It is undoubtedly the ability of nw.js to convert .js files into .bin files that prompted me to switch from electron to nw.js. When I tried nw.js and saw its capabilities I will never go back to electron. Not only because of the protection of the scripts, but also because of the operation of the application’s contexts, the possibility of including Polymer that didn’t work in electron and the non-SDK flavor that doesn’t allow inspecting the app’s windows.

Once you understand nw.js you can easily make node.js an automatic compiler with a little effort that even works better with electron builders.

I hope to help.

It is not fixed in v0.35.5.


module.js: console.log(‘hello from module’);

Compile: nwjc --nw-module module.js module.bin

Load and run in index.html: win.evalNWBinModule(null, “module.bin”, “module.js”);

The code was not executed at all.

What I’m wondering, actually, is the following: is it possible to make nested imports (either static either dynamic modules) to work with binary compiled modules via nwjc ?

So that a whole NW.js application made up of separate es modules can be compiled into individual binary module files which would work together when the main module is loaded into NW.js.

Ideally, as a developper, and as stated by @rogerwang, there should not be any change to make into the application code in order to support it.

So, one’s best guess would be that NW.js somehow would hook into the import internal mechanism of either node or chromium. And you seem to suggest, @smotaal , that the new node’s loader would be the more pertinent to use internally by NW.js to achieve that goal.

Now, how would that connect to binary modules requiring or importing each other ? Can nwjc compile es modules with top-level imports or dynamic imports into binaries which would then be imported at runtime by the application, each binary module being also able to import the others like non compiled es modules?

My point is that perhaps to protect the javascript source code in the context of separate modules is not possible with nwjc snapshots, but I may be wrong, not knowing the internals of how a snapshot is made. But to use a customized node’s loader as you pointed out, @smotaal, could also allow to use alternative encryption tools to protect the source code without using the nwjc snapshots (if they do not work in the context of modules).

so an integrated ES module logic is part of the solution of real ES modules as compiled javascript

The compiled javascript OP and I talked about here in this issue is not the same concept with yours. We were talking about a specific NW feature to transform JS source to binary (similar with what happened to C/C++ source code), not ’ javascript source code in a single-file representing multiple files’ compilation used by many JS programmers.

Yes, I recall that, perfect, so can you elaborate a little on how you coerce blink’s resolution there

Blink maintains the modules map here https://github.com/nwjs/chromium.src/blob/nw28/third_party/WebKit/Source/core/dom/ModuleMap.h

Will change it to add the support needed for the new evalNWBin(), which I’m going to add before 0.28.0 release and mark the new API experimental (subject to change in the future)

Thanks @smotaal . Chromium engine had its module system implemented and it’s working in NW. We could just reuse it for module binaries. It’s just that a module would load its dependency by referring to it’s JS filename (see testmodule.js importing lib.js in OP’s example). Regarding NW.js binary module, it might not be feasible to let developers change the source code to refer to the binary’s filename (importing lib.bin instead of lib.js in testmodule.js), because that would require changing all the source code when the binary modules are to be built. I believe that would break developers’ work flow.

I am thinking to extend the API Window.evalNWBin() which NW used to load compiled JS binary to something like : evalNWBin(null, 'lib.bin', 'lib.js');

This creates a mapping between the paths of the module source and binary. After that, each time when Blink engine wants to load module lib.js, it will try loading lib.bin if the source code is missing.

I’m not sure if this would work the best way for JS application developers because my first language is C++. So please advise.

@smotaal as said in the last comment we are waiting for proposal from application developers. So if you want it to be implemented soon, please take some time to submit a proposal first.