TL;DR: see . Or just skip to the summary at the end of the post. https://en.wikipedia.org/wiki/Betteridge%27s_law_of_headlines I have a dream! And in my dream, all the tooling needed today to use JavaScript just goes away. We can all just write the code in our favorite editor, hit refresh, and be done with it. No package.json. No babel. No webpack. No config.foo.json, or .foorc. Just write the code, and hit refresh. Obviously, big applications will always need tooling — linters, static analysis, optimization tools for production. But even when coding big applications, while we’re just running our code in development, all we want to do is code and refresh. One day I’ll write a blog post about how to get there, but today I want to try out one of the steps that will allow us to get there: ES Modules. ES Modules A quick recap on what ES modules are. There are on this subject, so feel free to go and read them if you’re not familiar with ES modules. This recap is mostly to synchronize and understand it from the point of view of this article. better tutorials out there To create an ES module, we write code like this, which export-s a function. <a href="https://medium.com/media/08b41dede5664f404c1aef57d967a117/href">https://medium.com/media/08b41dede5664f404c1aef57d967a117/href</a> And to import it, we use import. <a href="https://medium.com/media/88e95369967a8c75c34a07d935319053/href">https://medium.com/media/88e95369967a8c75c34a07d935319053/href</a> As I said, this isn’t really a tutorial, and to really explore the syntax, I would suggest you go to tutorial. What is important to me, is that if, today, we script src the module above that imports the other module, then it won’t work on any browser — the browser will treat the import syntax as a syntax error. Browser vendors that their latest versions have more or less 100% coverage of ES6, and the , but that is because, for some reason, ES modules aren’t included in their definition of “ES6”, even though it part of that version. this say wonderful kangax compatibility table agrees is But all the cool kids use ES Modules today. How? How can most React and Angular samples use ES Modules? Because, as is usual in these times, the JavaScript community has found ways of circumventing browser vendors, and enabling ES Modules using tools like , , and . Webpack browserify rollup These tools are called module , since they crawl the JavaScript modules looking for import statements, and bundle all the modules into one big file. bundlers CommonJS and ES modules, along with npm, have revolutionized the way we write JavaScript, and it would be inconceivable today to write a software project without using them. Unfortunately, no browser supported has supported CommonJS or ES modules. Till now. Native ES Modules Starting from the last week, all 4 major browsers — Safari, Firefox, Edge, and Chrome — have started supporting ES modules natively. This means that if you script src the module that imports, it will JUST WORK. Well, it will “just work” currently only in the “developer/canary/technology preview/insider” versions. My dream is coming closer! But I was skeptical. All the examples I’ve seen in the various blog posts try and do 2–3 modules importing one another. But the reality today is that an application can bring in ten or even hundreds of modules at a time — each one very small, true, but hundreds of them nonetheless. So I decided to try and see how those browsers work when there are tens of modules being imported. I wanted to check out how browsers would behave when confronted with lots of little modules? Trying Out Native ES Modules Luckily, I didn’t have to build a module that imports tens of other modules: there is such a module already. Moreover — it’s a VERY famous module. It’s . Most people don’t know, but for some reason, the lodash team have a that has lodash importing the other sub-lodash modules (e.g. pick and map and compose and debounce and others) using ES modules syntax. And there a of sub-lodash modules. lodash package in npm lot So all I needed to do, was create an HTML page that had a script tag that imports lodash, and try it out. Does it work? Is the performance of loading multiple modules, using multiple HTTP requests, comparable to loading one big bundle? I was even all ready to try this out using HTTP/2, as HTTP/2 is MUCH better at handling multiple small resources from the same domain. And then to test how HTTP/2 push support will make it even better. As we shall see, I didn’t get there, because, well… you’ll see. You can try out for yourself the results of my examination here: giltayar/esm-with-http2 To try them out, you will need to run npm install, then npm run build, and finally npm start to start the node server that serves the HTML and JS. If you go to you will get a page that tries to import lodash, and console.log-s the result: http://localhost:3000/es6-modules.html <a href="https://medium.com/media/9c2bf9b86bbe3eeb10db1c31cc4129ce/href">https://medium.com/media/9c2bf9b86bbe3eeb10db1c31cc4129ce/href</a> The code loads es6-module-1.js. This is the module that loads lodash, which in turns loads all the little lodash sub-modules. So let’s try it on Chrome Canary. If you also want to try it, you currently need to goto chrome://flags and enable “Experimental Web Platform features”. Native ES Modules on Chrome Canary (v60) So I tried it out. Imagine my amazement when I got this result: benchmark: 18484.576904296875ms Yup — . loading all those modules took more than 18 seconds If we try out the link in that page — webpack modules—we will get: benchmark: 191.23876953125ms And this page loads the same code as the previous page, but bundled into one file. Oh, and the file isn’t that big — around 1Kb. But it runs in around 200 milliseconds. lower than 18 seconds. Much So what’s going on? Why is Chrome so slow in loading ES modules? Is it the loads of HTTP requests? Would HTTP/2 help here, by parallelizing all HTTP request? No. I made all requests to the server return an infinity expiration date (using themaxage HTTP directive), and tried again — same result. So if the browser isn’t doing any HTTP requests when caching is turned on, then what is going on? What is it doing? According to the Chrome’s Network tab, the JS files were loaded (when cached) after 3 seconds (which is still a lot). But what is it doing for 15 after that? seconds I tried figuring out what it was doing using the “Performance” tab: I found out that after about 6 seconds, it’s basically doing till the 20th second — those little yellow lines spread around are just DOM Garbage Collection. nothing So what is making it run so slow? No idea. It’s not the network problem, as we have proven by turning on caching. but I tried HTTP/2 anyway using . Same result! the browser is now loading the modules in parallel, but the time is still around the 20 seconds. https://localhost:3001/es6-modules.html This was very disappointing — what I really wanted to do was optimize HTTP/2 fetching so that loading the modules would be almost as fast as loading the bundles, but with this performance, there’s no point in shaving off the network time, because the browser is doing something after loading the JS modules. else But now I got curious. What about the other browsers? Native ES Modules on Firefox Developer Edition (v54) Mostly, the same result: benchmark: 11749.47ms Oh, wait, no. It’s actually worse. I ran it a few more times, and consistently got numbers like these: benchmark: 31409.71ms Moreover, the browser seems to freeze when loading the page! The performance is worse than in Chrome. much What about Safari? Native ES Modules on Safari Technology Preview (v29) Much better! Without caching, the result I get is: benchmark: 2826.892ms And with caching: benchmark: 1583.700ms Of course, this is not even comparable to the performance of the bundled version, which takes 200ms uncached, and 40ms cached. But it’s a huge improvement over Chrome and Firefox. This reminds of . Safari got rid of the goat. the story of the poor family, the rabbi, and the goat And it still begs the same question — what is Safari doing for 1.5 seconds if all the files are in the cache? Summary Chrome, Firefox, and to a lesser extent, Safari, all exhibit the same behavior when loading ES Modules natively — makes the browsers idle for a long time after the network loading of the modules is done. And that is making the loading time of a page that uses lots of ES modules very high: around 18 seconds for Chrome, more than 30 seconds for Firefox, and around 2 seconds for Safari. something something I couldn’t figure out what that something is. Maybe somebody can refer this blog post to the various browser developers? I’d love to understand what it is! One thing is for certain — I am absolutely sure that this is a temporary thing, and that the browser developers will optimize this. And when they do, I will go on and optimize the network part using HTTP/2 and other technologies. But that’s for another blog post.