Conversation
An ES module build cannot follow a require() call: esbuild keeps it as a runtime require, which throws in browsers (the concerto-core one in markdown-transform runs at load time). Convert the five remaining calls to imports and declare the two untyped modules. dayjs has no exports map, so its plugin subpath carries the .js extension Node ESM needs. Signed-off-by: Ujjwal Verma <ujjwalverma010305@gmail.com>
formulaName() was the only use of Node crypto, which pulled about 1 MB of crypto-browserify into browser bundles. @noble/hashes 1.x is a pure JavaScript SHA-256 (5 KB minified) with CommonJS and ESM builds. Names are unchanged; new tests compare against Node crypto. Signed-off-by: Ujjwal Verma <ujjwalverma010305@gmail.com>
scripts/build-esm.js, modelled on Concerto v5, emits lib/esm (import condition) and lib/esm-browser (browser condition) next to the CommonJS lib/. Dependencies stay bare imports so consumers share one copy of each; the browser build stubs Node builtins and jsdom. scripts/smoke-esm.mjs runs after the root build. BREAKING CHANGE: each package now has an exports map, so deep imports into lib/ no longer resolve, and Node import loads the ESM build. Signed-off-by: Ujjwal Verma <ujjwalverma010305@gmail.com>
Bundles the packages through the browser export condition with esbuild, as an application would, and runs the result in Chromium. Signed-off-by: Ujjwal Verma <ujjwalverma010305@gmail.com>
The exports maps already route webpack 5, Vite, Rollup and esbuild to lib/esm-browser, so the UMD bundles only served script-tag users and tools that do not read exports. Remove them with their webpack configs, the browser field, the Node polyfill devDependencies and the process dependency (113 packages out of the lockfile). The UMD e2e cases move into esm-browser.spec.ts. MIGRATION.md describes the 2.0 changes. BREAKING CHANGE: the umd/markdown-html.js, umd/markdown-template.js and umd/markdown-transform.js bundles are no longer published; bundle the packages instead (see MIGRATION.md). Signed-off-by: Ujjwal Verma <ujjwalverma010305@gmail.com>
Author
|
Hi @mttrbrts , opening this as a draft because four choices here are mine and I'd like your call before marking it ready:
This is the first of the section 2 PRs. Next are concerto-codegen (which can go in parallel), cicero-core once markdown 2.0 is released, and then template-engine. |
ujjwalv01
marked this pull request as ready for review
October 4, 2026 10:20
This branch has not been deployed
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.
Part of accordproject/template-engine#185 (section 2)
Every library package now ships two ES module builds next to the CommonJS
lib/:lib/esmfor Node andlib/esm-browserfor bundlers targeting the web. An explicitexportsmap selects between them. The webpack UMD bundles are removed. A browser bundler now takes each package'slib/esm-browserand shares one copy of markdown-it, dayjs and Concerto with the rest of the application. Before, each UMD bundle carried its own copy of Concerto plus about 1 MB of Node polyfills, and the markdown-transform UMD nested the markdown-template and markdown-html UMDs inside itself. The approach follows Concerto v5 (accordproject/concerto#1306).What template-engine imports from these packages (
{ TemplateMarkTransformer }and{ transform }), bundled for the browser with esbuild, Concerto included:lib/esm-browserChanges
refactor(*): the five remainingrequire()calls insrc/becomeimportstatements: markdown-it-cicero, markdown-it-template, concerto-core'sModelLoader, dijkstrajs and type-of. Type declarations are added for the last two. An ES module build cannot follow arequire(); the one in markdown-transform would have thrown in browsers as soon as the module loaded.dayjs/plugin/utcbecomesdayjs/plugin/utc.js, because dayjs has no exports map and Node ESM needs the extension.feat(markdown-template):formulaName()uses@noble/hashesinstead of Nodecrypto. Nodecryptowas the only reason crypto-browserify was in the browser bundles. Formula names are unchanged; new tests compare them against Nodecrypto.feat(*)!:scripts/build-esm.jsemitslib/esmandlib/esm-browserwith esbuild, one output module per source module. Dependencies stay as imports; the browser build replaces Node builtins and jsdom with empty modules. The seven library packages getexports(.and./package.jsononly),moduleandsideEffects: false. markdown-cli is a Node-only CLI and is unchanged.scripts/smoke-esm.mjsruns after the root build with 9 checks:importtolib/esm;require()(other than jsdom in the Node build);process.test(e2e):esm-browser.spec.tsbundles the packages through thebrowsercondition, as an application's bundler would, and runs the result in Chromium.feat(*)!: the UMD bundles are dropped, along with:browserfield;processdependency (113 packages out of the lockfile);The UMD e2e cases move into
esm-browser.spec.ts. MIGRATION.md is added, and the e2e README, the markdown-html README and.github/copilot-instructions.mdare updated.Flags
Breaking, needs a major release (2.0):
.../lib/...) no longer resolve;importnow loads the ESM build, so a process using bothimportandrequire()holds two copies;processdependency are gone.MIGRATION.md covers each case. I found no deep imports of these packages in other accordproject repos; template-engine, template-playground, cicero-core, template-cli, template-compiler and vscode-extension all import package roots.
New dependencies:
@noble/hashes^1.8 (runtime, markdown-template) is a pure JavaScript SHA-256: 5 KB minified, CommonJS and ESM builds. I used v1 because v2 is ESM-only.esbuild^0.27.7 (root dev dependency) is the same tool Concerto uses for its ESM builds.Differs from Concerto: Concerto bundles third-party dependencies into its browser build; this PR leaves them as imports. That gives one copy of markdown-it instead of three, and 689 KB instead of 977 KB minified for the imports above. The cost is that
lib/esm-browsercannot be loaded without a bundler using an import map alone, because dayjs and @xmldom/xmldom are CommonJS.Differs from (feat) convert commonmark dom to plain text #185: item 1 proposed keeping the UMD as a
./umdsubpath; this PR removes it, as Concerto v5 did.The design choices above are listed as questions in the first comment.
Screenshots or Video
N/A: build and packaging change.
Related Issues
Testing
npm test: 1,866 passed (1,860 before plus 6 new), 1,602 snapshots unchanged; lint shows 0 errors and licchk passes.npm run test:esm: 9/9. I confirmed the guard works: putting onerequire()back makes it fail in both builds.Author Checklist
--signoffoption of git commit.mainfromujjwalv01:build/esm-exports