This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 25868 - <script module>
Summary: <script module>
Status: RESOLVED MOVED
Alias: None
Product: WHATWG
Classification: Unclassified
Component: HTML (show other bugs)
Version: unspecified
Hardware: Other other
: P3 normal
Target Milestone: Unsorted
Assignee: Domenic Denicola
QA Contact: contributor
URL:
Whiteboard: blocked on ES6
Keywords:
Depends on:
Blocks: 22700
  Show dependency treegraph
 
Reported: 2014-05-22 22:39 UTC by Ian 'Hixie' Hickson
Modified: 2015-12-28 21:57 UTC (History)
11 users (show)

See Also:


Attachments

Description Ian 'Hixie' Hickson 2014-05-22 22:39:31 UTC
We need some way to tell JavaScript that the module being loaded is a JS module and not a program, since they currently use out-of-band signalling to decide how to parse a script file.

Probably a "module" attribute, as in <script module>.

Maybe the attribute should take the name of the module, so that it can be referenced from "import"? As in:

   <script src="jquery.js" module="jquery"></script>

...so that later people can do:

   import jquery from "jquery";

...or whatever.

What hooks in the JS spec should I be invoking?
Comment 1 Dimitri Glazkov 2014-05-22 22:46:32 UTC
https://github.com/dherman/web-modules
Comment 2 Ian 'Hixie' Hickson 2014-05-22 23:46:53 UTC
arv and esprehn on IRC pointed out that using type="" would have the advantage of preventing legacy UAs from running modules. It would have the disadvantage of either being ugly or requiring that we warp the syntax of type="" to allow non-MIME types. Also, it wouldn't be orthogonal with the language selection, so if some future language also wanted something to be able to distinguish between modules and programs, it wouldn't be able to use the same mechanism.

It's not clear to me why you'd ever want to have a page both have programs (which would run in old and new UAs) and modules (which would only run in new UAs), but if that's something that's gonna happen, it's worth bearing in mind.

What exactly are people expecting the deployment for modules to look like in the transition period before they're widely supported?
Comment 3 Anne 2014-05-29 09:18:37 UTC
I think the expectation is that they would be supported using a polyfill. The hook in JS seems to be that it needs to be processed per the rules in http://people.mozilla.org/~jorendorff/es6-draft.html#sec-modules Not sure if there's a more detailed hook.

I think the current proposal is to have <script type=module> and support <module> as well as a longer term solution once support is everywhere. Reasoning being that <module> is in equal length to <script> and that we want everyone to bootstrap from that as it's asynchronous and nice. Shorter names converts more developers.
Comment 4 Ian 'Hixie' Hickson 2014-05-29 18:27:37 UTC
<module> is a non-starter IMHO. A quarter of the tokeniser today is parsing scripts. It's massively confusing. We wouldn't want to introduce another element that was just as bad. Even worse, doing so would be a source of security issues, since it introduces radically new ways to parse the same content in new UAs vs legacy UAs. Introduce the element with different parse rules would be bad too, because it would mean that moving script from <script> to <module> would result in hard-to-explain breakage.

It's not clear to me what everything will use modules, anyway. Event handlers aren't going to support modules (unless we want to introduce onclick-type="module" and so on...). (I don't really understand why we wouldn't just make modules self-identifying. It's the only thing that's actually going to work long term, IMHO; e.g. automatically switch to module mode if the script starts with 'import', 'export', or 'module'.)

How are we going to do inline modules?
Comment 5 Dave Herman 2014-06-03 00:24:28 UTC
> A quarter of the tokeniser today is parsing
> scripts. It's massively confusing. We wouldn't want to introduce another
> element that was just as bad.

That's what abstraction/parameterization is for. :) The tokenizing and parsing of <script> and <module> should work the same, so there shouldn't be code duplication.

> Even worse, doing so would be a source of
> security issues, since it introduces radically new ways to parse the same
> content in new UAs vs legacy UAs.

