Skip to content

Instantly share code, notes, and snippets.

@danieldietrich
Last active February 14, 2024 13:15
Show Gist options
  • Save danieldietrich/999abe1aaee11dcdf91d182807f7ee3f to your computer and use it in GitHub Desktop.
Save danieldietrich/999abe1aaee11dcdf91d182807f7ee3f to your computer and use it in GitHub Desktop.
The easiest way to bundle a simple TypeScript web application

THIS README IS OUTDATED AND UNMAINTAINED - PLEASE DON'T RELY ON THIS

The easiest way to bundle a simple TypeScript web application

Packaging JavaScript applications can be a bit overwhelming. The popular project uglifyjs does not support ES6, it is cumbersome to configure the allmighty Webpack, bundlers like Parcel and Microbundle still have bugs or do not compile to ESM bundles that work in a browser. It is hard to figure out the best way to bundle an application.

Here I give a small example, how we achieve the goal using the

☕️ Prerequisites: Install Node.js

✨ Feature overview

  • Zero configuration bundling (esm, umd)
  • Proper entry point hints for npm, unpkg and when used as module
  • Runs with <script type='module'> in a web page

🚀 Initialize Node.js project

Go to a new directory say-hello/

npm init -y

Install dependencies

npm i -D typescript rollup terser

Replace package.json "scripts" (umd name sayHello is app specific)

"scripts": {
  "clean": "rm -fr dist",
    "build": "npm run clean && npm run lint && tsc --project tsconfig.build.json && npm run bundle:esm && npm run bundle:esm:min && npm run bundle:umd && npm run bundle:umd:min && npm run build:stats",
    "build:stats": "(echo '\\033[35;3m' ; cd dist && ls -lh index*js index*gz | tail -n +2 | awk '{print $5,$9}')",
    "bundle:esm": "rollup dist/index.js --file dist/index.mjs --format esm",
    "bundle:esm:min": "terser --ecma 6 --compress --mangle --module -o dist/index.min.mjs -- dist/index.mjs && gzip -9 -c dist/index.min.mjs > dist/index.min.mjs.gz",
    "bundle:umd": "rollup dist/index.js --file dist/index.umd.js --format umd --name sayHello",
    "bundle:umd:min": "terser --ecma 6 --compress --mangle -o dist/index.umd.min.js -- dist/index.umd.js && gzip -9 -c dist/index.umd.min.js > dist/index.umd.min.js.gz",
},

Replace "main" in package.json

- "main": "index.js"
+ "main": "dist/index.js",
+ "module": "dist/index.min.mjs",
+ "unpkg": "dist/index.umd.min.js",
+ "types": "dist/index.d.ts",
+ "files": [
+   "dist"
+ ],

Create TypeScript configuration tsconfig.json

{
  "compilerOptions": {
    "declaration": true,
    "lib": ["es6", "dom", "dom.iterable"],
    "module": "es6",
    "moduleResolution": "node",
    "removeComments": true,
    "sourceMap": true,
    "strict": true,
    "target": "es6",
    "outDir": "./dist"
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "dist",
    "node_modules"
  ]
}

Create test application src/index.ts

export function sayHello() {
    return "Hi ya all!";
}

Create a file example/index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Say Hello</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="author" content="Daniel Dietrich">
    </head>
    <body>
        <noscript>
            You need to enable JavaScript to run this app.
        </noscript>
        <div id="app">
            Loading...
        </div>
        <script type="module">
            import { sayHello } from '../dist/index.mjs';
            document.getElementById('app').innerHTML = sayHello();
        </script>
    </body>
</html>

📦 Build the project

npm run build

Bundle

🥰 Directly using an ESM bundle in a web page

Loading our example web page example/index.html (might require to Disable Local File Restrictions in the browser)

Example

The interesting part

<script type="module">
    import { sayHello } from '../dist/index.mjs';
    document.getElementById('app').innerHTML = sayHello();
</script>

When published to npmjs.com, we can use the unpkg.com CDN to include our module in a web page

<script type="module">
-   import { sayHello } from '../dist/index.mjs';
+   import { sayHello } from 'https://unpkg.com/say-hello?module';
    document.getElementById('app').innerHTML = sayHello();
</script>

[Written by @danieldietrich]

@s17-git
Copy link

s17-git commented Dec 2, 2022

what about snowpack ?

@danieldietrich
Copy link
Author

Good point @s17-git! I also think this README is outdated. In fact I currently either use vite or microbundle. Both are superb. Haven't tested snowpack, yet.

@DerZyklop
Copy link

@danieldietrich
Copy link
Author

Thanks @DerZyklop, this README is totally outdated. Please don't rely on it anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment