detecting JS language mode for tools

# John Lenz (4 years ago)

For static language parsers there seems to be a bit of a dilemma with ES6 modules. I would appreciate a correct or hint.

Here is my understanding:

  • standard scripts as we know them today will parse in the browser as "loose" code
  • scripts with the standard "use strict" will parse as "strict" with access to all ES6 goodness
  • scripts loaded as modules will parse as "strict" even without the "use strict" annotation.

Is this true? If so, it seems like a tooling hazard and "use strict" on modules should at least be the encouraged convention.

# Tab Atkins Jr. (4 years ago)

Loose code will also get all the ES6 goodness. 1JS and all that.

# John Lenz (4 years ago)

You don't get "let", "function" block scoping, "yield" or other incompatible constructs. (let and yield aren't a reserved word in ES5 "loose)

# John Barton (4 years ago)

On Fri, Jan 24, 2014 at 8:49 AM, Tab Atkins Jr. <jackalmage at gmail.com>wrote:

Loose code will also get all the ES6 goodness. 1JS and all that.

You can't use import or export (or module?) keywords in script. There are two parsing goals, one for script and one for module. So more like 2JS ;-)

REPL is a dilemma: if you parse as module, then obtaining the last expression value is not simple. if you parse as a script, then common cut/paste fails on export/import statements.

# Oliver Hunt (4 years ago)

I believe the conclusion with let was to identify let syntax: let foo(=*) is syntactically unambiguous, just a bit more work to identify.

yield is only valid in generators (function*) so that gets reserved the moment you enter a generator definition

# John Lenz (4 years ago)

On Fri, Jan 24, 2014 at 9:16 AM, John Barton <johnjbarton at google.com> wrote:

You can't use import or export (or module?) keywords in script. There are two parsing goals, one for script and one for module. So more like 2JS ;-)

You can't import from a script? How do you load the first module? That seemed like the natural migration strategy.

REPL is a dilemma: if you parse as module, then obtaining the last expression value is not simple. if you parse as a script, then common cut/paste fails on export/import statements.

My basic question remains. As a tool owner how do I know if what I'm looking at is intended to be a Module or a Script?

# John Lenz (4 years ago)

On Fri, Jan 24, 2014 at 9:17 AM, Oliver Hunt <oliver at apple.com> wrote:

I believe the conclusion with let was to identify let syntax: let foo(=*) is syntactically unambiguous, just a bit more work to identify.

yield is only valid in generators (function*) so that gets reserved the moment you enter a generator definition

