Repository navigation
Migration to ES Modules #6520
Description
Have you read the Contributing Guidelines on issues?
- I have read the Contributing Guidelines on issues.
Motivation
I did a very naïve attempt to migrate to ESM in #5816, but I far underestimated the difficulty in pushing it through. After some pondering, I think this should be rolled out progressively.
Status of ESM
ESM is a new type of Node modules system, replacing the old common JS system (require + module.exports). For the engine, the parsing goal is different ("module" or "script"), so a file needs to be determined as ESM or CJS before executing it, either through the .mjs extension or through the "type": "module" entry in the nearest package.json.
If a file is ESM, it can import from other ES modules. However, it may not be able to import all CJS modules, depending on how the CJS module is structured, because exported symbols, per the ES spec, need to be lexically determined, while CJS can be far more dynamic.
If a file is CJS, it can't import ESM modules, unless the await import() dynamic import is used. However, this is against the norm of how most modules are imported. This effectively means as soon as a considerable number of the dependencies are ESM, we have to migrate ourselves.
Many packages on NPM are now ESM-only, most notably the packages by Sindre Sorhus, and MDX v2, which is the pillarpost of our architecture.
Benefits
- Unlock future dependency upgrades. Many popular libraries are seeking to upgrade to ESM; if we can be ESM, we can interoperate with them. For example, MDX v2, chalk...
- A similar transpilation target for client and server code; no need for multiple tsconfigs
- Permit top-level awaits
Blockers
- TypeScript has very lame support of ESM transpilation so far. It seems their deferred ESM support still won't land in 4.6, so in the meantime we may have to run all our Node code with
--experimental-specifier-resolution=nodeand keep the old resolution - Jest doesn't seem to like importing ESM dependencies
- We use
import-freshto bypass cache and always import fresh modules for hot reloading, etc. But ES Modules don't expose caching manipulation yet - Community dividing: although the ESM migration will surely be a major version, it means in the foreseeable future after that, some plugins will not be compatible with the new version (especially those that import
utilsandlogger)
Actions needed
- Removing
__filenameand__dirname. These globals don't exist in the ESM scope, replaced by theimport.meta.url - Setting
target: 'nodenext'in the tsconfig. - Changing our import paths. ESM requires the
index.jsname and the.jsextension to be explicit. - Setting
"type": "module"in our package.json. - Tweaking the configuration for related tools?
Plan
- Config files: JS config files like
docusaurus.config.jsandsidebars.jscan be allowed in ESM once we figure out how to bypass cache and fresh-import ESM - Utils: this includes
utils,utils-validation,logger. They should always be distributed as dual-package because plugin authors are likely to import them as CJS. - Core: the biggest blocker is still the extensive use of
import-fresh. Migration to ESM means we can import both CJS and ESM plugin modules withawait import. However, because users only interact with the core through its own CLI, we don't have to care about others importing this. - Plugins: migration of plugins can only happen after migration of core (or at least solving
import-freshin the core), because they have to be imported as ESM.
Related issues/PRs
If an issue or PR is related to the ESM migration process, please link to this meta-issue and we will add it to the list below for tracking purposes.
- Support ESM config file #5379
- misc: migrate all packages to ESM-only #5816
- misc: convert all internal scripts to ESM #6286
- refactor: mark all functions that import external modules as async #6521
- refactor: convert CLI entry points to ESM; migrate create-docusaurus to ESM #6661
- refactor: ensure lodash is default-imported #6716
- refactor: import jest as global; unify import style of some modules #6898
- refactor(theme-common): mark package as ESM #6899
- feat(core): allow plugin lifecycles to return relative paths #6921
- feat(core): support docusaurus.config.cjs as default file name #7371
- fix(core): make generated files have unambiguous module types #7379
Activity
rafaelhorvat commentedon Feb 7, 2022
Yes !!!! +1 !
Finally I stumbled on this issue, I had updated
@mdx-js/reactand had errors and it took me a while to understand what happened...Error was something like
and
Josh-Cena commentedon Feb 8, 2022
@iPurpl3x Your problem is probably not because of ESM, because
@mdx-js/reactis used on client-side, where Webpack can take care of ESM syntax. Instead, it's because of the API changes in v2. MDX will be compiled to a JSX file containing a lineimport { mdx } from '@mdx-js/react';which doesn't exist in the latest MDX version.Josh-Cena commentedon Feb 19, 2022
I ran
yarn outdatedand below are all dependencies that are ESM and we can't upgrade:Outdated dependencies
Mostly Sindre Sorhus packages and MDX ones
sachaw commentedon Mar 9, 2022
This is just going to get worse with time, @Josh-Cena Thanks for the great work, hopefully we can get Docusaurus using ESM soon.
sambacha commentedon Mar 11, 2022
sindre is working on converting his packages to pure ESM, see https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
also, the latest
@docusaurus/migratepackage does not work, theindex.mjsis re-written asindex.jscausing it to fail. Renaming the file extension fixes itslorber commentedon Mar 11, 2022
What do you mean by "does not work"? How do you run it and how do you see it not working exactly? It seems to work for me
Josh-Cena commentedon Mar 11, 2022
@slorber It was a mistake made in the last publish😅 The file is called
bin/index.mjsbut in package.json it's referred to asbin/index.js. You probably need to run it outside our workspace. See #6897Josh-Cena commentedon Apr 9, 2022
TS 4.7 seems promising: https://devblogs.microsoft.com/typescript/announcing-typescript-4-7-beta/#ecmascript-module-support-in-node-js We should be able to investigate after that
slorber commentedon Apr 13, 2022
Yes, also great to have "exports" field support!
arobbins commentedon Apr 15, 2022
This might be a silly question, but If I'm creating a React library that I want to import into Docusaurus, what is my workaround at the moment? Do I just need to build the library as CJS and not ESM?
21 remaining items
Josh-Cena commentedon Nov 30, 2023
@Zamiell
type: commonjsis not equivalent for Webpack. Whentypeis absent, Webpack allows both ESM and CJS syntax in the same file; when the module type is unambiguous, it only allows one.amanaknows commentedon Aug 12, 2024
vtempest commentedon Dec 27, 2024
It is frustrating this is causing endless issues after 2 years. How hard it is just to use requre vs import.
Every time my docs open they have a great red error require ESM!!!!
How to avoid setup search when all the community search plugins require.resovle??? what to replace that with???
clicktodev commentedon Jan 24, 2025
Any plans to finish the migration in the near future?
slorber commentedon Jan 31, 2025
No immediate plan, and I'd prefer it to be done incrementally, one package after another.
If you want to help migrate one package, feel free to submit a PR.
shreedharbhat98 commentedon May 17, 2025
Hi @Josh-Cena 👋,
I’d like to tackle the migration to
@docusaurus/loggerfor this issue.Before I dive in, is there anything you’d like me to keep in mind?
Thanks for your guidance!
slorber commentedon May 19, 2025
Thanks for your help proposal @shreedharbhat98
The plan is to upgrade Docusaurus v4 to Node 22 soon, uncloking the synchronous
require(esmModule). Once we have upgraded, we can start converting some of our packages to ESM incrementally.I'd prefer we don't do anything before the upgrade because even though some packages can probably be converted to ESM today, in practice, the 2 ones we already converted caused some troubles already.
CMCDragonkai commentedon May 25, 2025
slorber commentedon May 27, 2025
CMCDragonkai commentedon May 28, 2025
slorber commentedon May 28, 2025
vtempest commentedon May 28, 2025
https://github.com/vtempest/grab-api/tree/master/docs-config
https://github.com/vtempest/grab-api/blob/master/docs-config/package.json
Docusaurus with OpenAPI and Typedoc and Lunr Search
This is the ultimate setup for Docusaurus to unlock Docs-Driven Development where your docs are autogenerated by your code so others can understand all functions clearly.
There are insane compatibility headaches especially with the paloaltonetworks openapi docusaurus versions please check up on these plugins so they are compatible