Do you mean because existing content could already be using <module> and expecting it not to contain executed script? I'm happy to do web compat investigation.

> Introduce the element with different parse
> rules would be bad too, because it would mean that moving script from
> <script> to <module> would result in hard-to-explain breakage.

This isn't an issue. The Module non-terminal simply allows more forms than the Script non-terminal does. ES6 modules were carefully designed to have a smooth migration path from pre-ES6 scripts.

> It's not clear to me what everything will use modules, anyway. Event
> handlers aren't going to support modules (unless we want to introduce
> onclick-type="module" and so on...). (I don't really understand why we
> wouldn't just make modules self-identifying.

Let's not make bad law from hard cases. The point is to get it so that the vast majority of development is done in a simpler JS semantics where you don't have to learn all the quirks of ES sloppy mode. Meanwhile attributes are commonly used for small amounts of code like calling some function defined elsewhere; and there the differences between strict mode and sloppy mode are not much of an issue.

> It's the only thing that's
> actually going to work long term, IMHO;

Hm, but you haven't made arguments about the long-term. The reason why <module> is important *is* for the long term: once it reaches saturation in major browsers, it becomes a better overall development experience where people can stop worrying about quirks of the past. The point is to be a successful model like <!doctype html> rather than an unsuccessful mode like "use strict". The reason why <!doctype html> is successful is because it's no more boilerplate than the doctype declarations that preceded it.

> e.g. automatically switch to module
> mode if the script starts with 'import',

This doesn't work because not every top level program has imports, but we want a single uniform syntax for writing top-level programs, regardless of their content. Meanwhile you get semantic cleanups like fixing up the mess of block-local function scope and automatic strict mode without having to declare "use strict".

What I'm arguing for is another success story like <!doctype html>. Something that is as convenient as its predecessors in terms of top-level boilerplate, but offers programmers a cleaner overall semantics that eliminates past quirks. Moreover, it offers the ability to declaratively import from asynchronously loaded modules -- the primary purpose of modules -- and which is fundamentally at odds with the default synchronous loading semantics of <script>.

> 'export', or 'module'.)

