
Az utóbbi időben mindannyian sokat hallottunk a „JavaScript modulokról”. Valószínűleg mindenki kíváncsi arra, hogy mit kezdjen velük, és hogyan is játszanak létfontosságú szerepet a mindennapi életben ...?
Mi a fene a JS modulrendszer? ?
Ahogy a JavaScript fejlesztése egyre szélesebb körben elterjed, a névtereket és a függőségeket sokkal nehezebb kezelni. Különböző megoldásokat fejlesztettek ki a probléma kezelésére modulrendszerek formájában.

Miért fontos a JS modulrendszer megértése?
Hadd mondjak el egy történetet.
A történetek elmondása ugyanolyan alapvető az emberi lény számára, mint az evés. Sőt, valójában, bár míg az étel élővé tesz minket, a történetek azok, amelyek életünket érdemesek megélni - Richard KearneyMiért is beszélek ezekről a dolgokról?
Szóval, a napi munkám a projektek tervezése és felépítése, és gyorsan rájöttem, hogy a projektek között sok közös funkcióra van szükség. Mindig végül újra és újra beillesztettem ezeket a funkciókat új projektekbe.
A probléma az volt, hogy valahányszor a kód egy része megváltozott, manuálisan szinkronizálnom kellett ezeket a változásokat az összes projektemben. Mindezen unalmas manuális feladatok elkerülése érdekében úgy döntöttem, hogy kibontom a közös funkciókat, és összeállítok belőlük egy npm csomagot. Így a csapat többi tagja újra felhasználhatja őket függőségként és egyszerűen frissítheti őket, valahányszor új kiadás kerül bevezetésre.
Ennek a megközelítésnek volt néhány előnye:
- Ha valamilyen változás történt a törzskönyvtárban, akkor csak egy helyen kellett változtatni, anélkül, hogy újra kellett volna változtatni az alkalmazás összes kódját ugyanarra a dologra.
- Az összes alkalmazás szinkronban maradt. Valahányszor változás történt, az összes alkalmazásnak csak az „npm update” parancs futtatásához volt szüksége.

Tehát a következő lépés a könyvtár kiadása volt. Jobb? ?
Ez volt a legnehezebb rész, mert egy csomó dolog ugrált a fejemben, például:
- Hogyan lehet a fát megrendíteni?
- Milyen JS modulrendszereket célzok meg (commonjs, amd, harmony).
- Át kell adnom a forrást?
- Csomagoljam be a forrást?
- Milyen fájlokat tegyek közzé?
Mindegyikünknek ilyen kérdések fortyogtak a fejünkben egy könyvtár létrehozása közben. Jobb?
Most megpróbálom megválaszolni a fenti kérdéseket.
Különböző típusú JS modulrendszerek?
1. CommonJS
- Csomópont által megvalósítva
- A kiszolgálói oldalon használják, ha moduljai vannak telepítve
- Nincs futásidejű / aszinkron modul betöltése
- import „ igényel ”
- exportálás a „ module.exports ” útján
- Importáláskor visszakap egy objektumot
- Nincs fa remegés, mert az importáláskor kap egy tárgyat
- Nincs statikus elemzés, mivel objektumot kap, így a tulajdonságkeresés futás közben történik
- Mindig kap egy példányt egy objektumból, tehát nem változik élő változás magában a modulban
- Gyenge ciklikus függőségkezelés
- Egyszerű szintaxis
2. AMD: Async Module Definition
- A RequireJs hajtja végre
- Az ügyféloldali (böngésző) számára használható, ha a modulok dinamikus betöltését szeretné megtenni
- Importálás „igényléssel”
- Komplex szintaxis
3. UMD: univerzális modul meghatározása
- A CommonJs + AMD kombinációja (vagyis a CommonJs szintaxisa + az AMD aszinkron betöltése)
- Használható mindkét AMD / CommonJs környezetben
- Az UMD lényegében megteremti a kettő bármelyikének használatának módját, miközben támogatja a globális változó definícióját is. Ennek eredményeként az UMD modulok mind kliensen , mind szerveren képesek működni .
4. ECMAScript Harmony (ES6)
- Használt mind szerver / kliens oldali
- Támogatott modulok futásidejű / statikus betöltése
- Ha importálja, akkor kap vissza kötések érték (tényleges érték)
- Import „import” és export „export” útján
- Statikus elemzés - Meghatározhatja az importálást és az exportálást fordításkor (statikusan) - csak a forráskódot kell megnéznie, nem kell végrehajtania
- Fa megrázható, az ES6 által támogatott statikus elemzés miatt
- Mindig kapjon tényleges értéket, így az élő változások magukban a modulokban változnak
- Jobb ciklikus függőségkezelés, mint a CommonJS
Tehát most mindent tud a különböző típusú JS modulrendszerekről és azok fejlődéséről.
Bár az ES Harmony modulrendszert minden eszköz és modern böngésző támogatja, a könyvtárak publikálásakor soha nem tudjuk, hogy a fogyasztók miként használhatják őket. Tehát mindig biztosítanunk kell, hogy a könyvtárak minden környezetben működjenek.
Merüljünk el mélyebben, és tervezzünk egy mintakönyvtárat, hogy megfelelő módon megválaszoljuk a könyvtár kiadásával kapcsolatos kérdéseket.
I’ve built a small UI library (you can find the source code on GitHub), and I’ll share all my experiences and explorations for transpiling, bundling, and publishing it.

