Compiling and bundling JavaScript, the painless way
Michele Riva
Michele Riva
Senior Software Architect @NearForm
Google Developer Expert
Microsoft MVP
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9488728/photo_2022-04-10_15-22-25.jpg)
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9410911/image_9.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9410912/MVP_Logo_Preferred_Cyan300_RGB_300ppi.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9589688/NearForm_Master_Template_v3_2.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9410932/Real-World_Nextjs.png)
Real-World Next.js
Build scalable, high performances and modern web applications using Next.js, the React framework for production
MicheleRivaCode
Compiling and bundling JavaScript
is (often) a pain*
*but it shouldn't
MicheleRivaCode
A bit of terminology: compiling
to change a computer program into a machine language
Cambridge Dictionary
MicheleRivaCode
A bit of terminology: compiling transpiling
to translate a source code into a different language source code
Me, myself
MicheleRivaCode
A bit of terminology: bundling
to encapsulate code and resources into a single executable file
Me, myself
MicheleRivaCode
Why do we want to transpile our code?
- To make it compatible with different platforms
- To write our scripts in different languages
- To adopt new language features
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043373/Google_Chrome_icon__September_2014_.svg.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043390/1_tfZa4vsI6UusJYt_fzvGnQ.png)
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043491/Screenshot_2021-10-22_at_11.19.27.png)
Scala.js
https://www.scala-js.org
MicheleRivaCode
ReasonML
ReScript
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043505/F_Sharp_logo.svg.png)
F# (via Fable)
Gleam
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043509/36161205.png)
Elm
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043516/Elm_logo.svg.png)
Kotlin
Nim, Haxe, C/C++ (via Emscripten), ClojureScript, Dart, PureScript, Haskell (via GHCJS)
MicheleRivaCode
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9530052/DragonFull.png)
LLVM
MicheleRivaCode
function toUpper(x) {
return x.toUpperCase();
}
function addExclamationMarks(x) {
return x + '!!!'
}
function scream(input) {
return input
|> toUpper
|> addExclamationMarks
|> console.log
}
scream('Hello, Belgium');
// HELLO, BELGIUM!!!
"use strict";
function toUpper(x) {
return x.toUpperCase();
}
function addExclamationMarks(x) {
return x + '!!!';
}
function scream(input) {
var _ref, _ref2, _input;
return _ref = (
_ref2 = (_input = input, toUpper(_input)),
addExclamationMarks(_ref2)
), console.log(_ref);
}
scream('Hello, Belgium');
// HELLO, BELGIUM!!!
MicheleRivaCode
import { VFC } from 'react';
enum UserType {
ADMIN = "admin",
EDITOR = "editor",
USER = "user",
ANONYMOUS = "guest"
}
type MyProps = {
userType: UserType;
}
const MyComponent: VFC<MyProps> = ({ userType }) => {
return (
<div>
User is of type: {props.userType}
</div>
)
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var UserType;
(function (UserType) {
UserType["ADMIN"] = "admin";
UserType["EDITOR"] = "editor";
UserType["USER"] = "user";
UserType["ANONYMOUS"] = "guest";
})(UserType || (UserType = {}));
const MyComponent = ({ userType }) => {
return /*#__PURE__*/ React.createElement(
"div",
null,
"User is of type: ",
props.userType
);
};
MicheleRivaCode
Why do we want to bundle our code?
- To create a single executable file
- To serve a single JS file over the net
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9043373/Google_Chrome_icon__September_2014_.svg.png)
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045735/javascript.png)
ReadArticle.jsx
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045735/javascript.png)
NewArticle.jsx
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045735/javascript.png)
AuthorProfile.jsx
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045735/javascript.png)
BundledPage.js
MicheleRivaCode
in depths
transpiling
MicheleRivaCode
Language-to-language
ClojureScript
(defn simple-component []
[:div
[:p "I am a component!"]
[:p.someclass
"I have " [:strong "bold"]
[:span {:style {:color "red"}} " and red "] "text."]])
cljs.user.simple_component = (function cljs$user$simple_component(){
return new cljs.core.PersistentVector(null, 3, 5, cljs.core.PersistentVector.EMPTY_NODE,
[new cljs.core.Keyword(null,"div","div",(1057191632)),
new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE,
[new cljs.core.Keyword(null,"p","p",(151049309)),"I am a component!"], null),
new cljs.core.PersistentVector(null, 5, 5, cljs.core.PersistentVector.EMPTY_NODE,
[new cljs.core.Keyword(null,"p.someclass","p.someclass",(-1904646929)),
"I have ",new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE,
[new cljs.core.Keyword(null,"strong","strong",(269529000)),"bold"], null),
new cljs.core.PersistentVector(null, 3, 5, cljs.core.PersistentVector.EMPTY_NODE,
[new cljs.core.Keyword(null,"span","span",(1394872991)),
new cljs.core.PersistentArrayMap(null, 1, [new cljs.core.Keyword(null,"style","style",(-496642736)),
new cljs.core.PersistentArrayMap(null, 1, [
new cljs.core.Keyword(null,"color","color",(1011675173)),"red"]
, null)], null)," and red "], null),"text."], null)], null);
});
https://reagent-project.github.io
MicheleRivaCode
[@bs.config {jsx: 3}];
module Greeting = {
[@react.component]
let make = () => {
<button> {React.string("Hello!")} </button>
};
};
ReactDOMRe.renderToElementWithId(<Greeting />, "preview");
// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';
var React = require("react");
var ReactDOMRe = require("./stdlib/reactDOMRe.js");
function _none_$Greeting(Props) {
return React.createElement("button", undefined, "Hello!");
}
var Greeting = {
make: _none_$Greeting
};
ReactDOMRe.renderToElementWithId(React.createElement(_none_$Greeting, { }), "preview");
exports.Greeting = Greeting;
/* Not a pure module */
https://reasonml.github.io
Language-to-language
ReasonML
MicheleRivaCode
Language-to-language
TypeScript
import { VFC } from 'react';
enum UserType {
ADMIN = "admin",
EDITOR = "editor",
USER = "user",
ANONYMOUS = "guest"
}
type MyProps = {
userType: UserType;
}
const MyComponent: VFC<MyProps> = ({ userType }) => {
return (
<div>
User is of type: {props.userType}
</div>
)
}
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var UserType;
(function (UserType) {
UserType["ADMIN"] = "admin";
UserType["EDITOR"] = "editor";
UserType["USER"] = "user";
UserType["ANONYMOUS"] = "guest";
})(UserType || (UserType = {}));
const MyComponent = ({ userType }) => {
return /*#__PURE__*/ React.createElement(
"div",
null,
"User is of type: ",
props.userType
);
};
MicheleRivaCode
Every language has its own transpiler
TypeScript TSC
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045797/F_Sharp_logo.svg.png)
Fable
ClojureScript
BuckleScript
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045804/1024px-Unofficial_JavaScript_logo_2.svg__2_.png)
JavaScript (Babel)
MicheleRivaCode
Problem #1
transpilation time
Really fast
Average
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045797/F_Sharp_logo.svg.png)
Fast
Slow on large codebases
Slow on large codebases
MicheleRivaCode
Problem #2
optimized output
Beautifully optimized
Awful
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9045797/F_Sharp_logo.svg.png)
Beautifully optimized
Quite optimized
Well optimized*
MicheleRivaCode
Let's focus on the most popular ones
Quite slow, quite optimized
Quite fast, well optimized*
MicheleRivaCode
Bundling time grows
Quite slow, quite optimized
Quite fast, well optimized
MicheleRivaCode
MicheleRivaCode
in depths
bundling
WebPack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046187/avatar.67f301d4.png)
Parcel
Rollup
MicheleRivaCode
Hard
Easier
Easiest
WebPack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046187/avatar.67f301d4.png)
Parcel
Rollup
MicheleRivaCode
Hard
Easier
Easiest
Slowest
Slower
Fast
WebPack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046187/avatar.67f301d4.png)
Parcel
Rollup
MicheleRivaCode
king of configurations
MicheleRivaCode
king of configurations
Is it still worth it?
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046214/logo__3_.png)
ESBuild
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046217/swc.png)
SWC
Vite
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046219/68747470733a2f2f7777772e736e6f777061636b2e6465762f696d672f6c6f676f2e706e67.png)
Snowpack
is there any better alternative?
(rest in pepperoni)
MicheleRivaCode
esbuild src/myEntry.js --bundle --sourcemap --minify --outfile=dist/mybundle.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046214/logo__3_.png)
ESBuild
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9047565/es2019.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9047566/es2020.png)
ES2019
ES2020
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046217/swc.png)
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046217/swc.png)
{
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": false,
"dynamicImport": false,
"privateMethod": false,
"functionBind": false,
"exportDefaultFrom": false,
"exportNamespaceFrom": false,
"decorators": false,
"decoratorsBeforeExport": false,
"topLevelAwait": false,
"importMeta": false
},
"transform": null,
"target": "es5",
"loose": false,
"externalHelpers": false,
// Requires v1.2.50 or upper and requires target to be es2016 or upper.
"keepClassNames": false
}
}
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046217/swc.png)
SWC can run in a browser thanks to WASM
MicheleRivaCode
Vite
MicheleRivaCode
Vite
MicheleRivaCode
Vite
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046214/logo__3_.png)
MicheleRivaCode
// ESM
export default function greet() {
return "Hello Serbia!";
}
// ESM
import foo, { bar } from "foobar";
// CJS
module.exports = function greet() {
return "Hello Serbia!";
}
// CJS
const foo, { bar } = require("foobar");
MicheleRivaCode
Vite
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9555077/Screenshot_2022-05-12_at_15.43.27.png)
MicheleRivaCode
rest in pepperoni
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046219/68747470733a2f2f7777772e736e6f777061636b2e6465762f696d672f6c6f676f2e706e67.png)
Snowpack
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046219/68747470733a2f2f7777772e736e6f777061636b2e6465762f696d672f6c6f676f2e706e67.png)
Snowpack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046214/logo__3_.png)
rest in pepperoni
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046219/68747470733a2f2f7777772e736e6f777061636b2e6465762f696d672f6c6f676f2e706e67.png)
Snowpack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9046214/logo__3_.png)
rest in pepperoni
MicheleRivaCode
MicheleRivaCode
/*
* Skypack CDN - canvas-confetti@1.4.0
*
* Learn more:
* 📙 Package Documentation: https://www.skypack.dev/view/canvas-confetti
* 📘 Skypack Documentation: https://www.skypack.dev/docs
*
* Pinned URL: (Optimized for Production)
* ▶️ Normal: https://cdn.skypack.dev/pin/canvas-confetti@v1.4.0-POmgSMO0U5q84otJfYlN/mode=imports/optimized/canvas-confetti.js
* ⏩ Minified: https://cdn.skypack.dev/pin/canvas-confetti@v1.4.0-POmgSMO0U5q84otJfYlN/mode=imports,min/optimized/canvas-confetti.js
*
*/
// Browser-Optimized Imports (Don't directly import the URLs below in your application!)
export * from '/-/canvas-confetti@v1.4.0-POmgSMO0U5q84otJfYlN/dist=es2020,mode=imports/optimized/canvas-confetti.js';
export {default} from '/-/canvas-confetti@v1.4.0-POmgSMO0U5q84otJfYlN/dist=es2020,mode=imports/optimized/canvas-confetti.js';
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9051709/wb.png)
MicheleRivaCode
The future is no-bundle
MicheleRivaCode
The future is no-bundle*
*maybe
MicheleRivaCode
The future is bright
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9556805/Screenshot_2022-05-13_at_07.25.04.png)
https://kdy1.dev/posts/2022/1/tsc-go
MicheleRivaCode
MicheleRivaCode
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/8301691/giphy-downsized-large.gif)
MicheleRivaCode
@MicheleRiva
@MicheleRivaCode
/in/MicheleRiva95
www.micheleriva.dev
![](https://s3.amazonaws.com/media-p.slid.es/uploads/1040289/images/9453990/qrcode.png)
Compiling and bundling JS, the painless way
By Michele Riva
Compiling and bundling JS, the painless way
- 532