Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I reference files in a `script` tag when using ES6 modules in a browser

I can't seem to find an answer to my question about whether I should include files in a <script> tag when using ES6 modules or if a browser will request them automatically? If so, how does it resolve the path?

like image 218
Max Koretskyi Avatar asked Oct 09 '16 14:10

Max Koretskyi


1 Answers

In a comment you've said:

I know that there's no support yet. My question is about how it'll behave when implemented

There wasn't when we first posted this question and answer, but there is now. And it matches what I'd previously described was provisionally specified: You use type="module":

<script src="mod.js" type="module"></script>

You only do that for the entry point, not for the modules the entry point references via import (more below).

From the WHAT-WG specification:

The type attribute allows customization of the type of script represented:

  • ...
  • Setting the attribute to an ASCII case-insensitive match for the string "module" means that the script is a module script, to be interpreted according to the JavaScript Module top-level production. ...
  • ...

...

Classic scripts and module scripts may either be embedded inline or may be imported from an external file using the src attribute, which if specified gives the URL of the external script resource to use.

The modules' dependencies will be resolved and automatically fetched, you don't list them in their own script tags. Just the entry point.

Note that you can serve modules to module-enabled browsers and also serve transpiled bundles to non-module-enabled browsers by using the nomodule attribute:

The nomodule attribute is a boolean attribute that prevents a script from being executed in user agents that support module scripts. This allows selective execution of module scripts in modern user agents and classic scripts in older user agents, as shown below. The nomodule attribute must not be specified on module scripts (and will be ignored if it is).

And since any browser that supports modules supports ES2015 features at least (probably more as well), that means you can serve native class and arrow function and such code in modules, and transpiled code in non-module bundles, so you get native performance from native engines.

Later, the spec says:

To resolve a module specifier given a URL base URL and a JavaScript string specifier, perform the following steps. It will return either a URL record or failure.

  • Apply the URL parser to specifier. If the result is not failure, return the result.
  • If specifier does not start with the character U+002F SOLIDUS (/), the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./), or the three-character sequence U+002E FULL STOP, U+002E FULL STOP, U+002F SOLIDUS (../), return failure.

NOTE: This restriction is in place so that in the future we can allow custom module loaders to give special meaning to "bare" import specifiers, like import "jquery" or import "web/crypto". For now any such imports will fail, instead of being treated as relative URLs.

So, if the module is a peer of the file loading it, start the module specifier with ./ (src="./myfile.js" or import ... from "./myfile.js"). Plain module specifiers with no path at all are reserved for import maps (should they ever be supported unflagged in browsers other than Chromium-based ones).

like image 129
T.J. Crowder Avatar answered Nov 14 '22 23:11

T.J. Crowder