Open scripting opened 3 years ago
This may be one of those times where carefully writing the question helped me answer it.
This seems to be a basic rule.
Any code that calls into a module must itself be a module.
As far as I can see none of the tutorials states this limit.
Normally, code.js would just be JavaScript code, and I'd have a routine in there called startup, which I'd call from the body of index.html. This is just a convention I established so all my web apps would work this way.
Well you can't import from a non-module, so that means this convention won't work in this context. code.js must be a module for it to even begin to participate in the module system. That seems like a wrong design decision, I've been using modules under different names since UCSD Pascal units in 1979. You want to be able to use a package/module/unit whatever you call it, from normal non-module code.
Also all the demos I've seen stack the modules, making it more complex. A Hello World must be as simple as possible to illustrate the idea. There are a lot of things I can't tell if they're part of a bigger demo and not related to modules, so I'll keep reducing my Hello World app until something stops working.
Annoyance -- I learned NPM modules, why did they do it differently here? I suspect they'll say they were first, but not in my life they weren't. I've built a whole system of modules. It's like having a vinyl record collection and having to create a whole new collection when cassette tapes come out. Ugh.
Take for example my daveutils package. A ton of routines, you call them like this:
const utils = require ("daveutils");
const whenstart = new Date ();
console.log (utils.secondsSince (whenstart));
I like that everything from the daveutils package is referred to as utils.something.
That doesn't seem to apply to ES6 modules.
I suppose you can create that effect.
If you use import * as canvas from './modules/canvas.js';
, rather than explicitly indicating what you're importing, you'll get that behavior - canvas.create()
, etc.
(Note all the import forms at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
Well you can't import from a non-module, so that means this convention won't work in this context. code.js must be a module for it to even begin to participate in the module system. That seems like a wrong design decision, I've been using modules under different names since UCSD Pascal units in 1979. You want to be able to use a package/module/unit whatever you call it, from normal non-module code.
The reason for this restriction (iirc) is that it being a module lets you interact with the module import graph, which is important and would be a breaking behavior change in some cases for legacy scripts.
But you can manually handle the import graph, and thus use modules from non-module code, if you call the import("./module.js")
function instead - it'll return a promise for the module, rather than pausing your script until the import resolves. (You can, of course, mimic the behavior by immediately await
ing the promise.) This'll resolve to an object similar to what you'd get from the import * as foo
syntax, but with a special key for the default export as well.
First, thanks for all the help. :-)
As promised here's the Hello World app.
https://github.com/scripting/es6ModulesHelloWorld
Please continue to use this thread for any questions, comments.
I don’t think putting code.js in the
element has any effect. Module scripts are always loaded async. You could try some System.logs to see if you can detect any difference with where it goes. It is presumably defined in the HTML specification, maybe somebody else here knows for sure.Modules initialize roughly bottom up in import order starting from roots modules (modules with no used exports) in the order they occur in the HTML file. Initialization of a module first initializes all of the modules it imports (skipping modules that have already been initialized) and then evaluating the body of the module. Do this recursively top-down resulting in bottom up execution of uninitialized module bodies.
One important thing to know that isn’t covered by your hello world: the bindings that are imported are read only to the importer. In your example, code.js can’t assign to secsSince
but module.js can. If module.js changed the value of secsSince
, that change would be visible to code.js.
The code works. You can try it, this link was in the readme file.
Allen I have no idea what the rest of it means.
Yes, I know it works as written. I've fixed some typos and tried to clarify my previous comment.
Okay I think this is the line you're referring to.
document.getElementById ("idMessagePlace").innerHTML = "Number of seconds since March 12, 2020: " + secsSince ("March 12, 2020");
What is it doing that you disagree with>?
No, that line is fine.
Clearly, it all works.
I was questioning why <script type="module" src="code.js"></script>
was nested within <head>
rather than <body>
.
I understand that for this simple program it makes absolutely no difference where you put it. I mostly wanted to point out that for module scripts there are new rules for interpreting the script loading attributes. EG: from https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
async HTML5 For classic scripts, if the async attribute is present, then the classic script will be fetched in parallel to parsing and evaluated as soon as it is available.
For module scripts, if the async attribute is present then the scripts and all their dependencies will be executed in the defer queue, therefore they will get fetched in parallel to parsing and evaluated as soon as they are available.
Okay now I understand what you were saying. I did that without any thought because that's where I always put my includes. I never put them in the body. No reason why.
I usually have a bit of code in the body that calls the startup function in code.js. But that depends on jQuery, and I didn't want to include that in this Hello World app. Minimal dependencies.
I think I found out somewhere in this exploration that I couldn't call a function in a module from the body.
Anyway I have my Hello World, I'm ready to move on. :-)
<script>
$(document).ready (function () {
startup ();
});
</script>
I think I found out somewhere in this exploration that I couldn't call a function in a module from the body.
You can call it from a \ Githubissues.
I had a modest goal for today, to understand how ES6 modules work and have a simple Hello World app that demonstrates.
I've tried to work my way through a bunch of tutorials, the only one that I found that has downloadable demo app is from Mozilla, and I downloaded them, and uploaded the simplest one to a test server, and ran from the browser, Chrome on a Mac.
It works. Here's a link.
http://hunter.scripting.com/moduletest/
Note that will probably not exist for a long time.
So I'm trying to figure out the flow. I set a breakpoint at the beginning of main.js, and it does run, and I stepped through it and it worked.
But here's the question -- how did it get to main.js?
I don't see a call to any script in there from index.html. In fact there is no JS code in index.html.
So that's the beginning. How does this flow? Help appreciated.