That is great, that only leave block scoped function declarations (and anything else I'm not aware of)

# David Bruant (4 years ago)

Le 24/01/2014 18:26, John Lenz a écrit :

My basic question remains. As a tool owner how do I know if what I'm looking at is intended to be a Module or a Script?

How do you know if some code is intended for the browser or Node? How do you know some code is intended to be used in a WebWorker and not in the main thread? How do you know the code won't be concatenated a "use strict" when someone else uses it?

The code itself lacks the context in which it's being loaded (hence very defensive patterns like UMD (Universal Module Definition)). If you want to be exhaustive, you'll have to make an assumption or make your tool smarter about the context.

# Brian Terlson (4 years ago)

You don't get "let", "function" block scoping, "yield" or other incompatible constructs. (let and yield aren't a reserved word in ES5 "loose)

It is true that there is some weirdness with let/const and block scoping in non-strict mode, but these issues can be sufficiently mitigated. IE11 has shipped let/const support and block-scoped functions with (mostly) backwards compatible semantics. For example, let let = 1; works in IE11 today outside of strict mode.

# John Lenz (4 years ago)

On Fri, Jan 24, 2014 at 9:32 AM, David Bruant <bruant.d at gmail.com> wrote:

How do you know if some code is intended for the browser or Node? How do you know some code is intended to be used in a WebWorker and not in the main thread?

These don't affect how the code is parsed or the behavior of the language itself.

How do you know the code won't be concatenated a "use strict" when someone else uses it?

This is an assembly issue and doesn't void intent. If it is true you won't be able "import" from a script, it is very reasonable to want to warn about this.

The code itself lacks the context in which it's being loaded (hence very defensive patterns like UMD (Universal Module Definition)). If you want to be exhaustive, you'll have to make an assumption or make your tool smarter about the context.

I want it to be "smarter" about the context, but smarter means knowing without being told. Having a different set of reserved words (between "loose" and "strict" mode) means this is a parser issue.

# John Barton (4 years ago)

If we are asking questions: why two parse goals? Why not allow import in Script and let it act like the code was wrapped in Loader.import() and allow export then just ignore it? The semantics of 'var' would be changed by appearance of 'import' just like the semantics of code changes with the appearance of 'use strict'.

# John Lenz (4 years ago)

As long as you can import from a script in some fashion: Loader.import works for me.

I'm a little concerned that "import/export" will need to work as a "use strict"

# Allen Wirfs-Brock (4 years ago)

On Jan 24, 2014, at 9:32 AM, David Bruant wrote:

How do you know if some code is intended for the browser or Node? How do you know some code is intended to be used in a WebWorker and not in the main thread? How do you know the code won't be concatenated a "use strict" when someone else uses it?

The code itself lacks the context in which it's being loaded (hence very defensive patterns like UMD (Universal Module Definition)). If you want to be exhaustive, you'll have to make an assumption or make your tool smarter about the context.

I've had some discussion with Dave Herman about this and I think there is a plausible way to handle it. I'm not sure if Dave would totally agree with 100% of the following but I think it is close to what seemed to make sense in our discussions.

  1. there are some very good technical reasons for having two syntactic goals (script and module) corresponding to the two semantics.

  2. A module with no imports and no exports is essentially a new form of top level code that is always strict mode and but has its own "file level" scope.

  3. In browsers, html syntax (new attribute on script tag, etc.) can be used to distinguish the two. Dave is working on this.

  4. but there are other situations where the intended syntactic goal of a source file need to be identifiable. For example, when listing source files on a command-line invocations of a JavaScript engine or tool

  5. Humans when reading or managing code files also need to know which kind of JS source file they are dealing with.

  6. typically we use file extensions to make distinctions of this sort.

  7. Hence, it probably makes sense to promote a convention of using a new file extension for ES6 source files that are intended to be parsed with the modules goal. .jsm, or mjs, or something similar that is appropriately suggestive and isn't already widely used as an extension.

# Kevin Smith (4 years ago)
  1. Hence, it probably makes sense to promote a convention of using a new file extension for ES6 source files that are intended to be parsed with the modules goal. .jsm, or mjs, or something similar that is appropriately suggestive and isn't already widely used as an extension.

Allen, I'm so glad you brought this option up! I've had it in the back of my mind for a good long while but I've always been hesitant to suggest it.

# Allen Wirfs-Brock (4 years ago)

I should have also included:

2A) Hopefully, overtime, the old script syntactic goal will fade from use, and the module goal will become the norm for new code.

# Mark S. Miller (4 years ago)

Assuming the current system for a moment, and discussing only conventions:

It is true that a "use strict" at the top of every *.js file does have the virtue of making it clear, both to tools and humans, that the remainder is strict code, even in one doesn't know if the file is to be loaded as a module or a script. Historically, we've recommended against a bare "use strict" at the top of script files conventions:avoid_strictness_contagion, in order to avoid the concatenation hazard. Instead, we recommend that script files have an outer strict IIFE. This still seems sensible when there's genuine ambiguity about whether it is a module or a script.

OTOH, if the author knows it is a module and simply wants to disambiguate to tools that it is strict, then the author knows there's no concatenation hazard and a bare "use strict" at the top would be fine. And, of course, if there are any export or import statements in there, then it cannot be a script, and it cannot be contained in an IIFE.

Btw, the conventional name for the opposite of strict is "sloppy" rather than "loose".

# John Barton (4 years ago)

On Fri, Jan 24, 2014 at 12:17 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

I should have also included:

2A) Hopefully, overtime, the old script syntactic goal will fade from use, and the module goal will become the norm for new code.

Now here is a reason, finally, for all the extra complexity the two goals cause.

If we want to kill script, let's not stab it with a dull pencil. Let's make Loader and System be modules, not globals. Then you cannot load modules with <script>, only with <module>.

# John Lenz (4 years ago)

I'm perfectly happy with convention of some kind: a) a file extension b) a comment on the first line of the file: // module mymodule c) a "use strict" style annotation that is just documentation: "module mymodule";

The key thing in my mind is that TC39 pick something and encourage it.

# Kevin Smith (4 years ago)

I'm perfectly happy with convention of some kind: a) a file extension b) a comment on the first line of the file: // module mymodule c) a "use strict" style annotation that is just documentation: "module mymodule";

