skip to content

What do dart compile js and dart compile wasm produce for a Dart web app, and what must the app avoid to compile to WebAssembly?

level: middleimportance: should knowfreq 30%

answer

  1. .js plus .js.map, out.js by default
  2. -O levels up to -O4
  3. .wasm plus a .mjs loader
  4. WasmGC browsers only
  5. dart:js_interop and package:web, not dart:html

basics

~20 s

dart compile js emits optimised JavaScript plus a source map; dart compile wasm emits a WasmGC module, a .mjs JavaScript loader and a source map. Wasm builds support only the new JS interop, so avoid dart:html and dart:js.

solid answer

~50 s

`dart compile js -O2 -o out/main.js web/main.dart` runs Dart's production JavaScript compiler: it tree-shakes and optimises, writing a `.js` file (named `out.js` if you give no `-o`) and a `.js.map` source map unless you pass `--no-source-maps`. `-O1` gives the default optimisations, `-O2` adds minification that is safe for all programs, and `-O3`/`-O4` also **omit implicit type checks**, so a type error that `-O2` would throw can crash or misbehave instead - test at `-O2` first. `dart compile wasm` targets **WasmGC**: it writes a `.wasm` module, a `.mjs` file that loads it from JavaScript, and a `.wasm.map`. Only browsers with WasmGC run it, and the code - including dependencies - may use only the next-generation interop, `dart:js_interop` and `package:web`; `dart:html` and `dart:js` are not supported. The dart.dev guide recommends `webdev` over invoking the JavaScript compiler directly for most JS web builds.

code

bash · 5 lines
bash
# Production JavaScript
dart compile js -O2 -o build/main.js web/main.dart

# WebAssembly (WasmGC) with its .mjs loader
dart compile wasm -o build/main.wasm web/main.dart

go deeper

for a junior

Recall that js gives JavaScript and wasm gives a WasmGC module plus a loader.

for a middle

Explain the -O levels, source maps, the .mjs loader and why only dart:js_interop and package:web work for Wasm.

for a senior

Audit dependencies for Wasm readiness, choose optimisation levels with evidence and decide how source maps are deployed.

for a principal

Decide whether a product ships JS, Wasm or both, given browser coverage and the migration cost off legacy interop.

## Dart's web compilers Dart has three ways to put code in a browser: an **incremental development compiler** to JavaScript used while iterating, an **optimising JavaScript production compiler**, and an **optimising WebAssembly (WasmGC) compiler**. `dart compile js` and `dart compile wasm` are the command-line entry points to the two production compilers. | | `dart compile js` | `dart compile wasm` | |---|---|---| | Output | `.js` + `.js.map` | `.wasm` + `.mjs` loader + `.wasm.map` | | Default output name | `out.js` | `<entry>.wasm` beside the entry point | | Runs in | any JavaScript engine | browsers with WasmGC support | | JS interop allowed | new and legacy | `dart:js_interop` and `package:web` only | ## dart compile js The JavaScript production compiler performs **tree shaking**, so importing a large library does not bloat the output with code you never call. Its optimisation levels: 1. **`-O0`** disables many optimisations. 2. **`-O1`** enables the default optimisations. 3. **`-O2`** adds more, such as minification, that respect language semantics and are safe for all programs. One visible effect: string representations of types differ from what the Dart VM and the development compiler show. 4. **`-O3`** adds omission of **implicit type checks**. A program that would have thrown a `TypeError` may instead crash or behave incorrectly, so the docs say to test at `-O2` and confirm the app never throws a subtype of `Error` before moving up. 5. **`-O4`** is more aggressive still, with the same assumptions, and is sensitive to variations in input data. Other useful options: `-o` for the output file, `--enable-asserts`, `-D<name>=<value>` for compile-time declarations, and `--no-source-maps` to skip the `.js.map` - the docs discuss the security side of shipping source maps. For most JavaScript web apps, dart.dev recommends the `webdev` tool, whose `build` command produces minified output by default. ## dart compile wasm The Wasm compiler produces a **WasmGC** module: WebAssembly with garbage collection, which lets Dart objects live in the engine's GC instead of a hand-managed heap. It writes the `.wasm` module and a **`.mjs` JavaScript file** that instantiates it, plus a `.wasm.map` source map unless you disable it. Restrictions: - **Browser support** - only browsers that implement WasmGC run it. - **JavaScript host** - the output targets JavaScript environments, not standalone Wasm runtimes. - **Interop** - only the next-generation interop is supported. Code importing `dart:html`, `dart:js` or `dart:js_util` - directly or through a dependency - does not compile. pub.dev's `is:wasm-ready` filter finds compatible packages, and `dart create -t web` already uses `package:web`. - **Conditional imports** - `dart.library.js` is false when compiling to Wasm, so web detection must use `dart.library.js_interop`. - **Deferred loading** is off by default and experimental behind `--enable-deferred-loading`; the app loader must supply a `loadDeferredModules` callback, which now receives a batch of module names. ## Scenario: a web build of the CLI's core If a CLI's parsing and formatting logic should also run in a browser demo, keep that logic free of `dart:io`, put the web entry point under `web/`, use `package:web` for DOM access, and build both `dart compile js` and `dart compile wasm` outputs, serving the Wasm build where WasmGC is available. ## Common mistakes - Shipping `-O4` without testing at `-O2` first. - Keeping a dependency that imports `dart:html` and wondering why Wasm compilation fails. - Deploying source maps publicly without deciding to. - Expecting the Wasm output to run in a standalone Wasm runtime.

  • What exactly changes between dart compile js -O2 and -O3?
    `-O3` keeps all `-O2` optimisations and also omits implicit type checks. Code that would have thrown a `TypeError` at `-O2` can crash or misbehave silently at `-O3`, so you verify at `-O2` that the app never throws an `Error` subtype before switching.
  • Why does a Dart web app that imports dart:html fail to compile with dart compile wasm?
    The Wasm compiler supports only the next-generation JS interop - `dart:js_interop` and `package:web`. Legacy web libraries such as `dart:html` and `dart:js` are not available, so the app and its dependencies must migrate to `package:web`.

saying these in an interview costs you the question

  • Thinks -O3 is always safe because -O2 passed tests
  • Believes dart compile wasm output runs in any Wasm runtime
  • Assumes dart:html works when compiling to Wasm
  • Thinks tree shaking means unused imports bloat the output
  • Uses dart.library.js to detect the web in a Wasm build