Here we have a small UI library which has 3 components: Button, Card, and NavBar. Let’s transpile and publish it step by step.
Best practices before publishing ?
- Tree Shaking ?
- Tree shaking is a term commonly used in the context of JavaScript for dead-code elimination. It relies on the static structure of ES2015 module syntax, that is,
import
andexport
. The name and concept have been popularized by the ES2015 module bundler rollup. - Webpack and Rollup both support Tree Shaking, meaning we need to keep certain things in mind so that our code is tree shakeable.
2. Publish all module variants
- We should publish all the module variants, like
UMD
andES
, because we never know which browser/webpack versions our consumers might use this library/package in. - Even though all the bundlers like Webpack and Rollupunderstand ES modules, if our consumer is using Webpack 1.x, then it cannot understand the ES module.
// package.json
{"name": "js-module-system","version": "0.0.1",...
"main": "dist/index.js","module": "dist/index.es.js",
...}
- The
main
field of thepackage.json
file is usually used to point to theUMD
version of the library/package. - You might be wondering — how can I release the
ES
version of my library/package? ?A
odule
p m mezővel a könyvtár / csomagackage.json
ES
változatára lehet mutatni . Korábban sok mezőt használtak, például js:next
és js:main
, de az module
ma már szabványosítva van, és a kötegerekS v
a könyvtár / csomag E-változatának kereséseként használják .
package.json
vannak ellenőrizve.
Teljesítménytipp: Mindig próbálja közzé tenni a
ES
könyvtár / csomag verzióját is, mert az összes modern böngésző támogatja a
ES
modulokat. Tehát kevesebbet lehet transzponálni, és végül kevesebb kódot szállítasz a felhasználókhoz. Ez növeli az alkalmazás teljesítményét.
Akkor most mi következik? Átültetés vagy csomagolás? Milyen eszközöket használjunk?
Ah, here comes the trickiest part! Let’s dive in. ?
Webpack vs Rollup vs Babel?
These are all the tools we use in our day to day lives to ship our applications/libraries/packages. I cannot imagine modern web development without them — #blessed. Therefore, we cannot compare them, so that would be the wrong question to ask! ❌
Each tool has it’s own benefits and serves different purpose based on your needs.
Let’s look at each of these tools now:
Webpack
Webpack is a great module bundler ? that is widely accepted and mostly used for building SPAs. It gives you all the features out of the box like code splitting, async loading of bundles, tree shaking, and so on. It uses the CommonJS module system.
PS: Webpack-4.0.0 alpha is already out ?. Hopefully with the stable release it will become the universal bundler for all types of module systems.
RollupJS
Rollup is also a module bundler similar to Webpack. However, the main advantage of rollup is that it follows new standardized formatting for code modules included in the ES6 revision, so you can use it to bundle the ES module variant of your library/package. It doesn’t support async loading of bundles.
Babel
Babel is a transpiler for JavaScript best known for its ability to turn ES6 code into code that runs in your browser (or on your server) today. Remember that it just transpiles and doesn’t bundle your code.
My advice: use Rollup for libraries and Webpack for apps.
Transpile (Babel-ify) the source or Bundle it
Again there’s a story behind this one. ?
I spent most of my time trying to figure out the answer to this question when I was building this library. I started digging out my node_modules to lookup all the great libraries and check out their build systems.

