ES6 Features 14: Modules
This is an entry in the ES6 Features series on my blog here. Check out the full series list here.
1 year and 4 months later, and we're finally seeing es6 modules start to land in a browser near you (currently Chrome, Firefox with a flag, Edge 16+, and Safari). Since I've been having to refer back to several different blog posts on the subject at once just to remind myself of a particular aspect of the new syntax, how it's used, and how it interacts with other parts of the syntax, I thought I'd blog about it here.
Before we begin, a note on enabling it in your browser. In Firefox, you need to visit about:config
and set dom.moduleScripts.enabled
to true
instead of false
(or create it if it doesn't exist). In Chrome 60, you need to go to about:flags
and enable experimental javascript features or some such similar flag. Other browsers may either have it enabled by default, or require a variant on the above to get it to work.
With that, let's look at what it actually is and what it allows us to do that we couldn't before. Have you ever run into this issue before?
<script src="javascript/Vector.js"></script>
<script src="javascript/engine.js"></script>
<script src="javascript/main.js"></script>
<script src="javascript/LineSimplifier.js"></script>
<script src="javascript/Bezier.js"></script>
<script src="javascript/render.js"></script>
<!-- ... -->
It's a bit of a mess, right? Such is the problem with splitting one's code across multiple files in Javascript without a preprocessor such as Browserify or webpack.
Thankfully, it does not have to be this way! It's ES6 modules to the rescue. ES6 modules let us break our code down into discrete components that describe which other components they require. In this way, these components can be found and loaded by the browser on it's own - instead of us having to specify a whole load of <script />
tags and hope we've got them in the right order.
Let's take it from the top. Here's how you tell the browser you're loading a module and not a regular script:
<script type="module" src="./js/index.js"></script>
The above loads the file ./js/index.js
as a module. In there, we cna do things like add an onload
event listener to the window
object to kick things off - in fact you can do practically anything you could in a normal script. Let's take a look inside an example module:
"use strict";
import Vector from "./lib/Vector.js";
import { Banana, Apple } from "./Fruits.js";
window.addEventListener("load", function(event) {
// ......
});
Referencing another module is done with an import
statement. Currently, most browsers require the ./
(or /
or even a fully-qualified URL) at the beginning, and don't allow you to drop the file extension like you can in Node.JS - though this may change in the future.
I've given 2 different examples of import
statements above - the first one (line #3) imports the default export and assigns it to Vector
, and the second one (line #4) imports a pair of specifically named exports.
The next natural question here is how to export things so that we can import them. That's easy too:
export default Pineapple;
export { Apple, Banana, Kiwi as Coconut };
export function travel(start, finish) {
// ....
}
As you can see, it's quite flexible actually. You can specify a default export with export default ThingName
for use with the default import statement above, and you can export specifically named things - and even give them alternate names! Lastly, you can also export things as you define them - like I have with the travel()
function above.
That just about covers everything. I'll leave a bunch of links below that go into more depth than I have here. I can already see the endless possibilities with this - I just wonder if anyone's built a preprocessor that concatenates all your modules into one file - whilst maintaining the ability to debug it effectively.... perhaps I'll have to do some research.
Found this useful? Let me know below! I don't currently have any analytics set up, so your comments are the only way I know if anyone's reading this :P