One of the nicest things about the current modules syntax is that it avoids annoying boilerplate. Let's have none of that : )

# Brendan Eich (4 years ago)

John Barton wrote:

Now here is a reason, finally, for all the extra complexity the two goals cause.

If we want to kill script, let's not stab it with a dull pencil. Let's make Loader and System be modules, not globals. Then you cannot load modules with <script>, only with <module>.

We are not killing <script>. Dream on!

Introducing a new HTML element with implicit CDATA content model will require the old

<module>
<!-- hide script here
if (a < b) { console.log("<\/script> haha"); }
-->
</module>

hacks. This won't do anything (even render the HTML-commented-out fallback content) in old browsers, which will make it hard to work in both new and old.

Using <script> with a new attribute has several advantages, in contrast:

  1. No need for the return of the HTML comment-hiding hack I invented in Netscape 2 to avoid inline script content showing as fallback in pre-Netscape-2 browsers.

  2. Old browsers ignore the new attribute will process the content, which could be written to work "both ways".

But mainly: no way to kill script. Amending above words: do not dream on, wake up!

# David Sheets (4 years ago)

Is a new attribute necessary? What about using @type?

# Peter van der Zee (4 years ago)

<noscript type="module"></noscript>

"It's not a script, it's a module!"

# Allen Wirfs-Brock (4 years ago)

On Jan 24, 2014, at 6:33 PM, Brendan Eich wrote:

We are not killing <script>. Dream on!

Right, that's why I said "script syntactic goal". In 2A "script" refers to the ES6 Script grammar production, not the HTML <script> tag.

# John Barton (4 years ago)

Well, sorry my extra angle brackets. Let me try again.

Allen says, if I understand correctly, that the tiresome complexity of the second parsing goal will be repaid when the superior Module goal supplants the Script goal. But we undermine this tradeoff by allowing Scripts to use System and Loader.

The Script goal disallows 'import' and 'export' specifically to ensure that the Script goal is inconvenient for developers and thus they are encouraged to shift to the Module goal. By allowing 'System' and 'Loader', we allow exactly the range of possibilities forbidden by 'import' and 'export', undermining the mission of converting developers to use the Script goal.

Providing 'System' and 'Loader' via system modules rather than globals would seem to improve the chances of mission success.

# Brendan Eich (4 years ago)

David Sheets wrote:

Is a new attribute necessary? What about using @type?

Old browsers will ignore unknown types, losing the two-way fallback option.

# Brendan Eich (4 years ago)

Peter van der Zee wrote:

<noscript type="module"></noscript>

Again, no two-way fallback option. Clever thought re: implicit CDATA content model, though!

# Brendan Eich (4 years ago)

John Barton wrote:

The Script goal disallows 'import' and 'export' specifically to ensure that the Script goal is inconvenient for developers and thus they are encouraged to shift to the Module goal.

No, that's not the rationale. The reason is to avoid enabling more synchronous <script src=>-style jank. We have enough of that already with the existing attractive nuisance (script src= w/o async), per Steve Souders.

# Brian Di Palma (4 years ago)

Regarding the ".jsm" suggestion, a colleague suggested ".es", no need for the "m" as you could say all ES files are modules.

# David Sheets (4 years ago)

On Sat, Jan 25, 2014 at 11:26 PM, Brendan Eich <brendan at mozilla.com> wrote:

Old browsers will ignore unknown types, losing the two-way fallback option.

While it is possible to write scripts that change interpretation based on out-of-band metadata, is it desirable to encourage? Is it worth creating a new attribute on the script element for what should be a parameter of the media type?

Is there a reason that feature detection and a new media type or media type parameter would not suffice?

The HTML metadata aspect of the syntax goals is different from the general metadata hinting at the syntax type. If files with "es" or "jsm" extensions will be treated differently by some interpreters, this same indicator should be available at the media type level. If this indicator is available at the media type level, it should be usable in script/@type. If it is usable in script/@type, the interpretation/non-interpretation of that element can be used to detect the interpreter's capability in code common to both syntaxes.

I guess I'm not seeing the use case that is impossible under this scenario which requires one fewer duplicate way to transmit the same bit of metadata.

# Brendan Eich (4 years ago)

David Sheets wrote:

While it is possible to write scripts that change interpretation based on out-of-band metadata,

There is no out-of-band metadata in a new script attribute. Attributes are data, not data-about-data, and in-band in HTML.

