I am learning javascript. I read about how to import and export things between javascript modules. I am making a javascript game which consists of several files. Each defines a class and its methods.
I have two questions:
Only one of the files actually contains code that interacts with the DOM, so in the HTML do i need to include <script src="..."></script> for every js file? or only the one that deals with the DOM?
I first tried only referencing the one js file in the index.html and exporting the classes defined in the other js files and importing them in the js files where those classes are used. But no browser seemed to understand the import/export statements? Isn't that done on client side javascript?
You need referencing all js file in the index.html, because your game will use other file as the module for entry file. And the module file need to be referenced before the entry file.
Yes, export/import can not be used on client side directly, its used in nodejs platform mostly with supporting by some tools like typescript or babel. But you can use them with some tools as told before.
so, i think you can use babel to transform your code to es5 target firstly, then that you can reference them in browser.
If you mean ES6 imports, the import Whatever from “some-resource”; statement requires the “some-statement” to be a URL.
Additionally, the “entry point” script should be <script type=“module” src=“some-url”></script>. The “module” is what tells the user agent that it is loading a JavaScript module and that import statements should be resolved.
You only need to include one <script> tag if that one script correctly imports the rest of your dependency chain.
Browser support for this is still somewhat limited which is why using webpack or some other build step is still recommended until the feature is fully fleshed out.
currently import / export syntax is supported by approximatively 75% of all users browser (caniuse.com).
The very first thing is to put type="module" as an attribute of a <script tag> (Eg. <script type="module">)
Then you can import/export in your modules. And YES modules need to export a value (variable, function...) to be able to use it in another script, but this is optionnal since you can just execute script without the need to export something.
Documentation:
import
export
Very good article on how to use module in browsers
Keep in mind that is not yet a supported feature and you will need a polyfill if you mind about browser compatibility
Related
Issue description
I would like to have Visual Studio Code to hint autocompletion and provide documentation for a JavaScript project which includes libraries a module in a separate HTML file.
Context
I am using P5JS. It assumes we include the P5JS library and our script via the <script src="…"> tag in an HTML file. Autocompletion and documentation work after installing the p5.vscode extension. So, no problem here.
I am also using ml-matrix, which I'm including in the HTML via the <script src="…"> tag. The library constructors and methods can be accessed via mlMatrix.. (I figured this by toying around in the console, and I wouldn't know otherwise how to find out I need to prepend mlMatrix. to all functions in the library.)
index.html
<head>
<!-- script src="…" P5JS libraries -->
<script src="./node_modules/ml-matrix/matrix.umd.js"></script>
</head>
<body>
<script src="./script.js"></script>
</body>
script.js
A = mlMatrix.Matrix.eye(3) // no autocompletion or docs, code runs
console.log(A)
Workaround
Adding import * as mlMatrix from "ml-matrix" to the beginning of script.js makes autocompletion and documentation work, but the overall project does not run. So, I have to comment and uncomment the first line every time I save and preview my edits on the browser.
script.js
import * as mlMatrix from "ml-matrix"
A = mlMatrix.Matrix.eye(3) // autocompletion and docs work, code doesn't run
console.log(A)
When loading the HTML, the browser complains with script.js:1 Uncaught SyntaxError: Cannot use import statement outside a module..
Desiderata
I'd like to be able to save and preview my project while having a working autocompletion and documentation hint from VSC.
Debugging
After reading a few sections of David Flanagan's «JavaScript: The Definitive Guide», I started figuring out what's going on. So, I'm reporting here my current understanding.
JavaScript, or rather ECMAScript, used to be a scripting language.
Scripts loaded with <script src="…"> are "global" scripts, living on the current page, injecting vars and functions in the global scope (or window object).
In order to support proper software engineering relying on modularity, modules were introduced in 2015, in ECMAScript 6, or ES6 in short. To import a module in an HTML document one can use <script type="module" src="…">.
Now, to import a module in a JS file, the file itself needs to be a module. So, dealing with an actual script myself, I cannot do such a thing.
Even by <script src="…"> a module, it won't inject itself in the main namespace. It will create a whatever name where it will store everything it exports. So, now we are at the point where we need to instruct the IDE that a module has been loaded on the HTML side with a specific name and it's used in a JS script.
So, we have now a more articulate question.
Issue re-statement
How to inform VSC that a module has been loaded through the HTML page?
I believe a probable answer will include some custom jsconfig.json to be created. Right now I have zero clues about how to do this.
Another solution would be using some specific ///<reference path="…"/> at the beginning of the JS file. Also for this I have no specific knowledge.
Scenario
As part of my prototyping process I wanted to bring in tween.js which I can do using a <script> tag on the html portion but I'd like to import this vanilla es5 file directly to my es6 files for various reasons.
What I'd like to do is something like
import * as TWEEN from 'import * as TWEEN from 'https://cdnjs.cloudflare.com/ajax/libs/tween.js/16.7.0/Tween.min.js'
While that seems to load the remote file I don't seem to get methods like TWEEN.Tween etc etc. I suspect all the es5 is disposed of in some sort of closure vacuum > garbage collection.
Question
I realize I can clone this file locally but I'm hoping to streamline my one-off style prototyping by importing cdn files that aren't always es6 friendly. Is this feasible ?
If you would like to inject Tween.min.js which is hosted on CDN via script tag, it will be UMD module, which is not compatible with ESM modules.
But, instead of importing it like you describe above, you can use/call it via window object:
window.TWEEN inside your esm modules.
When Tween.min.js will be loaded and executed it will be attached to window object.
Just to make sure that you are load that script first separately on HTML side, before your esm scripts/apps, otherwise window.TWEEN might be undefined.
Can't understand the difference between the two examples that I just read at the end of the Deno manual section on the deno bundle command:
Bundles can also be loaded in the web browser. The bundle is a
self-contained ES module, and so the attribute of type must be set to
"module". For example:
<script type="module" src="website.bundle.js"></script>
Or you could import it into another ES module to consume:
<script type="module">
import * as website from "website.bundle.js";
</script>
I was under the impression that both forms achieve the same effect (i.e., "fetched and executed immediately, before the browser continues to parse the page"), and the latter is used when a script follows or one wants to narrow down what is imported (e.g., as seen in this answer).
Section 16.6.1.2 Modules of the Exploring ES6 book appears to agree with this assessment.
Reddit thread Difference Es6 import module vs script src="" also seems to confirm this: "Instead of dumping an entire library into your global scope you an instead only include what you need and actually use."
This may be considered a duplicate of other questions (see bottom for the list) but those answers didn't help me much, and the ancillary sources also didn't seem to reveal if my assumption is correct. (On the other hand, it is more than possible that I overlooked something obvious and would have to work on my reading comprehension skills...)
Load javascript as an ES6 module OR via a script tag in the page (tangentially related)
What is the difference between a script tag with src and a script tag that requires a module? (looked promising but not about ES6 modules...)
Classic scripts v/s module scripts in Javascript
WHATWG: Adding JavaScript modules to the web platform
Import js from script tag in HTML file. Possible?
What is the difference between importing js library or reference it in html <script> tag (not about ES6 modules)
Should I reference files in a `script` tag when using ES6 modules in a browser
ES6 import vs <script src> in html
I was under the impression that both forms achieve the same effect
Yes, both of these will have the same effect
(i.e., "fetched and executed immediately, before the browser continues
to parse the page"),
No, that any <script with type="module" will defer by default, so the loading will not block parsing. All deferred scripts are then executed in the order they appear, after parsing and before DOMContentLoaded fires.
and the latter is used when a script follows or
one wants to narrow down what is imported (e.g., as seen in this
answer).
Which one you want to use also depends on what work is done in the bundle. If the bundle only contains libraries, and doesn't create any side effects (ie, interacting with the page, rendering, etc) then you will probably want to import it so that you can use the functions.
If it does have side-effects (ie. a react app that renders to the DOM), and is self-contained, then just including the tag will be enough to get it started
This is vague - I apologize in advance, I am trying to be as succinct as I can with my limited understanding, while exposing my potentially incorrect assumptions.
I have a website that's literally one huge HTML file. It runs scripts defined in-line in a <scripts> tag.
My goal is to move all the scripts into individual .js files and pull them into index.html (or into one another where required). I am familiar with the usage of Node's require and I am familiar with import, as used in Angular. I stress usage because I don't really know how they work.
Assumption 1: I cannot use require - it is purely for Node.js. The reason I bring it up is that I am pretty sure I have seen require in AngularJS 1.5 code, so assuming makes me uncomfortable. I am guessing this was stitched together by WebPack, Gulp, or similar.
Assumption 2: I should use import, but import only works with a URL address, if I have my .js hosted on a server or CDN, it will be be pulled. BUT, I cannot give local pathing (on the server) here - index.html will NOT automatically pull in the dependencies while being served. I need npm/Webpack/other to pre-compile my index.html if I want the deps pulled in on the server.
Assumption 3: Pre-compiling into a single, ready-to-go, html file is the desired way to build things, because the file can be served quickly (assuming it's ready to go). I make the assumption with the recent trend of serving Markdown from CDNs, the appearance of the JAMstack, and the number of sites using Jekyll and such (though admittedly for traditional Jekyll sites).
Assumption 4: I also want to go to Typescript eventually, but I assume that changes nothing, since I will just pull in TS to compile it down to .js and then use whatever solution I used above
Question: If it's clear what I am trying to do and what confuses me, is a decent solution to look into npm/Webpack to stich together my .js files? What would prepare them for being stiched together, using import/export? If so, is there an example of how this is usually done?
As you mentioned, require cannot be used for your purposes, since it is a part of CommonJS and NodeJS's module system. More info on require can be found here: What is this Javascript "require"?
Import is a ES2015 standard JS syntax. But ES2015 standard and everything above it has very limited browser support. You can read more about it here: Import Reference
However, you can still code in the latest standard (thereby enabling the use of import/export etc.,) and then transpile the code to be able to run on the browser. Inorder to do this, you require a transpiler. You can refer Babel which is one of the most popular transpilers : https://babeljs.io/
For your exact purpose, you need to use a module bundler. Webpack/Rollup etc., are some popular module bundlers. They can automatically identify all the JS files referenced through import, combine them and then transpile code to be able to run on the browser (they also use a transpiler) and produce a single JS file (or multiple, based on your configurations).
You can refer the getting started guides of Webpack: https://webpack.js.org/guides/getting-started/
or RollupJS: https://rollupjs.org/guide/en#quick-start
Since mostly we're using modules and import statement transpiling them with tools like Babel, I'm intrigued about how native Web browser's implementations will load external files with the so-called import statement.
Will modules be loaded using XmlHttpRequest/XmlHttpRequest2 under the hoods?
AFAIK, the whole standard defines a programmatic API as System global variable where there're methods like System.define to evaluate a JavaScript source code and register it as a named module.
Does this mean that actual module system implementation won't cover external file module loading (meaning that a library/framework or your own vanilla JavaScript code should get the source code using an XmlHttpRequest?)
There is a loader standard being actively developed by the WHATWG that will handle the loading in the browser: http://whatwg.github.io/loader/
As this is still a work in progress, things might still change. As far as I can see, the exact way that the browser loads the files is not specified, but it is probable that it will use the Fetch API (the Promise-based replacement for XmlHttpRequest2).
In the end, you should be able to use the module syntax with script tags and the browser (or whatever your JS environment is) will handle the loading:
<script type="module">
import x from 'y';
import a from 'b';
...
</script>
or
<script type="module" src="y.js"></script>
Currently, browsers are at different points of implementation:
IE/Edge: Under Consideration
Firefox: In progress
Chrome: In progress
Webkit: Meta Bug
Please feel free to correct me or extend this answer.