import { talk } from './aaron-petcoff'; // @ughitsaaron on twitter // web developer at _new york_ magazine // http://aaronpetcoff.me- My name is… - I'm a web developer at… - I'm going to talk about… - You can follow me on Twitter at… - My website is…
export { slides } from './aaron-petcoff'; // http://aaronpetcoff.me/talks- You can find slides from this talk up on my website
The web has changed a lot.
The web has changed a lot since the publication of the first Javascript specification in 1997import and export have been reserved keywords in Javascript since the original specification
The words 'import' and 'export' were defined as reserved keywords in the original javascript specification (It would be interesting to know why that was?)But, until recently, Javascript has had no built in system for handling modules
but JS has never had a built in system for handling modularityJavascript used to be relatively simple.
<a onclick="alert('gimme pizza')">helll yahhh</a>- Our JavaScript applications used to be relatively simple - Existed on "one line" - Handled primarily simple interactivity, form validation, etc.
But our applications have become more complex.
{{#link-to 'pizza'}}helll yahhh{{/link-to}}- Our applications have become much more ambitous - This demands a whole new level of structure and organization to our code
More complex applications had to share code between scripts across the global scope…
Since JS has never had a built in system for modularity a more complex application had to share code across the global scope…with no interface or namespacing, threatening maintainability, and creating barriers to collaboration
// utils.js function slice(arr, n) { // ... }
<!-- index.html --> <script src="utils.js"></script> <script src="pizza.js"></script> <script> var slice = new Slice('plain'); // conflicts with slice in utils.js </script>This limited the stablity and maintainablity of applications, and makes it difficult to collaborate with others, etc.
Now we have multiple ways of handling modules.
// commonjs class Pizza { // ... } module.exports.Pizza = Pizza; // amd define(['Pizza'], function () { class Pizza { // ... } return Pizza; });Of course, people extended the language and created their own systems for modularity, the two most popular being CommonJS and AMD (Asynchronous Module Definition)
(But they are incompatible.)
but these distinct implementations of javascript modules are incompatible with each other not only is this confusing, but it also leads to a complicated package ecosystem for developers and maintainersWriting a JavaScript library in 2015: be sure to support browserify webpack rollup AMD UMD CJS globals ES6 modules npm bower jspm… [1/274]
— Nolan Lawson (@nolanlawson) October 12, 2015Other languages have a built-in interface for modules, giving developers one way to produce and consume modules
# pizza.py class Pizza: def __init__(self, toppings): self.toppings = toppings def Slice: def __init__(self, type): self.type = type # main.py from pizza import SliceMost languages have a built-in specification for modularity there's one way to export code from a module and one way to import it
Having a built in specification for Javascript provides one standard for everyone to follow
Now Javascript has a standard for modules, that aims to be familiar and build on the strengths of module systems already being used this has the potential to stablize the package environment for javascript but accomplishing that will be complicatedExports have to be declared.
You can export function, class, var, const, and let.
// toppings.js export const combo = ['pineapple', 'feta'], // 😋 // pizza.js export class Pizza { constructor(toppings) { this.toppings = toppings; } }
// index.js import { combo } from './libs/toppings'; import { Pizza } from './libs/pizza'; let pizza = new Pizza(combo);Just like in CommonJS, exports have to be explicity declared. Nothing is exported unless you say it is. Exports have to be named. Exports can be given a type.
You can have multiple exports…
// toppings.js export const plain = [], export const pepperoni = ['pepperoni'], export const combo1 = ['pineapple', 'feta'], export const combo2 = ['pepperoni', 'sausage', 'people'];You can have all the exports you want in a module
…or you can export a list…
// toppings.js const plain = [], pepperoni = ['pepperoni'], combo1 = ['pineapple', 'feta'], combo2 = ['pepperoni', 'sausage', 'people']; export { plain, pepperoni, combo1, combo2 }Although, you might think exporting a list of values is more clear
…and rename your exports.
const plain = [], pepperoni = ['pepperoni'], combo1 = ['pineapple', 'feta'], combo2 = ['pepperoni', 'sausage', 'people']; export { plain, pepperoni, combo1 as pineappleAndFeta, combo2 as meatLovers }And for the sake of clarity, you might choose to rename your exports
And you can do the same with imports.
// index.js import { plain as noToppings, meatLovers as meeeat } from './libs/toppings'; import { Pizza } from './libs/pizza'; let pizza1 = new Pizza(noToppings), pizza2 = new Pizza(meeeat);But you might also choose to rename them on the import
You can also namespace imports as an object
// toppings.js export const plain = []; export const pepperoni = ['pepperoni']; // index.js import * as toppings from './libs/toppings'; let plain = new Pizza(toppings.plain); let pepperoni = new Pizza(toppings.pepperoni);You can also namespace your imports as an object
And you can re-export modules from another module's exports.
// plain.js import { Pizza } from './libs/pizza'; export default new Pizza([]); // pepperoni.js import { Pizza } from './libs/pizza'; export default new Pizza(['pepperoni']); // all.js export { default as plain } from "./pizzas/plain"; export { default as pepperoni } from "./pizzas/pepperoni";You can also re-export the exports of another module
But what about default?
There is also a default keyword This exists as both a convenience method but also helps to provide some backward compatability with existing module systemsCommonJS and AMD modules only export once.
CommonJS and AMD can only export once.Those exports become equivalent to default in ES6
import _ from 'lodash'; // import { default as _ } from 'lodash'; // var _ = require('lodash'); let log = console.log.bind(console); export default log; // export { log as default } // module.exports = console.log.bind(console);ES6 treats those single exports from older modules essentially as the default export, named "default"
No nested imports or exports
const date = new Date(); if (date.getDay() === 3) { // wednesday is pizza day import { plain } from './all'; // this should fail }For implementing ES6 modules, there are a few rules First, import and export can be at the top level only, so you can't load an import or export code conditionally, for instance
An implementation must load all imported modules recursively.
A module system must load every module recursively, so every import also has to load and resolve all of it's external dependencies This has been the main thing holding up standardization and implementation of the module specificationLinking
// all.js export { default as plain } from "./pizzas/plain"; export { default as pepperoni } from "./pizzas/pepperoni"; export { default as pineappleAndFeta } from "./pizzas/pineappleAndFeta"; export { default as meatLovers } from "./pizzas/meatLovers"; // index.js import { taco } from './libs/all.js'; // this should failEvery module can only ask for code from other modules that's actually being exported
A module is run only once it's been loaded, parsed, and linked.
If any module fails, the application fails.
Modules are not supported in any browser, yet.
Currently not implemented in any browser or in Node. Various proposals and ideas for how modules should be implemenated in the browser have been exchanged, but no stable implementation exists. And the main thing seems to be how to fetch all the required dependencies? There are proposals for both a configurable module loader api, special asynchronous script tags with a module type attribute, as well standards for bundling or packaging dependencies (think a zip file). the growth of HTTP/2, which allows for multiple requests per connection, could have significant implications for how browsers might handle javascript dependencies but this is still an emerging standard, and currently very little seems locked in place in terms of browser support so, how can we use es6 modules in our applications today?Rollup only bundles what you need
// pizza.js export class Pizza { ... } export class Slice { ... } // index.js import { Pizza } from './pizza'; console.log(Pizza(['veggies', 'more veggies'])); // bundle.js export class Pizza { ... } console.log(Pizza(['veggies', 'more veggies']));One of the especially cool features of rollup is "tree shaking" which allows rollup to produce minimal bundle sizes by only importing the code that's actually used [[ demo if there's time!! ]]
We can't take full advantage of ES6 modules if they're not written as ES6 modules.
The advantages of the ES6 module spec won't be able to be realized without actually writing ES6 modules? But most of the packages we use in our day-to-day work are written as CommonJS modulesBut publishing Javascript is already really complicated.
And publishing code is already complicated enough, between all the different standards that need to be supportedYou can use jsnext:main to point toward ES6 source.
{ "name": "pizza", "version": "9.0.0", "main": "dist/pizza.js", "jsnext:main": "dist/future-pizza.js" }If you do publish es6 modules, you can use the "jsnext:main" property in your package.json file to point toward your ES6 source
Perhaps this is an opening for lots of new open-source contributions.
But it's a lot to ask maintainers to rewrite all their code as ES6 modules, which means this is a potentially huge opening for open source contributions to start to push our javascript code toward embracing this new feature?export { slides } from './aaron-petcoff'; // http://aaronpetcoff.me/talksAgain my slides are going to be up on my site at…
$ #a sandbox for es6 modules & rollup $ git clone https://github.com/ughitsaaron/getting-started-es6-modules.git $ cd getting-started-es6-modules $ npm installI also set up a small repo on github for people who might not know how to totally get off the ground with Es6 modules a little sandbox to play with to start getting familiar with es6 module syntax, rollup, babel, etc., so you can just clone that and run npm install to get started
process.exit(); // @ughitsaaron on twitter // web developer at _new york_ magazine // http://aaronpetcoff.meAgain, I'm aaron. You can follow me at… Thanks! (Mention NY Mag is hiring)