After looking at the build output for different libraries/packages, I got a clear picture of what different strategies the authors of these libraries might have had in mind before publishing. Below are my observations.
As you can see in the above image, I’ve divided these libraries/packages into two groups based on their characteristics:
- UI Libraries (
styled-components
,material-ui
) - Core Packages (
react
,react-dom
)
If you’re a good observer ? you might have figured out the difference between these two groups.
UI Libraries have a dist
folder that has the bundled and minified version for ES and UMD/CJSmodule systems as a target. There is a lib
folder that has the transpiled version of the library.
Core Packages havejust one folder which has the bundled and minified version for CJS or UMD module system as a target.
But why is there a difference in build output of UI libraries and Core Packages? ?
UI Libraries
Imagine if we just publish the bundled version of our library and host it on CDN. Our consumer will use it directly in a
t the <
;Button/> component, they have to load the entire library. Also, in a browser, there is no bundler which will take care of tree shaking, and we’ll end up shipping the whole library code to our consumer. We don’t want this.
import {Button} from "//unpkg.com/uilibrary/index.js";
Now if we simply transpile the
src
into lib
and host the lib
on a CDN, our consumers can actually get whatever they want without any overhead. “Ship less, load faster”. ✅
import {Button} from "//unpkg.com/uilibrary/lib/button.js";
Core Packages
Core packages are never utilized via the
For example, they can use the UMD variant but no tree shaking, or they can use the ES variant if the bundler is capable of identifying and getting the benefits of tree shaking.
// CJS requireconst Button = require("uilibrary/button");
// ES importimport {Button} from "uilibrary";
But…what about our question: should we transpile (Babelify) the source or bundle it? ?
For the UI Library, we need to transpile the source with Babel with the
es
module system as a target, and place it in lib
. We can even host the lib
on a CDN.
We should bundle and minifythe source using rollup for
cjs/umd
module system and es
module system as a target. Modify the package.json
to point to the proper target systems.
// package.json
{"name": "js-module-system","version": "0.0.1",...
"main": "dist/index.js", // for umd/cjs builds"module": "dist/index.es.js", // for es build
...}
For core packages, we don’t need the
lib
version.
We just need to bundle and minifythe source using rollup for
cjs/umd
module system and es
module system as a target. Modify the package.json
to point to the proper target systems, same as above.
Tip: We can host the
dist
folder on the CDN as well, for the consumers who are willing to download the whole library/package via
How should we build this?
How should we build this?
We should have different scripts for each target system in
package.json
. You can find the rollup config in the GitHub repo.
// package.json
{..."scripts": {"clean": "rimraf dist","build": "run-s clean && run-p build:es build:cjs build:lib:es","build:es": "NODE_ENV=es rollup -c","build:cjs": "NODE_ENV=cjs rollup -c","build:lib:es": "BABEL_ENV=es babel src -d lib"}...}
What should we publish?
What should we publish?
License
README
Changelog
Metadata(
main
,module
,bin
) — package.jsonControl through package.json
files
property
In
package.json
, the "files"
field is an array of file patterns that describes the entries to be included when your package is installed as a dependency. If you name a folder in the array, then it will also include the files inside that folder.
We will include the
lib
and dist
folders in "files"
field in our case.
// package.json
{..."files": ["dist", "lib"]...}
Finally the library is ready to publish. Just type the
npm run build
command in the terminal, and you can see the following output. Closely look at the dist
and lib
folders. ?

Wrap up
Wow! Where does the time go? That was a wild ride, but I sincerely hope it gave you a better understanding of the JavaScript Module system and how you can create your own library and publish it.
Just make sure you take care of the following things:
- Make it Tree Shakeable. ?
- Target at least ES Harmony and CJS module systems. ?
- Use Babel and Bundlers for libraries. ?
- Use Bundlers for Core packages. ?
- Set the
module
field of package.json
to point to the ES version of your module (PS: It helps in tree shaking). ?
- Publish the folders which have transpiled as well as bundled versions of you module. ?
Trending this week ?
- Webpack-V4 alpha released. ?
- ParcelJs: Blazing fast, zero configuration web application bundler. ?
- Turbo: 5x faster than Yarn & NPM, and runs natively in-browser ?
Thanks to Juho Vepsäläinen and Lakshya Ranganath for their reviews & feedback, Sean T. Larkin and Tobias Koppers for sharing the insights of webpack at ReactiveConf, Addy Osmani for sharing workings of different JS module Systems in “Writing Modular JavaScript With AMD, CommonJS & ES Harmony”.
P.S. If you like this, make sure to recommend (by clap? ) , follow me on twitter, and share this with your friends!?