Skip to content

Support modern ESM dependencies (e.g. @texel/color)#32

Open
mattdesl wants to merge 1 commit into
masterfrom
claude/session-2p1h5
Open

Support modern ESM dependencies (e.g. @texel/color)#32
mattdesl wants to merge 1 commit into
masterfrom
claude/session-2p1h5

Conversation

@mattdesl

@mattdesl mattdesl commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Problem

Importing a package authored as native ES modules fails today:

import { convert } from "@texel/color";
ParseError: 'import' and 'export' may appear only with 'sourceType: module'

The CLI runs esmify with nodeModules: false, so ESM published to node_modules is never converted to CommonJS for browserify. And even with that flag flipped, browserify's parser (an older acorn via module-deps) can't read modern operators like ?? and ?. that such packages use — @texel/color hits both (core.js uses ??, other files use non-ASCII identifiers like let ε = …).

Approach

Rather than rip out browserify/budo (which would risk the dev server, hot reload, glslify static analysis, and instrumentation), this adds a narrowly-scoped esbuild transform that only touches node_modules — which currently isn't transformed at all, so the change is purely additive:

  • converts import/export → CommonJS so browserify can bundle the dependency
  • lowers only the operators the bundler's parser can't read (target: es2019) and keeps non-ASCII identifiers literal (charset: utf8)
  • skips files that don't need it (plain CJS without import/export/??/?.)

This is not a transpile-to-ES5 step. Modern syntax (classes, async/await, arrow functions, spread, template literals, destructuring, …) is preserved — only what the parser literally can't read is lowered.

Local source is untouched and still handled by esmify, which preserves the static-require analysis that glslify/brfs depend on. So no existing behavior changes.

Verified

  • import { convert, sRGB, OKLCH } from "@texel/color" now bundles and runs (both the --build path and the budo dev server)
  • A combined sketch mixing local ESM import, a glslify template tag (#define GLSLIFY 1 still injected ✓), a CJS dep (canvas-sketch), and the ESM dep all bundle together correctly
  • Compressed (terser) build works
  • Existing tests still pass; adds a new test bundling a modern ESM-only dependency

Changes

  • src/plugins/transform-esbuild.js — new node_modules-only esbuild transform
  • src/index.js — register the transform as a global (-g) browserify transform
  • package.json — add esbuild dependency
  • test/test-esm-deps.js + fixture — coverage for bundling an ESM-only dep

https://claude.ai/code/session_01K5PbUnmY8T48tcRZ7VL6cq


Generated by Claude Code

Importing a package authored as native ES modules (e.g.
`import { convert } from "@texel/color"`) previously failed with
"'import' and 'export' may appear only with 'sourceType: module'".

The bundler used esmify with `nodeModules: false`, so ESM published to
node_modules was never converted to CommonJS for browserify. Even with
that flag flipped, browserify's parser (an older acorn via module-deps)
can't read modern operators like `??` and `?.` that such packages use.

This adds a narrowly-scoped esbuild transform that runs over node_modules
files only:

  - converts import/export to CommonJS so browserify can bundle them
  - lowers just the operators the parser can't read (target es2019), and
    keeps non-ASCII identifiers literal (charset utf8)

It is NOT a transpile-to-ES5 step: modern syntax (classes, async/await,
arrow fns, spread, etc.) is preserved. Local source is still handled by
esmify, which keeps the static-require analysis that glslify/brfs rely on,
so no existing behavior changes. Build and dev-server paths, glslify, env
injection, CJS deps, source maps and minification all continue to work.

Adds a test covering bundling of a modern ESM-only dependency.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants