Skip to content

crutch12/esbuild-standalone

Repository files navigation

esbuild-standalone provides a standalone build of Esbuild for use in browsers. Made with Service Worker and esbuild-wasm.

It's alternative for @babel/standalone and esm.sh/tsx.

When (not) to use esbuild-standalone

If you're using Esbuild in production, you should normally not use esbuild-standalone. Instead, you should use a build system running on Node.js, such as Esbuild or Vite, to transpile your JS ahead of time.

However, there are some valid use cases for esbuild-standalone:

  • It provides an easy, convenient way to prototype with Esbuild. Using esbuild-standalone, you can get started using Esbuild with just a simple script tag in your HTML.
  • You want to write html pages that require transpilation (e.g. in confluence) without additional build/deploy stages.
  • You want to check your es6 code as quickly as possible, just using index.html

How it works

esbuild-standalone is a script that allows you to write JSX/TSX directly in HTML without any build steps. Your source code is sent to the Service Worker, compiled, cached, and served to the browser as a JavaScript module.

It also may work without Service Worker setup, but with limitations.

Installation

Service Worker Setup

In your "public"/"root" directory

  1. create file service-worker.js (for "classic" sw type support)
// /service-worker.js
importScripts('https://unpkg.com/[email protected]/service-worker.js')
  1. create file service-worker.mjs (for "module" sw type support)
// /service-worker.mjs
import 'https://unpkg.com/[email protected]/service-worker.mjs'

Files should be available here:

  • https://{domain}/service-worker.js
  • https://{domain}/service-worker.mjs

Note

You can specify any service-worker.js/service-worker.mjs path with data-sw-url/data-sw-esm-url options. See Options.

Usage

Supported script types:

  • text/babel
  • text/esbuild
  • text/jsx
  • text/tsx
  • text/ts
  • text/vue

Inline (no SW setup required)

Package: https://esm.sh/esbuild-standalone

Create index.html file:

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- @IMPORTANT: ?external is required for singleton libraries (e.g. react) -->
    <!-- @NOTE: More info: https://esm.sh/ -->
    <script type="importmap">
    {
      "imports": {
        "react": "https://esm.sh/[email protected]",
        "react/jsx-runtime": "https://esm.sh/[email protected]/jsx-runtime.js?external=react",
        "react-dom/client": "https://esm.sh/[email protected]/client?external=react"
      }
    }
    </script>
    <script src="https://esm.sh/esbuild-standalone" type="module"></script>

    <!-- Every script with "text/babel" will be built and executed with esbuild-wasm  -->
    <script type="text/babel">
      import { createRoot } from 'react-dom/client';

      export function App({ name }) {
        return <div>
          <h2>Hello, {name}</h2>
        </div>
      }

      const root = createRoot(document.getElementById('root'))
      root.render(<App name="esbuild-standalone" />)
    </script>
  </head>
  <body>
    <div id="root">Loading...</div>
  </body>
</html>

External (SW setup required)

Package: https://esm.sh/esbuild-standalone/sw

Create index.html file:

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- @IMPORTANT: ?external is required for singleton libraries (e.g. react) -->
    <!-- @NOTE: More info: https://esm.sh/ -->
    <script type="importmap">
    {
      "imports": {
        "react": "https://esm.sh/[email protected]",
        "react/jsx-runtime": "https://esm.sh/[email protected]/jsx-runtime.js?external=react",
        "react-dom/client": "https://esm.sh/[email protected]/client?external=react"
      }
    }
    </script>
    <!-- @IMPORTANT: Requires Service Worker Setup -->
    <!-- /service-worker.js and /service-worker.mjs should be available -->
    <script src="https://esm.sh/esbuild-standalone/sw" type="module"></script>

    <!-- @NOTE: You can provide data-sw-url to your service-worker.js file -->
    <!-- <script
      src="https://esm.sh/esbuild-standalone/sw"
      type="module"
      id="esbuild-standalone"
      data-sw-url="/sw.js">
    </script> -->

    <!-- Every script with "text/esbuild" will be built and executed with esbuild-wasm too  -->
    <script src="index.tsx" type="text/esbuild"></script>

    <!-- type="module" works too (thanks to Service Worker) -->
    <!-- <script src="index.tsx" type="module"></script> -->
  </head>
  <body>
    <div id="root">Loading...</div>
  </body>
</html>

Create index.tsx file:

import { createRoot } from 'react-dom/client';

import { App } from './app.jsx' // import via service worker

const root = createRoot(document.getElementById('root'))
root.render(<App name="esbuild-standalone" />)

Create app.jsx file:

function App({ name }) {
  return <div>
    <h2>Hello, {name}</h2>
  </div>
}

export { App }

Options

Options API

Note

If specified path is relative (e.g. data-tsconfig="./tsconfig.json"), it is resolved relatively to current page document.baseURI value.

type Options = {
  config: string | undefined, // e.g. "./esbuild.config.json"
  tsconfig: string | undefined, // e.g. "https://raw.githubusercontent.com/crutch12/esbuild-standalone/refs/heads/master/examples/preact/tsconfig.json"
  // Service Worker setup options
  swUrl: string | undefined, // e.g. /sw.js
  swEsmUrl: string | undefined, // e.g. /sw.mjs
  swType: 'classic' | 'module' | undefined,
  swScope: string | undefined, // e.g. /pages
  swUpdateViaCache: 'all' | 'imports' | 'none' | undefined
}

Usage 1. Specify with script data-* attributes

Note

id="esbuild-standalone" is required for data-* attributes usage.

<script
  src="https://esm.sh/esbuild-standalone/sw"
  type="module"
  id="esbuild-standalone"
  data-sw-url="./service-worker.mjs"
  data-tsconfig="./tsconfig.json"
  data-config="./esbuild.config.json">
</script>

Usage 2. Specify with url search params

<script src="https://esm.sh/esbuild-standalone/es2022/sw.mjs?config=./esbuild.config.json" type="module"></script>

Usage 3. Specify with window.esbuildStandaloneOptions

<script>
  window.esbuildStandaloneOptions = {
    swUrl: '/service-worker.js',
    swEsmUrl: '/service-worker.mjs',
    tsconfig: './tsconfig.json',
  }
</script>
<script src="https://esm.sh/esbuild-standalone/sw"></script>

Examples

All examples (react/preact/etc.) available here:

References