is it desirable to encourage? Is it worth creating a new attribute on the script element for what should be a parameter of the media type?

Who says modules should be a media type parameter?

Is there a reason that feature detection and a new media type or media type parameter would not suffice?

I'm advocating feature detection based on a new attribute, not a new media type. I thought you were advocating the reverse.

# David Sheets (4 years ago)

On Mon, Jan 27, 2014 at 1:29 AM, Brendan Eich <brendan at mozilla.com> wrote:

There is no out-of-band metadata in a new script attribute. Attributes are data, not data-about-data, and in-band in HTML.

The channel is the contents of the script element or the ES resource. The attribute is not transmitted in the contents of the script element or ES resource. This seems out-of-band from the perspective of the programming language you are specifying.

Who says modules should be a media type parameter?

They can be annotated in a lot of ways. If you want to transmit a variation in interpretation of a media type, it would seem straightforward to do so either:

  1. in the content you are transmitting
  2. in the media type of the content you are transmitting
  3. in a parameter of the media type of the content you are transmitting

I'm advocating feature detection based on a new attribute, not a new media type. I thought you were advocating the reverse.

Is a new attribute to change interpretation behavior feature detection? Usually feature detection happens in the language using the features...

I'm advocating introducing the smallest possible number of ways to indicate the same bit of information. It seems that there is a demand for:

  1. a file extension
  2. a media type mechanism
  3. an HTML attribute
  4. in-language feature detection or declaration

Of these, the HTML attribute seems to be the least flexible and most coupled.

Is there a use case for 3 that is not covered by some combination of 1, 2, and 4? If 1 is used or encouraged, will you not specify 2? If neither 1 nor 2 is specified, will you expect each carrier specification (HTML, HTTP, file system, etc) to specify their own special way to convey this bit of metadata?

# Kevin Smith (4 years ago)

Old browsers will ignore unknown types, losing the two-way fallback option.

Two-way fallback? Why is that important? Since modules are implicitly strict, there is little intersection between scripts and modules.

# Brendan Eich (4 years ago)

David Sheets wrote:

The channel is the contents of the script element or the ES resource. The attribute is not transmitted in the contents of the script element or ES resource. This seems out-of-band from the perspective of the programming language you are specifying.

Same argument applies to a novel media type. It'll get stripped just as much as the module attribute, but the latter has the advantage that old browsers will ignore just the attribute, while with an unknown type= value or version parameter (which we rejected with 1JS), the contents will be ignored.

They can be annotated in a lot of ways. If you want to transmit a variation in interpretation of a media type, it would seem straightforward to do so either:

  1. in the content you are transmitting
  2. in the media type of the content you are transmitting
  3. in a parameter of the media type of the content you are transmitting

This is all abstract and off target. We know what old browsers do, RFC 4329 (www.ietf.org/rfc/rfc4329.txt) codified it. The concrete choice is between new script attribute and new script type or version parameter (other parameters than ;version would be ignored by old browsers, making them equivalent to a new attribute, but harder to detect).

Is a new attribute to change interpretation behavior feature detection? Usually feature detection happens in the language using the features...

I'm advocating introducing the smallest possible number of ways to indicate the same bit of information. It seems that there is a demand for:

1. a file extension

Talk here is not demand, and I bet we'll regret trying to add a new one. Extensions mapped by servers to media types require server configury, often missed or mangled. This has led in the past to clients hardcoding, e.g. text/javascript for missing content type / type= attribute / Content-Script-Type header in IE (older versions, not sure about 9 and up).

2. a media type mechanism

Also a pain, easy to get lost as "metadata", easy to mangle, easy to forget. IETF red tape is the least of it, but there's that too.

3. an HTML attribute

See my repeated points about fallback in old browsers, this is the way to win migration.

4. in-language feature detection or declaration

With module bodies in files in NPM and AMD, you don't need to detect anything. Clients require provided modules, there's no new suffix or MIME type.

Why should ES6 be different?

Now, say we add <script module>...</script> support. The ... bits can use export, but need not. It could use the module loader API to do its deed, detecting that API and falling back on global or other properties in old browsers.

Why shouldn't we support such two-way-compatible inline modules?

Of these, the HTML attribute seems to be the least flexible and most coupled.

We want most coupled between 3 and 4, because that's what enables two-way compatibility.

Is there a use case for 3 that is not covered by some combination of 1, 2, and 4? If 1 is used or encouraged, will you not specify 2? If neither 1 nor 2 is specified,

Do Not Want 1 or 2, as far as I can tell. Both new media type and new suffix face stiff adoption hurdles, hamper migration, add more typo and forgetfulness habitat, and smell bad. :-P

will you expect each carrier specification (HTML, HTTP, file system, etc) to specify their own special way to convey this bit of metadata?

It's implicit in filesystem cases such as NPM today, and that wins.

If you insist on treating it as meta- (or OOB, better, but same point here), please explain how filesystems convey media types today. Suffix conventions do not do it on Unixy systems. #! is in-band but not relevant to modules. Content sniffing considered harmful.

HTML is the prize. We aren't going to generalize any useful "module body here, not global code" in- or out-of-band attribute across all containers. We don't need to for the out-of-line module case anyway. Only <script> is recognized usefully in browsers old and new. This leaves two-way compatibility winning, by my current analysis.

# Brendan Eich (4 years ago)

Kevin Smith wrote:

Two-way fallback? Why is that important? Since modules are implicitly strict, there is little intersection between scripts and modules.

One can write strict code that runs fine in old browsers!

Why do we want inline module-bodied elements in HTML? That's the topic here. There is no issue for out-of-line module-bodied elements, AFAICT. Once you focus on inline bodies, you face harsh adoption barriers without enabling works-in-old-and-new coding.

# Kevin Smith (4 years ago)

Once you focus on inline bodies, you face harsh adoption barriers without enabling works-in-old-and-new coding.

OK, I follow.

# David Bruant (4 years ago)

Le 27/01/2014 06:45, Brendan Eich a écrit :

One can write strict code that runs fine in old browsers!

Yes. For transition from non-strict to strict and advice on writing strictness-neutral code, there is developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode/Transitioning_to_strict_mode?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FFunctions_and_function_scope%2FStrict_mode%2FTransitioning_to_strict_mode (reviews welcome)

Why do we want inline module-bodied elements in HTML? That's the topic here.

Indeed. I'm wondering why we need inline <script> for modules.

Historically, the good practice regarding inline <script> was to put them either in <head> or before </body> (the rest of the scripts can load after DOMContentLoaded/load or on demand). I imagine modules are intended to be reusable, "stateless", timing-independent pieces of code. If, for perf reasons, we do need JS to be in the page alongside the HTML, we don't need it to run right away.

I feel that without too much work, we can have best of all worlds. Module code could be sent along the HTML inlined, but with an unrecognized @type (and a class like "module"), so that it runs in neither old or new browsers. At a time decided by the author, the author can do:

 var scripts = document.querySelectorAll('script.module');
 if(es6modulesSupported){
     [].forEach.call(scripts, function(s){ loader.load(s.textContent) });
 }
 else{
     [].forEach.call(scripts, function(s){ (1, eval)(s.textContent)) };
 }

(I'm not sure about the edges, but you get the idea)

We get the network perf benefits of sending the modules over the wire. The only way it differs with inline scripts is the scheduling, but I wonder how often it'll be important to load modules before DOMContentLoaded.

# Kevin Smith (4 years ago)

OK, I follow.

However, I'm sympathetic with David because adding an attribute specifically to "fix" the JS script/module issue is design-entropy-increasing.

I wonder to what extent this might be a non-issue brought about by the lack of lexical modules.

# John Barton (4 years ago)

Thanks for the explanation.

Given all of the costs, perhaps it is worth reconsidering the benefit. Many issues affect the load timing of web pages, will this one change make such an improvement that it's worth the disruption it causes?

# David Herman (4 years ago)

On Jan 27, 2014, at 2:07 AM, David Bruant <bruant.d at gmail.com> wrote:

Indeed. I'm wondering why we need inline <script> for modules.

Because people write inline scripts all the time. It's unacceptably inconvenient not to be able to bootstrap your app with inline code. It also allows you to control for when the scripts resource is there, in particular to be sure that necessary bootstrapping/kernel code has loaded before you need to do some wiring up of your app.

But it's not even worth overthinking. It's so obviously, obscenely anti-usable not to be able to write

<script module>
import $ from "jquery";
import go from "myapp";
$(go);
</script>

inline that I'm surprised this is even a discussion.

# David Bruant (4 years ago)

Le 27/01/2014 19:41, David Herman a écrit :

On Jan 27, 2014, at 2:07 AM, David Bruant <bruant.d at gmail.com> wrote:

Indeed. I'm wondering why we need inline <script> for modules. Because people write inline scripts all the time. It's unacceptably inconvenient not to be able to bootstrap your app with inline code. It also allows you to control for when the scripts resource is there, in particular to be sure that necessary bootstrapping/kernel code has loaded before you need to do some wiring up of your app.

Agreed. Note that I didn't suggest to stop writing inline scripts and proposed an alternative to script at module that can work today. Granted, it's somewhat hacky, but I think it can work during the period during which there'll be both ES6 and non-ES6 browsers to support.

I was sloppy in my phrasing. What we don't need is the current inline script "execute right now and block everything else" semantics, specifically for modules which order of execution shouldn't block things.

But it's not even worth overthinking. It's so obviously, obscenely anti-usable not to be able to write

 <script module>
 import $ from "jquery";
 import go from "myapp";
 $(go);
 </script>

inline that I'm surprised this is even a discussion.

If the snippet is only targetting ES6 browser, it can work without the module attribute (I think?). This snippet doesn't work on non-ES6 browsers, though.

I feel two different problems are being discussed in this thread? One about inline modules, one about compatibility, (both a bit away from the original topic ;-)). I was on the compatibility track.

# David Herman (4 years ago)

[Resending, not sure why it's not getting through to the list...]

# David Herman (4 years ago)

On Jan 27, 2014, at 10:58 AM, David Bruant <bruant.d at gmail.com> wrote:

Agreed. Note that I didn't suggest to stop writing inline scripts and proposed an alternative to script at module that can work today. Granted, it's somewhat hacky, but I think it can work during the period during which there'll be both ES6 and non-ES6 browsers to support.

I was sloppy in my phrasing. What we don't need is the current inline script "execute right now and block everything else" semantics, specifically for modules which order of execution shouldn't block things.

OK, sorry I jumped in the middle of things missing some context. In fact, I think what we've been planning on proposing is not too far -- I think -- from what you're talking about. The plan is not a module attribute (that was a think-o on my part, and maybe some misinformation that crept into this discussion earlier?) but type="module". That way on old browsers it's ignored and you can add shims to load it. Shims can be made future-proof via feature detection, so type="module" can obtain new semantics.

Moreover, the type="module" should not actually mean "execute right now and block everything else," but rather "executing asynchronously once all my module dependencies are loaded and linked."

Does that make more sense? I realize part of the issue here is there isn't a concrete plan or proposal that's been spelled out, it's just been informal discussions. That's

# Brendan Eich (4 years ago)

David Herman <mailto:dherman at mozilla.com> January 27, 2014 at 12:03 PM

OK, sorry I jumped in the middle of things missing some context. In fact, I think what we've been planning on proposing is not too far -- I think -- from what you're talking about. The plan is not a module attribute (that was a think-o on my part, and maybe some misinformation that crept into this discussion earlier?) but type="module". That way on old browsers it's ignored and you can add shims to load it. Shims can be made future-proof via feature detection, so type="module" can obtain new semantics.

The shims word suggests that old-browser-targeted script must DOM-scrape the script type=module text and interpret it with Esprima or similar. This may not perform well enough compared to an AOT compiler, which is another option. Just weighing these.

Moreover, the type="module" should not actually mean "execute right now and block everything else," but rather "executing asynchronously once all my module dependencies are loaded and linked."

The detail I mentioned 1:1 of type= requiring IANA media types suggests something other than "module". Detail? Not to standardistas (Hi, Bjoern!).

Whatever the bootstrap inline script compatibility story, I agree having an inline bootstrap module-script is desirable.

# John Lenz (4 years ago)

On Sun, Jan 26, 2014 at 9:44 PM, Brendan Eich <brendan at mozilla.com> wrote:

Talk here is not demand, and I bet we'll regret trying to add a new one. Extensions mapped by servers to media types require server configury, often missed or mangled. This has led in the past to clients hardcoding, e.g. text/javascript for missing content type / type= attribute / Content-Script-Type header in IE (older versions, not sure about 9 and up).

This is concerning, an new file extension affects build systems, editors, servers, etc. This moves use back to something in the source code:

// hey, I'm a module not a script
"hey, I'm a module not a script";

?

# Brendan Eich (4 years ago)

John Lenz wrote:

This is concerning, an new file extension affects build systems, editors, servers, etc. This moves use back to something in the source code:

// hey, I'm a module not a script
"hey, I'm a module not a script";

?

It's pretty clear from NPM experience that a new suffix is not needed for out-of-line modules. Or are you suggesting that Node.js lacks tooling? I'm not offended, just trying to understand.

For NPM read AMD/require.js too.

# Brendan Eich (4 years ago)

Brendan Eich wrote:

# John Barton (4 years ago)

On Mon, Jan 27, 2014 at 2:51 PM, Brendan Eich <brendan at mozilla.com> wrote:

It's pretty clear from NPM experience that a new suffix is not needed for out-of-line modules. Or are you suggesting that Node.js lacks tooling? I'm not offended, just trying to understand.

What about the node experience helps? They have only one type of input, modules, ergo only one suffix.

For NPM read AMD/require.js too.

Ditto.

# Brendan Eich (4 years ago)

John Barton wrote:

What about the node experience helps? They have only one type of input, modules, ergo only one suffix.

No, their non-module main programs are in files with names ending in .js.

Ditto.

No, <script src=foo.js> interops with AMD/require.js and the .js suffix is used everywhere.

# John Barton (4 years ago)

On Mon, Jan 27, 2014 at 4:57 PM, Brendan Eich <brendan at mozilla.com> wrote:

No, their non-module main programs are in files with names ending in .js.

Their non-module main programs don't fail if you issue require().

No, <script src=foo.js> interops with AMD/require.js and the .js suffix is used everywhere.

Because it is js everywhere. Pick any file in an AMD/require.js system and you can parse it.

I think you are on the right track here: 1JS needs only one file suffix. If we have two languages, we need to suffixes.

# Brendan Eich (4 years ago)

John Barton wrote:

Their non-module main programs don't fail if you issue require().

Nor do browserify'ed or properly-written require.js client main scripts.

Because it is js everywhere. Pick any file in an AMD/require.js system and you can parse it.

ES6 cannot support require as a function that synchronously loads from the filesystem, and I think you know this.

I think you are on the right track here: 1JS needs only one file suffix. If we have two languages, we need to suffixes.

You do not have two languages, though. Two entry points to the grammar of the one language does not make "two languages". HTML event handlers are FunctionBodies. I think you have no argument.

# John Barton (4 years ago)

On Sat, Jan 25, 2014 at 3:31 PM, Brendan Eich <brendan at mozilla.com> wrote:

No, that's not the rationale. The reason is to avoid enabling more synchronous <script src=>-style jank. We have enough of that already with the existing attractive nuisance (script src= w/o async), per Steve Souders.

Why can't <script type='module'> mean "If we see import/export/module statements then we will will not evaluate the body synchronously."? That way we avoid the jank with new code just as we do with two parsing goals and yet we don't need two parsing goals.

# Kevin Smith (4 years ago)

ES6 cannot support require as a function that synchronously loads from the filesystem, and I think you know this.

Without a new extension, you cannot "import" from an old-style module in the browser or the server. One must know a priori how to parse the file before one parses the file. Old-style modules cannot (in general) be parsed as ES6 modules, and ES6 modules (in general) cannot be parsed as old-style modules.

# Brendan Eich (4 years ago)

Kevin Smith wrote:

Without a new extension, you cannot "import" from an old-style module in the browser or the server. One must know a priori how to parse the file before one parses the file. Old-style modules cannot (in general) be parsed as ES6 modules, and ES6 modules (in general) cannot be parsed as old-style modules.

Yes, so?

My argument was that Node.js has both non-module and module files with a common suffix, .js.

You are mixing compatibility with "consistency" arguments.

# Brendan Eich (4 years ago)

John Barton wrote:

Why can't <script type='module'> mean "If we see import/export/module statements then we will will not evaluate the body synchronously."? That way we avoid the jank with new code just as we do with two parsing goals and yet we don't need two parsing goals.

We could do this, but then refactoring from no-exports to exports, or no-imports to imports, changes order of execution. Surprising, undesirable without good reason (having one entry point to the grammar, or two instead of three if you count HTML event handlers, is not a good reason).

Note also that type="module" does not fly, the type attribute wants a media type value.

# Erik Arvidsson (4 years ago)

All browsers support non media types. Can we change the specs to match reality

# Kevin Smith (4 years ago)

My argument was that Node.js has both non-module and module files with a common suffix, .js.

Yes - but Node-modules and non-modules can be parsed the same way, so a common extension makes sense. But when a file needs to be parsed a different way in Node, how's that's done? By registered file extensions, of course.

# Brendan Eich (4 years ago)

On Jan 27, 2014, at 8:35 PM, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:

All browsers support non media types. Can we change the specs to match reality

Examples? What is the specified grammar?

I hope you aren't thinking of language= here.

How about fallback for old browsers?

# Domenic Denicola (4 years ago)

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich

Examples? What is the specified grammar?

From the HTML spec:

The type attribute gives the language of the script or format of the data. If the attribute is present, its value must be a valid MIME type. The charset parameter must not be specified. The default, which is used if the attribute is absent, is "text/javascript".

Then there's a bunch of other text regarding how the type attribute translates into MIME types and how mime types end up translating to "supported scripting languages", ending up at 3.


My understanding of what's been specified here, codified from legacy, is that browsers (since the dawn of time) always interpreted either missing type attribute or "text/javascript" as instructions to execute JavaScript code, and most other things as inert and ignored.

There's a bit of a gray area involving all the other "aliases" for text/javascript, e.g. some older browsers probably don't support text/livescript, while others probably don't support text/jscript.

The upside is that, as Arv says, you can put any string you want in there, and browsers will cope just fine by ignoring it unless it's one of the specific types that maps to JavaScript per 3. The spec has authoring conformance criteria that it must be a MIME type. But the actual codified behavior is closer to "if it's in this list of strings, or absent, you get JavaScript; otherwise it gets ignored, unless the browser wants to implement VBScript/Dart/etc. using some other magic string."

# Brendan Eich (4 years ago)

Domenic Denicola wrote:

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of Brendan Eich

Examples? What is the specified grammar?

From [the HTML spec][1]:

The type attribute gives the language of the script or format of the data. If the attribute is present, its value must be a [valid MIME type][2]. The charset parameter must not be specified. The default, which is used if the attribute is absent, is "text/javascript".

Then there's a bunch of other text regarding how the type attribute translates into MIME types and how mime types end up translating to "supported scripting languages", ending up at [3].


My understanding of what's been specified here, codified from legacy, is that browsers (since the dawn of time) always interpreted either missing type attribute or "text/javascript" as instructions to execute JavaScript code, and most other things as inert and ignored.

Right, that doesn't mean the type can be any old string and have new meaning, though. More the reverse.

There's a bit of a gray area involving all the other "aliases" for text/javascript, e.g. some older browsers probably don't support text/livescript, while others probably don't support text/jscript.

Those are long dead. RFC 4329 defines properly registered IANA media types, application/javascript and application/ecmascript. The text/javascript misnomer was created without being registered by Dave Raggett for HTML4. It is shorter than application/javascript, so hard to kill now. But at least it's a media type.

The upside is that, as Arv says, you can put any string you want in there, and browsers will cope just fine by ignoring it unless it's one of the specific types that maps to JavaScript per [3].

Yes, this is part of the fail-soft nature of HTML. But it does not mean the HTML grammar allows anything for specified cases -- in fact for those as you say, it requires an IANA media type. Old content on the web could today use module and count on content being ignored (not that I know of any, or think this is likely).

Defining new types should follow the rules, not just extend the domain of type to random strings we think we can get away with.

# John Lenz (4 years ago)

There are three issues in my mind for tooling:

  1. should the code be parsed as "use strict"
  2. are "import" and "export" and "module" statements valid
  3. should top level declarations be considered visible outside the file (no can be inferred from the presence of import or exports)

It is my guess that it will be a common beginner mistake to load modules as scripts or try to use "import" from scripts. The first is the primary one as keywords etc are different.

# Brendan Eich (4 years ago)

John Lenz wrote:

There are three issues in my mind for tooling:

  1. should the code be parsed as "use strict"
  2. are "import" and "export" and "module" statements valid

Note no "module" form in ES6.

  1. should top level declarations be considered visible outside the file (no can be inferred from the presence of import or exports)

It is my guess that it will be a common beginner mistake to load modules as scripts or try to use "import" from scripts. The first is the primary one as keywords etc are different.

You could be right -- we should find out. The "mistake" has a flip-side, if we allow it: detection-based two-way module-scripts.

# Erik Arvidsson (4 years ago)

On Tue, Jan 28, 2014 at 12:32 PM, Brendan Eich <brendan at mozilla.com> wrote:

Note no "module" form in ES6.

module M from './path/to/module';

is a valid ModuleItem.

# Brendan Eich (4 years ago)

Ah, right. I thought John meant module M {...}.