Importing ES6 modules

We're trying to embed Spidermonkey76 - will look move to 78 ESR at some point - into a software that isn't a web browser. We've been looking at support for ES6 features and aren't sure about modules.

Attempts to use local path identifiers with import commands (import MyFunc from "./whatever";) provoke an "import declarations may only appear at the top level of a module" message.

There was a similar post a couple of years ago. One response suggested the usage of JS::CompileModule (instead of JS::Compile<Script>). How do we know that we have a module a-priori, rather than a script? 

Is the solution then to use a module resolve hook? Would it be possible to find an example? The JS API user guide doesn't include much on this topic.

Thanks very much.
9/1/2020 9:30:15 AM
📃 2054 articles.

💬 3 Replies


In general, JavaScript requires that you know certain code is a module a-priori. There are examples of code that parse as both Script and as Module yet have different results. SpiderMonkey will not try to guess. If your application wishes to take a guess, it could first try parsing as Script (since that has semantics that most people expect) and if parsing fails it could try again as Module. Your choice here would depend on what is acceptable for your application in terms of performance and predictable behaviour.

Note as well that using the `CompileModule` API you must also call  ModuleInstantiate in order to trigger loading and parsing of other modules that are imported. This all happens before executing the top-level JS code itself.

I've added an example to the embedding-examples repo.

You can see the pull-request here:

9/1/2020 2:27:32 PM
To clarify, the difference involves modules like this:

    function foo() {
      console.log("hello world");

You can run this as a script. It declares a global function `foo`.

You can run this as a module too. But since it doesn't import or export anything, it won't do anything useful. The function `foo` is module-scope rather than global. Other scripts and modules can't see it.

That's why if you really don't know, it's best to try parsing it as a script first, then module as a fallback. But it's even better to just have clear rules about which files are treated as scripts and which ones are modules. Your JS developers will probably expect such rules they'll be familiar with HTML, for example, where a <script> is always a script, unless the tag actually says <script type="module">.

9/1/2020 3:03:30 PM
This is a real problem, with no perfect solution.  In my case, I mandate that developers use a different file extension for modules. That makes it super easy, and the error it throws if you try and compile a module as a script is hopefully informative enough that they can fix it.

Also something to consider doing: Use JS::SetModuleResolveHook() so that you can have some control over where the interpreter looks for modules to load.  I'm not sure how intelligent SpiderMonkey is about module resolution without it.
9/10/2020 1:55:42 PM
(Thread closed)