feat: support monaco-editor 0.56 - #2
Merged
Merged
Conversation
0.56 reorganized the ESM tree and added an `exports` map, and the combination
breaks the one deep import this package makes. The pgsql definition extends
monaco's own monarch grammar rather than duplicating it, so it imports
`basic-languages/pgsql/pgsql` directly. Under 0.56 that specifier resolves to
nothing, and any consumer bundling this package fails with:
Module not found: Package path ./esm/vs/basic-languages/pgsql/pgsql is exported
from package monaco-editor, but no valid target file was found
Two separate things have to change to fix it:
- The definitions moved to `languages/definitions/<lang>/<lang>`.
- The path must go through the exports map (`monaco-editor/<path>`, not
`monaco-editor/esm/vs/<path>`), and must carry its `.js` extension. The map's
wildcards rewrite `./<path>` to `./esm/vs/<path>.js` and match the result
literally, so the extensionless form resolves to a file that does not exist.
Verified end to end against a *pristine* 0.56 install -- deliberately not the
patched copy popsql carries -- by building the package, installing it as a
consumer would, and awaiting the lazy loader over both CJS and ESM. pgsql resolves
with 657 builtin functions including the pg17 additions, and timescale (which
layers on pgsql) resolves with 825.
Because 0.56 is now the floor, `peerDependencies` narrows from `*` to `>=0.56.0`
rather than silently mis-resolving on older versions. The devDependency moves from
^0.38.0 to ^0.56.0 so CI tests what consumers actually get.
Three incidental fixes, each needed to keep the existing suites running on 0.56:
- tsconfig: 0.56's `typings` field points at ./esm/vs/editor/editor.main.d.ts,
which the package no longer ships; the real declarations are at
./esm/vs/index.d.ts, reachable only through `exports`. Since
`moduleResolution: node` ignores `exports`, TypeScript was falling back to the
untyped ./min bundle and failing every `import ... from 'monaco-editor'` with
an implicit any. Mapped explicitly via `paths`. Upgrading TypeScript to 5.x
and using a resolution mode that honors `exports` would be the cleaner fix,
but that is a larger change than this one warrants.
- babel: 0.56 locates its workers with `new URL(..., import.meta.url)`, which is
a syntax error once Jest transforms those modules to CJS, so the whole
editor.api import chain failed to load. Added
babel-plugin-transform-import-meta. Tests only tokenize strings and never
start a worker, so the rewrite is inert at runtime.
- jest: `moduleNameMapper` stripped the package name but did not apply 0.56's
`esm/vs/` rewrite, so the new specifier resolved nowhere. Added a rule that
mirrors the exports map, ahead of the existing generic rule that still handles
already-`esm/...` paths.
- test mocks: 0.56 builds its icon stylesheet through `CSS.escape`, absent in
jsdom, which threw inside setMonarchTokensProvider before any tokenization ran.
All 228 tokenization tests pass, lint is clean, and both build targets emit.
murrayju
force-pushed
the
murrayju/monaco-0.56
branch
from
August 4, 2026 16:01
c2c1c94 to
08b3038
Compare
This repo had not been touched in a couple of years, and the previous commit was
sitting on a toolchain old enough to make the monaco 0.56 support awkward: pinning
babel-plugin-transform-import-meta to 2.x purely to keep @babel/template off node
>=22, and mapping monaco's declarations through tsconfig `paths` because
TypeScript 4.9 has no resolution mode that reads `exports`.
Toolchain
- Node >=24, declared in `engines` and .nvmrc, and the only version CI builds.
The old matrix (14/16/18/20/22) could not survive this: monaco 0.56, jest 30 and
the current typescript-eslint all require newer runtimes.
- TypeScript 4.9 -> 5.9, jest 29 -> 30, prettier 2 -> 3, husky 8 -> 9,
lint-staged 13 -> 17, rimraf 5 -> 6, typescript-eslint 5 -> 8, babel to current.
- eslint stays on 8. Moving to 9+ means flat config, and both
eslint-config-airbnb-base (unmaintained, eslint <=8) and
eslint-plugin-typescript-sort-keys (eslint <=8) block that. Worth doing, but it
is a rewrite of the lint setup rather than a version bump, so it is left alone
here.
- CI also runs `yarn lint` now, and installs with --frozen-lockfile so a stale
lockfile fails the build instead of being silently rewritten. Actions bumped off
the deprecated v2/v3 releases.
- The publish workflow ran node 16, which `engines` would now reject outright.
TypeScript resolution
With TypeScript 5 available, the `paths` mapping added in the previous commit is
replaced by resolution modes that actually understand `exports`: `bundler` for the
ESM build, `node16` for the CJS build (`bundler` requires an ES module, and plain
`CommonJS`/`node10` cannot see monaco's declarations at all). Verified the CJS
output is still CommonJS -- `module: node16` emits either form depending on
context.
Packaging fix
`exports` listed `types` last, after `import` and `require`. Node and TypeScript
take the first matching condition, so the type declarations were never selected
and consumers silently got none. Nested under `.` with `types` first, plus a
`./package.json` entry. Confirmed against a scratch consumer with a pristine 0.56
install: `import { pgsqlLanguageDefinition } from '@popsql/monaco-sql-languages'`
now typechecks, where before it failed with "Cannot find module ... or its
corresponding type declarations". This bug predates this branch.
The example app pinned monaco ^0.38.0, which now violates the peer range, and its
react-monaco-editor was too old to accept 0.56. Both bumped; the publish workflow
builds this site.
Verified from a clean clone on node 24: install, lint, 228 tests, and both build
targets all pass, and the built package still resolves and typechecks from a
consumer against an unpatched monaco 0.56 (pgsql 657 builtins, timescale 825, over
both CJS and ESM).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds support for monaco-editor 0.56 (which this package currently cannot build against), and modernizes the build chain onto Node 24 / TypeScript 5 while we're in here.
Two commits, separately reviewable:
08b3038feat: support monaco-editor 0.56— the actual fixc162de2chore: modernize the build chain onto node 24 and typescript 5This is blocking timescale/popsql#4913, which is carrying a
patch-packagepatch against this package as a stopgap. Once this is released, that patch can be deleted.Part 1 — monaco 0.56 support
0.56 reorganized the ESM tree and added an
exportsmap. The pgsql definition extends monaco's own monarch grammar rather than duplicating it, so it importsbasic-languages/pgsql/pgsqldirectly — and under 0.56 that specifier resolves to nothing:Two things have to change: the definitions moved to
languages/definitions/<lang>/<lang>, and the path must go through the exports map (monaco-editor/<path>, notmonaco-editor/esm/vs/<path>) with its.jsextension — the map's wildcards rewrite./<path>→./esm/vs/<path>.jsand match literally, so the extensionless form points at a file that doesn't exist.No single specifier spans versions, which is why the peer range has to narrow:
esm/vs/basic-languages/pgsql/pgsqlesm/vs/basic-languages/pgsql/pgsql.jslanguages/definitions/pgsql/pgsql.jsSo
peerDependenciesgoes*→>=0.56.0rather than silently mis-resolving on older versions.Three incidental fixes, each required to get the existing suites running on 0.56 — none cosmetic:
new URL(..., import.meta.url), a syntax error once Jest transforms those modules to CJS, so the wholeeditor.apiimport chain failed to load. Addedbabel-plugin-transform-import-meta; tests only tokenize strings and never start a worker, so it's inert at runtime.moduleNameMapper— stripped the package name but didn't apply 0.56'sesm/vs/rewrite, so the new specifier resolved nowhere. Added a rule mirroring the exports map, ahead of the existing generic rule (whichtransformIgnorePatternsdepends on).CSS.escape, absent in jsdom, which threw insidesetMonarchTokensProviderbefore any tokenization ran.Part 2 — toolchain modernization
The old toolchain made the above awkward: pinning
babel-plugin-transform-import-metato 2.x purely to keep@babel/templateoff Node ≥22, and mapping monaco's declarations through tsconfigpathsbecause TS 4.9 has no resolution mode that readsexports.engines+.nvmrc, and the only version CI builds. The old matrix (14/16/18/20/22) couldn't survive this — monaco 0.56, jest 30, and current typescript-eslint all need newer runtimes.eslint-config-airbnb-base(unmaintained, eslint ≤8) andeslint-plugin-typescript-sort-keys(eslint ≤8) block it. Worth doing, but that's a rewrite of the lint setup rather than a version bump — happy to take it as a follow-up.yarn lint, installs with--frozen-lockfile(a stale lockfile fails instead of being silently rewritten), and is off the deprecatedactions/*@v2/@v3. The publish workflow ran Node 16, whichengineswould now reject outright.With TS 5 available, the
pathsmapping from the first commit is replaced by resolution modes that genuinely understandexports:bundlerfor ESM,node16for CJS (bundlerrequires an ES module; plainCommonJS/node10can't see monaco's declarations at all). Verified the CJS output is still CommonJS —module: node16emits either form depending on context.Packaging bug found along the way
exportslistedtypeslast, afterimport/require. Node and TypeScript take the first matching condition, so the declarations were never selected and consumers silently got no types at all. Now nested under.withtypesfirst, plus a./package.jsonentry.Confirmed against a scratch consumer with a pristine 0.56 install:
import { pgsqlLanguageDefinition } from '@popsql/monaco-sql-languages'now typechecks, where before it failed with "Cannot find module ... or its corresponding type declarations". This bug predates this branch — it's a real improvement for consumers independent of the monaco work.The example app pinned monaco
^0.38.0(now violating the peer range) with areact-monaco-editortoo old to accept 0.56; both bumped, since the publish workflow builds that site.Verification
Verified against a pristine 0.56 install — deliberately not the patched copy popsql carries — by building, installing as a consumer would, and awaiting the lazy loader over both CJS and ESM:
pgsqlLanguageDefinition.loader()→ 657 builtin functions, pg17 additions present (json_table)timescaleLanguageDefinition.loader()→ 825 (correctly layering on pgsql)tsc --moduleResolution bundler→ cleanFrom a clean clone on Node 24: install, lint, 228 tests, and both build targets pass. CI green on 24.x.
Release note
No version bump in the diff — the publish workflow sets the version from the release name. This needs a release cut (0.4.0 seems right, given the peer-dependency narrowing and the Node floor) before popsql can drop its patch.