Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Migrate Core output from CJS to ESM - #2863

Merged
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm
Mar 23, 2026
Merged

Migrate Core output from CJS to ESM#2863
Harjun751 merged 17 commits into
MarkBind:masterfrom
Harjun751:core-cjs-to-esm

Conversation

@Harjun751

@Harjun751Harjun751 commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of this pull request?

  • Documentation update
  • Bug fix
  • Feature addition or enhancement
  • Code maintenance
  • DevOps
  • Improve developer experience
  • Others, please explain:

Works towards #2615

Overview of changes:
Mostly similar to #2836, though there are nitty-gritty differences

  • Add ESM configuration
  • Update import syntax where required
  • Change jest test runner from ts-jest to babel transpilation

Anything you'd like to highlight/discuss:
Tests in core use babel now, meaning that the ESM test code is transpiled to CJS. This is just like CLI now.

Luckily, unlike the CLI ESM migration, no package was outright not working. And thankfully, with the winston migration done, I didn't get an issue with that!

Testing instructions:
Check that core-web builds is fine and not affected, since a component in that was slightly changed to conform with ESM syntax.

  • Serve CS2103 website and see that nothing breaks

^ I would like to do this just as a sanity check because I think implications are quite wide with this PR. I'll get to it soon before merging.

Proposed commit message: (wrap lines at 72 characters)

Migrate Core package from CommonJS to ES Modules

  • Convert Core package to ESM with type: 'module'
  • Switch from ts-jest to babel-jest for testing
  • Update all imports to use ESM syntax

Checklist: ☑️

  • Updated the documentation for feature additions and enhancements
  • Added tests for bug fixes or features
  • Linked all related issues
  • No unrelated changes

Reviewer checklist:

Indicate the SEMVER impact of the PR:

  • Major (when you make incompatible API changes)
  • Minor (when you add functionality in a backward compatible manner)
  • Patch (when you make backward compatible bug fixes)

At the end of the review, please label the PR with the appropriate label: r.Major, r.Minor, r.Patch.

Breaking change release note preparation (if applicable):

  • To be included in the release note for any feature that is made obsolete/breaking

Give a brief explanation note about:

  • what was the old feature that was made obsolete
  • any replacement feature (if any), and
  • how the author should modify his website to migrate from the old feature to the replacement feature (if possible).

Harjun751and others added 13 commits March 20, 2026 21:28
Core uses `require` imports due to CJS.
ESM uses `import { } and export { }` syntax
instead.
Change all import/export formats to use
ESM-compatible syntax.
See MarkBind#2836 or commit #265fbac for
the reasons why.
Dynamic imports are used throughout core code.
These imports (with `require()`) are not
compatible with ESM syntax.
Replace with `createRequire` where necessary.
Additionally, use fileURLToPath for __dirname
alternative in ESM.
Importing ignore uses a fragile workaround.
Change to importing using createRequire()
This allows the CJS module to be imported
as expected in the ESM environment.
src files use `__filename` variable name with
`import.meta.url`.
This causes an issue with transpiling
`import.meta` calls to CJS - see:
javiertury/babel-plugin-transform-import-meta#8
Change `__filename` to `__filepath`
core-web/ uses CJS `export = ` format.
This doesn't work with ES modules.
Change to `export { ... }` format.
Let's
* Update package.json to specify `type: module`
* Update tsconfig to specify module resolution
* Update tsconfig lint
Jest doesn't support ESM testing OOB.
Use babel to transpile to CJS, allowing
testing.
See MarkBind#2836 or #5d66aac for
more discussion.
Add eslintrc.cjs file to core.
Use same rules as cli, with some changes.
NodeNext imposes stricter type-checking.
Let's add module declarations for:
- markdown-it internal subpaths (lib/renderer, lib/token, etc.)
- Untyped markdown-it plugins and fastmatter
- csv-parse/lib/sync subpath (csv-parse v4)
- @markbind/core-web UMD bundle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Markdown-it-linkify was bumped to v4 from v3
during development of this branch.
There may be breaking changes introduced by this.
Undo bump and reset to version that was being
used before.
Bumping markdown-it should be done in its own
PR as there may be other implications that
should be observed.
@Harjun751Harjun751 changed the title Core cjs to esmMigrate Core output from CJS to ESMMar 20, 2026
@codecov

codecovBot commented Mar 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.23810% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.29%. Comparing base (8e80ff8) to head (c0943eb).
⚠️ Report is 1 commits behind head on master.

Files with missing linesPatch %Lines
...down-it/patches/custom-component/htmlInlineRule.ts16.66%15 Missing ⚠️
...re/src/plugins/default/markbind-plugin-plantuml.ts80.00%8 Missing and 1 partial ⚠️
...kdown-it/patches/custom-component/htmlBlockRule.ts72.72%6 Missing ⚠️
packages/core/src/plugins/dataTable.ts95.65%1 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## master #2863 +/- ##
==========================================
- Coverage 71.99% 70.29% -1.71% 
==========================================
Files 132 129 -3 Lines 7352 6951 -401 Branches 1635 1633 -2 ==========================================
- Hits 5293 4886 -407 - Misses 1958 1964 +6 
Partials 101 101 

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR continues the repository-wide ESM migration (issue #2615) by converting the @markbind/core package output and its test environment to ES Modules, aligning Core with the earlier CLI ESM work.

Changes:

  • Switch Core’s TS compilation to NodeNext and set packages/core to "type": "module".
  • Update Core source + tests to ESM-style imports (including explicit .js for internal relative imports) and adjust several CJS interop points.
  • Replace ts-jest with a Babel-based Jest setup for Core tests.

Reviewed changes

Copilot reviewed 134 out of 138 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
packages/core/tsconfig.lint.jsonLint TS config updated for NodeNext module resolution.
packages/core/tsconfig.jsonCore TS compilation switched to NodeNext/NodeNext resolution.
packages/core/test/unit/utils/utils.tsUpdate test imports to ESM-style paths.
packages/core/test/unit/utils/LockManager.test.tsUpdate LockManager import to new ESM export shape.
packages/core/test/unit/utils/HtmlValidationUtil.test.tsUpdate imports for ESM paths.
packages/core/test/unit/plugins/default/tree.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/shorthandSyntax.test.tsUpdate default plugin imports for ESM paths/shape.
packages/core/test/unit/plugins/default/plantuml.test.tsUpdate plugin + NodeProcessor imports for ESM paths.
packages/core/test/unit/plugins/default/mermaid.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/dataTable.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/plugins/default/anchor.test.tsUpdate imports for ESM paths/shape.
packages/core/test/unit/lib/progress/node-progress.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/set-external.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/nunjucks-extensions/nunjucks-date.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-radio-button.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-icons.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-footnotes.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-double-delimiter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-colour-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-center-text.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-block-embed.test.tsUpdate block-embed plugin import to new named export entrypoint.
packages/core/test/unit/lib/markdown-it/plugins/markdown-it-alt-frontmatter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/index.test.tsUpdate markdown-it import to explicit index entrypoint.
packages/core/test/unit/lib/markdown-it/highlight/helper.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/Highlighter.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRuleComponent.test.tsUpdate imports for ESM paths.
packages/core/test/unit/lib/markdown-it/highlight/HighlightRule.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/linkProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/includePanelProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/cardStackProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/SiteLinkManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/html/NodeProcessor.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SitePagesManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/SiteGenerationManager.test.tsUpdate imports + require paths for ESM builds.
packages/core/test/unit/Site/SiteDeployManager.test.tsAdjust mocks/imports for ESM module paths.
packages/core/test/unit/Site/SiteAssetsManager.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Site/Site.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/index.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/filterIconAssets.test.tsUpdate imports for ESM paths.
packages/core/test/unit/Page/PageVueServerRenderer.test.tsUpdate dynamic imports for ESM paths.
packages/core/test/functional/Site.functional.test.tsUpdate imports for ESM paths.
packages/core/src/variables/VariableRenderer.tsConvert internal imports + patch load to ESM import.
packages/core/src/variables/VariableProcessor.tsConvert internal imports to ESM paths.
packages/core/src/utils/logger.tsUpdate type-only import path for ESM.
packages/core/src/utils/htmlValidationUtil.tsUpdate internal logger import to ESM path.
packages/core/src/utils/LockManager.tsConvert singleton export from export = to named ESM export.
packages/core/src/plugins/web3Form.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/mermaid.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/mathDelimiters.tsConvert plugin module from CJS export to ESM exports; update texmath import.
packages/core/src/plugins/googleAnalytics.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/filterTags.tsConvert plugin module from CJS export to ESM exports; update lodash usage.
packages/core/src/plugins/disqus.tsConvert plugin module from CJS export to ESM exports; formatting cleanup.
packages/core/src/plugins/default/markbind-plugin-tree.tsConvert plugin module from CJS export to ESM exports; update lodash/md usage.
packages/core/src/plugins/default/markbind-plugin-shorthandSyntax.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/default/markbind-plugin-plantuml.tsConvert plugin module to ESM imports/exports; replace crypto require with ESM-friendly usage; add import.meta dirname.
packages/core/src/plugins/default/markbind-plugin-anchors.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/dataTable.tsConvert plugin module from CJS export to ESM exports; update markdown-it import.
packages/core/src/plugins/codeBlockWrapButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockCopyButtons.tsUpdate internal imports to ESM paths; convert to ESM exports.
packages/core/src/plugins/codeBlockButtonsAssets/codeBlockButtonsContainer.tsUpdate MbNode import to ESM path.
packages/core/src/plugins/algolia.tsConvert plugin module from CJS export to ESM exports.
packages/core/src/plugins/PluginManager.tsUpdate to ESM-style imports; replace patch require; adjust lodash usage; add import.meta dirname utilities.
packages/core/src/plugins/Plugin.tsUpdate to ESM-style imports; replace patch require; introduce createRequire for loading plugins.
packages/core/src/patches/nunjucks/nunjucks-submodules.d.tsUpdate nunjucks internal module declarations to .js deep imports.
packages/core/src/patches/nunjucks/nunjucks-internals.d.tsUpdate nunjucks internal module declarations to .js deep imports; extend runtime Frame typing for patching.
packages/core/src/patches/nunjucks/load-event.tsUpdate nunjucks runtime import to .js deep import; adjust lib access.
packages/core/src/patches/nunjucks/index.tsUpdate patch imports to explicit .js paths.
packages/core/src/patches/nunjucks/context-overrides-frame.tsRefactor patch to avoid require of frozen ESM namespace; update internal imports and compiler typing.
packages/core/src/patches/index.tsConvert patch barrel export from export = to named ESM export.
packages/core/src/lib/progress/index.tsUpdate re-export path to include .js.
packages/core/src/lib/nunjucks-extensions/set-external.tsUpdate csv-parse/nunjucks deep imports for ESM; adjust parser import pattern.
packages/core/src/lib/nunjucks-extensions/index.tsUpdate re-export paths to include .js.
packages/core/src/lib/markdown-it/plugins/markdown-it-radio-button.tsUpdate markdown-it deep import path and internal code cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-footnotes.tsUpdate internal constants import to ESM path; add token typing in filter callback.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/YouTubeService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VineService.tsConvert from CJS module.exports to ESM exports; minor refactors.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VimeoService.tsUpdate relative import to .js path; normalize quotes.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/VideoServiceBase.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/SlideShareService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PreziService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/services/PowerPointOnlineService.tsUpdate relative import to .js path.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/index.tsConvert default export to named export; update internal imports and minor cleanup.
packages/core/src/lib/markdown-it/plugins/markdown-it-block-embed/PluginEnvironment.tsUpdate internal imports to .js; adjust VineService import/export shape; minor cleanup.
packages/core/src/lib/markdown-it/patches/markdown-it-emoji-fixed.tsConvert to ESM export; switch to import attributes for JSON; normalize property access.
packages/core/src/lib/markdown-it/patches/custom-component/inlineTags.tsConvert export = to named ESM export.
packages/core/src/lib/markdown-it/patches/custom-component/htmlInlineRule.tsUpdate internal import to .js; convert export = to named ESM export; minor formatting.
packages/core/src/lib/markdown-it/patches/custom-component/htmlBlockRule.tsConvert require-style imports to ESM; convert export = to named ESM export; formatting cleanup.
packages/core/src/lib/markdown-it/patches/custom-component/customComponentPlugin.tsConvert require-style imports to ESM imports; update markdown-it import path.
packages/core/src/lib/markdown-it/index.tsConvert markdown-it setup to ESM exports; replace runtime require(...) plugins with ESM imports; update emoji patch usage.
packages/core/src/lib/markdown-it/highlight/Highlighter.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRuleComponent.tsUpdate relative import to include .js.
packages/core/src/lib/markdown-it/highlight/HighlightRule.tsUpdate relative import to include .js.
packages/core/src/html/warnings.tsUpdate internal imports to ESM paths.
packages/core/src/html/vueSlotSyntaxProcessor.tsConsolidate lodash imports; update node import path.
packages/core/src/html/siteAndPageNavProcessor.tsUpdate internal imports to ESM paths; replace patch require with import.
packages/core/src/html/linkProcessor.tsSwitch lodash import; add createRequire interop for ignore CJS package; update internal imports to ESM paths.
packages/core/src/html/includePanelProcessor.tsConsolidate lodash imports; convert internal imports to ESM paths; replace patch require with import.
packages/core/src/html/headerProcessor.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/elements.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/codeblockProcessor.tsConsolidate lodash imports; update markdown-it import to ESM entrypoint.
packages/core/src/html/cardStackProcessor.tsUpdate node import to ESM path.
packages/core/src/html/SiteLinkManager.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/NodeProcessor.tsConvert internal imports to ESM paths; replace fastmatter require with ESM import; replace patch require with import.
packages/core/src/html/MdAttributeRenderer.tsConsolidate lodash imports; update internal imports to ESM paths.
packages/core/src/html/MarkdownProcessor.tsUpdate markdown-it import to ESM entrypoint.
packages/core/src/html/FootnoteProcessor.tsUpdate internal imports to ESM paths.
packages/core/src/html/CustomListIconProcessor.tsUpdate internal imports to ESM paths; switch emoji patch import to ESM export.
packages/core/src/html/Context.tsUpdate CyclicReferenceError import to ESM path.
packages/core/src/errors/index.tsConvert export = to named ESM export.
packages/core/src/errors/CyclicReferenceError.tsConvert export = to named ESM export.
packages/core/src/declarations.d.tsAdd ambient module declarations for NodeNext/ESM type gaps.
packages/core/src/Site/template.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/index.tsUpdate imports to ESM paths; replace patch require with import.
packages/core/src/Site/constants.tsReplace curated lodash-function object with full lodash _ export.
packages/core/src/Site/SitePagesManager.tsUpdate imports to ESM paths; add import.meta dirname utilities.
packages/core/src/Site/SiteGenerationManager.tsUpdate imports to ESM paths; add JSON import for version; add import.meta dirname utilities.
packages/core/src/Site/SiteDeployManager.tsUpdate imports to ESM paths; adjust simple-git import style for ESM.
packages/core/src/Site/SiteConfig.tsUpdate FrontMatter import to ESM path.
packages/core/src/Site/SiteAssetsManager.tsAdd createRequire interop for ignore CJS package; update internal imports.
packages/core/src/Page/index.tsConsolidate lodash; add JSON import for version; add LockManager ESM import; adjust js-beautify interop; replace patch require with import.
packages/core/src/Page/PageVueServerRenderer.tsSwitch core-web bundle import wiring; update internal imports to ESM paths.
packages/core/src/Page/PageSources.tsConsolidate lodash import.
packages/core/src/Page/PageConfig.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/index.tsUpdate internal imports to .js paths.
packages/core/src/Layout/LayoutManager.tsUpdate internal imports to ESM paths.
packages/core/src/Layout/Layout.tsUpdate internal imports to ESM paths.
packages/core/src/External/ExternalManager.tsConsolidate lodash import; update internal imports to ESM paths.
packages/core/src/External/External.tsUpdate imports to ESM paths; adjust js-beautify interop.
packages/core/package.jsonMark package as ESM; add Babel/Jest deps for new test pipeline.
packages/core/jest.config.jsRemove old ts-jest config.
packages/core/jest.config.cjsAdd new Jest config for Babel-based TS transpilation.
packages/core/index.tsUpdate exports to ESM index entrypoints.
packages/core/babel.config.cjsAdd Babel config for Jest TS transpilation (ESM→CJS).
packages/core/.eslintrc.cjsAdd Core-scoped ESLint overrides for ESM import extensions + lodash rules.
packages/core-web/src/index.jsUpdate VueCommonAppFactory import to named exports.
packages/core-web/src/VueCommonAppFactory.jsChange export from default object to named exports.
packages/cli/src/lib/live-server/index.jsUpdate @markbind/core fsUtil import for ESM export shape.
package-lock.jsonLockfile updates reflecting dependency/tooling changes for Babel/Jest/ESM.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Changes converted default export syntax
for vueCommonAppFactory to non-default.
This caused a regression in the CI
environment when build:web was
used.
Revert the change and maintain old
import/export style for core-web.
@Harjun751
Harjun751 marked this pull request as ready for review March 21, 2026 08:00
@Harjun751
Harjun751 requested a review from a teamMarch 21, 2026 08:00

@yihao03yihao03 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at quite a few files I noticed its mostly just changes in import/export syntax, and sometimes some linting? LGTM overall but just wonders if we should be using default exports/imports in some cases

Comment threadpackages/core/src/errors/index.ts

@gerteckgerteck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your PR @Harjun751

LGTM

  • Seeing a lot of lint fixes in the PR.

  • Migrated from import XXX from '..' to import XXX from '...js' because ESM under NodeNext requires explicit file extensions in relative imports since Node.js no longer auto-resolves extensions like CJS did.

  • Migrated from optimized lodash imports (e.g. import has from 'lodash/has') to full lodash imports (e.g. import _ from 'lodash') because TypeScript's NodeNext module resolution cannot resolve types from lodash's per-function subpath imports in ESM, with the tradeoff of increased node_modules size being acceptable since lodash is only used in the CLI and does not affect end-user bundle size.

  • Migration added import { createRequire } from 'module'; const require = createRequire(import.meta.url); as ESM modules do not have require available natively, so createRequire(import.meta.url) creates a CJS-style require function rooted at the current file's location, needed to load CJS packages that can't be properly imported via ESM's import syntax.

  • Additionally, ESM has no __dirname or __filename globals like CJS does, so they have to be manually reconstructed from import.meta.url.

  • declarations.d.ts file added because the ESM/NodeNext migration introduced stricter module resolution, causing TypeScript to fail to resolve types for packages that lack a proper exports field in their package.json (e.g. markdown-it v12, csv-parse v4) or have no type definitions at all (e.g. markdown-it-mark, fastmatter). This file acts as a compatibility shim, manually declaring the types for these packages so the codebase compiles cleanly under NodeNext without waiting for every dependency to add ESM support.

  • Migrated from ts-jest to Babel for Jest test transformation because ts-jest compiles TypeScript to ESM output which Jest's CJS environment cannot run, whereas Babel transforms the source on the fly while converting ESM to CJS via modules: 'cjs', allowing Jest to run the tests without a separate build step.

  • Also noted migrated of plugins from export assignment (export = { ... }) which exported a single CJS object, to named exports (export { ... }) which is the proper ESM way of exporting multiple values individually.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point in the future, to complete the ESM migration entirely, PluginManager.ts which still relies on CJS interop workarounds (createRequire, __dirname reconstruction, require.resolve) to not use these workarounds.

These are currently used as some plugin files themselves may not have been fully migrated to ESM yet. These workarounds act as a bridge allowing the now-ESM PluginManager to dynamically load plugins that are still CJS.

This is also a user-facing change that would require a deprecation notice to be communicated to users who have authored their own plugins in _markbind/plugins/, giving them time to migrate their plugins to ESM named exports before support for CJS plugins is dropped.

@Harjun751Harjun751Mar 23, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, the __dirname reconstruction is something we can't workaround - using import.meta.url is the "proper" way of doing so.

(see: MDN import.meta, StackOverflow: Alternative for __dirname in Node.js when using ES6 modules)

For the other require calls, I've created an issue (#2867 ) to investigate and handle the plugin issue.

@Harjun751
Harjun751 merged commit 510231a into MarkBind:masterMar 23, 2026
10 of 11 checks passed
@github-actions

Copy link
Copy Markdown

@Harjun751 Each PR must have a SEMVER impact label, please remember to label the PR properly.

@gerteck

Copy link
Copy Markdown
Member

tbh i don't know if this is really considered a patch or major version change, technically @markbind/core is not depended externally... hmm

@gerteckgerteck added the r.Major Version resolver: increment by 1.0.0 label Mar 23, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r.MajorVersion resolver: increment by 1.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Harjun751@gerteck@yihao03