# Bundless documentation (plain Markdown)

This file is the no-runtime fallback for the browser-rendered documentation on
[bundless.dev](https://bundless.dev/usage.html).

The browser footprint refactor is local and unreleased; the package version
remains `1.0.12`. The pinned npm/CDN examples below do not promise those local
changes are already published.

## Fresh-folder starter

```sh
mkdir bundless-starter && cd bundless-starter
npm init -y
npm install --save-exact bundlessdev@1.0.12
mkdir -p vendor components
cp node_modules/bundlessdev/dist/bundless.acorn.min.js vendor/bundless.acorn.min.js
```

Create `index.html`:

```html
<!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="importmap">
{
  "imports": {
    "react": "https://esm.sh/react@17.0.2/es2022/react.mjs",
    "react-dom": "https://esm.sh/react-dom@17.0.2/es2022/react-dom.mjs"
  }
}
</script>
<div id="react-root"></div>
<script src="./App.jsx" type="text/jsx"></script>
<script src="./vendor/bundless.acorn.min.js" type="module"></script>
```

Create `App.jsx`:

```jsx
import React from "react";
import ReactDOM from "react-dom";
import Header from "./components/Header.jsx";

function App() {
  return <Header />;
}

ReactDOM.render(<App />, document.getElementById("react-root"));
```

Create `components/Header.jsx`:

```jsx
import React from "react";
import Button from "./Button.jsx";

export default function Header() {
  return (
    <header>
      <h1>Hello from three files.</h1>
      <Button>It works</Button>
    </header>
  );
}
```

Create `components/Button.jsx`:

```jsx
import React from "react";

export default function Button({ children }) {
  return <button type="button">{children}</button>;
}
```

Run `npx http-server . -c-1` and open the printed HTTP URL. Do not use a
`file://` URL. All application paths are relative, so the folder also works
under a hosted subdirectory.

If a CDN dependency is acceptable, the local runtime tag can be replaced with:

```html
<script src="https://unpkg.com/bundlessdev@1.0.12/dist/bundless.acorn.min.js" type="module"></script>
```

## Runtime choice

- Acorn is the recommended JSX default. `bundless.acorn.dev.js` includes inline
  runtime source maps. `bundless.acorn.min.js` and the explicit `.prod.js` build
  omit those maps and are byte-identical, minified builds.
- Meriyah is the alternate JSX parser and follows the same dev-versus-production
  source-map distinction.
- Sucrase handles JSX, TypeScript, and TSX. It removes TypeScript syntax but does
  not type-check it; run `tsc --noEmit` separately when checks are required. Its
  single browser build appends the source map generated by Sucrase inline.
- Babel uses Babel Standalone. Its single browser build requests a source map
  from Babel Standalone and appends it inline.

The local default Acorn runtime is about 35.1 kB with Brotli; Sucrase is about
56.4 kB (decimal kB = 1,000 bytes). These download sizes apply only when the
server serves Brotli with `Content-Encoding: br`. See the canonical
[browser footprint table](README.MD#browser-footprint) for raw sizes, other
variants, and the full npm package size. React, application code, and external
dependencies are additional; the Babel wrapper excludes Babel Standalone.

Acorn/Meriyah reuse one AST per compilation for module metadata and JSX edits,
preserving ordinary JavaScript source instead of regenerating the whole program.
Their parsers remain bundled; the separate module lexer and WASM payload are gone.
Babel/Sucrase retain their compiler-plus-lexer path. All default `.min.js` files
are minified. Acorn/Meriyah dev maps describe the final transformed source;
Babel/Sucrase compiler maps are not composed through subsequent loader rewrites.

Source preservation does not downlevel JavaScript for older browsers. Syntax
must be accepted by the selected parser and run in the target browser. Meriyah
still rejects trailing commas in dynamic imports and retains entity spellings
in quoted JSX attributes; Acorn decodes those attribute entities.

## Modules and cache

Bare package imports use the page import map. Relative and absolute local imports
ending in `.mjs`, `.js`, `.jsx`, `.ts`, or `.tsx` use the Bundless loader.
Named, default, namespace, and export-star re-exports work for those local source
modules, including query-bearing URLs.

Relative dynamic imports ending in `.js`, `.jsx`, `.ts`, or `.tsx` use the
Bundless loader. Relative `.mjs` dynamic imports retain native ESM behavior. Both
routes resolve from the source file URL rather than the temporary blob URL. Bare
dynamic imports remain native so the page import map applies.

`window.import()` caches by normalized original module URL. Concurrent and repeated
imports share one pending promise and one resolved module. A failed import is evicted
so a retry refetches. Query strings remain part of the cache key.

The custom loader exposes snapshot bindings: later mutations of an exported binding
do not propagate through transformed imports or re-exports. Cyclic custom-loader
graphs and export-star expansion through native or bare modules are not supported;
use explicit exports or a native/build-time ESM graph when those semantics matter.
Import attributes are unsupported on custom source imports and caller-relative
dynamic imports.

## More guides

- [Browser usage](https://bundless.dev/usage.html)
- [Multi-file starter](https://bundless.dev/docs/getting-started.html)
- [Module loading](https://bundless.dev/docs/guides/modules.html)
- [TypeScript and TSX](https://bundless.dev/docs/guides/typescript.html)
- [Runtime reference](https://bundless.dev/docs/reference/runtimes.html)
- [Webpack migration](https://bundless.dev/migration.html)
- [Troubleshooting](https://bundless.dev/docs/troubleshooting.html)