(The 'export' and 'module' cases are irrelevant. Top-level code can't export -- what clients would it be exporting to? -- and there is no 'module' keyword or contextual keyword in ES6, because modules do not declare their own name.) 

Having to tell people to write "use modules" or "use es6" or something like that for the cases where they happen not to have imports would be an unacceptable author UX.

> How are we going to do inline modules?

I don't understand the question -- what sense of inline do you mean here?

Dave
Comment 6 Simon Pieters 2014-06-03 08:34:21 UTC
> That's what abstraction/parameterization is for. :) The tokenizing and
> parsing of <script> and <module> should work the same, so there shouldn't be
> code duplication.

Please let's not introduce a new element with the same parsing as <script>. <script> parsing is on crack.

> Do you mean because existing content could already be using <module> and
> expecting it not to contain executed script?

Different parse trees is a potential source of security issues. e.g. <!-- --> has had security problems.

> This isn't an issue. The Module non-terminal simply allows more forms than
> the Script non-terminal does. ES6 modules were carefully designed to have a
> smooth migration path from pre-ES6 scripts.

I think Hixie meant HTML parsing, not ES parsing.

> Hm, but you haven't made arguments about the long-term. The reason why
> <module> is important *is* for the long term: once it reaches saturation in
> major browsers, it becomes a better overall development experience where
> people can stop worrying about quirks of the past.

In that case you most definitely don't want the parsing behavior of <script>.

> The point is to be a
> successful model like <!doctype html> rather than an unsuccessful mode like
> "use strict".

I don't think the doctype is something we should consider a success that we should be copying. http://quirks.spec.whatwg.org/#history

> The reason why <!doctype html> is successful is because it's
> no more boilerplate than the doctype declarations that preceded it.

It's longer than no doctype.
Comment 7 Ian 'Hixie' Hickson 2014-06-03 18:16:10 UTC
(In reply to Dave Herman from comment #5)
> Do you mean because existing content could already be using <module> and
> expecting it not to contain executed script? I'm happy to do web compat
> investigation.

I mean that:

   <module>
    /*
       <script>
          ... this content is only visible to old UAs, not new UAs ...
       </script>
    */
    <!--
   </module>
   <script>
     ... this content is only visible to new UAs, not old UAs ...
   </script>
   -->

This is a security problem. It means that to sanity check scripts you have to parse them both ways.


> This isn't an issue. The Module non-terminal simply allows more forms than
> the Script non-terminal does. ES6 modules were carefully designed to have a
> smooth migration path from pre-ES6 scripts.

I meant at the HTML level, not the script language level.

The following means one thing today:

   <script id="a">
    <!-- this <script> block is an example
    w('</foo>');
    w('</script>');
    w('</module>');
    w('</bar>');
   </script>
   <script>
    w('2');
   </script>

If you change the <script> elements to <module> elements without the wacked quirks of <script> parsing, you'll find you suddenly have a very different page on your hands, and your script won't work at all.


> Hm, but you haven't made arguments about the long-term. The reason why
> <module> is important *is* for the long term: once it reaches saturation in
> major browsers, it becomes a better overall development experience where
> people can stop worrying about quirks of the past.

I think the benefits of modules are wildly overstated here, and it's not clear to me how, if event handlers are still not modules, it would actually work in practice (how would you import the functions you want to call from the event handlers?), but let's put that aside. The bigger problems are those described above. Either we in fact don't leave quirky parsing behind, or we end up in a world where <module> and <script> parse differently (at the HTML level!) in the same browser. Neither is a good authoring experience, IMHO.


> The point is to be a successful model like <!doctype html>

<!DOCTYPE HTML> is not a successful model. It's an example of one of the Web's worse failures. We require boilerplate that does nothing useful for the author, but is required to avoid crazy behaviour.

What I would have _liked_ is for there to be no "quirks" vs "no-quirks" modes, and for there to be no DOCTYPE. _That_ would have been a success.


> rather than an unsuccessful mode like "use strict".

I don't understand why "use strict" is not a success. Can you elaborate on that?



> > e.g. automatically switch to module
> > mode if the script starts with 'import',
> 
> This doesn't work because not every top level program has imports,

That's why I also suggested two other keywords:

> > 'export', or 'module'.)
> 
> (The 'export' and 'module' cases are irrelevant. Top-level code can't export
> -- what clients would it be exporting to? -- and there is no 'module'
> keyword or contextual keyword in ES6, because modules do not declare their
> own name.) 

Right, I'm saying that the better solution would have been for them to declare their own name. That would have given us an unambiguous way to be able to identify modules without out-of-band data. It solves the event handler problem, it solves the ugly boilerplate problem, and it solves the "how do I depend on inline scripts" problem.


> Having to tell people to write "use modules" or "use es6" or something like
> that for the cases where they happen not to have imports would be an
> unacceptable author UX.

We are doing that. We're just spelling it type="module" instead.


> > How are we going to do inline modules?
> 
> I don't understand the question -- what sense of inline do you mean here?

How do you define a module in a <script> block that is then imported by another?

<script type=module>
 ... my module that defines a function ...
</script>

<script type=module>
 ... another module that uses it ...
</script>

Consider for example if the first <script> above has jQuery pasted into it, and the second is a module that uses jQuery.
Comment 8 Ian 'Hixie' Hickson 2014-09-11 23:09:55 UTC
Right now this is blocked on https://bugs.ecmascript.org/show_bug.cgi?id=3138 (I can't spec how ES6 and HTML integrate until the ES6 side is ready).
Comment 9 Domenic Denicola 2015-12-28 21:57:58 UTC
https://github.com/whatwg/html/pull/443