-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discuss: Should Highlight.js version 11 npm release be ESM only? #2600
Comments
Landed landed vs still experimental? Do you have a link/announcement? Is there a graph or stats anywhere of who is still using Node v10 (it's popularity still)? Is it considered "very old"? We have very limited time - I'd really rather not maintain both CJS and ESM if we can avoid it. I'd much rather say drop CJS with the next major release and switch completely to ESM if it works for the majority, etc. @egor-rogov @allejo Thoughts? Also worth noting the internal libs are already ESM, but our npm packages (built for Node primarily) are packaged as CJS. If you started from just the GitHub repo source you'd already have ESM all the way down. |
@aduh95 Do you know if the built-in support can import from JSON files? We currently do this (via rollup) to pull in the version from the package.json file, though I suppose we could change that if we had to. |
https://nodejs.org/en/blog/release/v12.17.0/ It used to be behind a flag and a warning, it's still officially experimental though. If you want to ditch CJS, it might be wiser to wait for the feature to be officially stable (the goal of Node.js is to have it stable by the time v14 reaches LTS in October). Node.js v10 is in LTS maintenance mode until April 2021, so we can expect people still using it until its end of life. I don't think there are any official download stats for Node.js versions 😕 What is the timeframe for Highlight.js 11.x?
That's a very good point, although it's worth noting that the source doesn't specify file extension in the imports (E.G.:
Importing JSON using ESM syntax is still experimental on current Node.js version. But there are workaround for this (example). |
Early 2021 prolly. I don't like to push breaking releases too often... so my idea is a roughly yearly cycle... but I'm also not in a rush if we don't NEED to break anything - 10 could live on longer.
Yeah, I'd say it's not a super high priority for us while it's still experimental.
If Rollup doesn't mind I'd have no issue with adding |
Is anyone using
Perhaps I should have looked at this a bit more carefully. Is this really ALL you were looking for here? If we shipped those 2-3 build assets (or variants of) with ONLY this change... would that resolve this? I was imagining publishing all the "raw" source files as their own or alternative NPM package... which is a whole other level of complexity. Just shipping ESM "entry points" for core and index sounds perhaps a lot more doable. |
Yes, that would be totally fine! I think Rollup can handle that, right? highlight.js/tools/build_config.js Line 10 in b1bce6e
Haven't tried it, but I think you can replace it with: output: [
{ format: "cjs", strict: false },
{ format: "esm" },
] Would you interested in a PR? |
Actually that will mess with all the individual languages we require also, no? Those would then also need to also be modules, yes? That's what I was fearful of... I'm not sure we want to ship +180 additional/duplicate JS files just because of ESM... is that the only way to do this - or am I thinking about it wrong? I wonder if there are any other large modular libraries and how they are dealing with this problem? Building a "monolith" (like we do for the browser) would solve some of the issues [for some people] but others really prefer to load just core and the languages they need one at a time, and it seems to allow that we'd still need 100s of separate modules. |
I doubt it. We have a pretty custom build process. It'd probably be easier to build a list of the individual CJS files and then feed them thru a simple text transform... then spit out new files beside them. But we'd also preferably want our CI/test suite to test these new "build products" and I'm not sure that's even even possible with Mocha. Do you know? Last time I looked at using modules with it things seemed pretty rocky... but perhaps that has improved? |
@aduh95 If your actual problem is truly just "get started fast" why not just use the browser build and change it's single CJS export to an ESM export instead? |
Thanks for the detailed explanation, I think I got your point. This discussion would be more productive in a few months when Node.js ESM support has stabilised. Maybe we can wait and see if the situation evolves on Node.js side, and come back to the "drop CJS with the next major release and switch completely to ESM" mindset when it makes sense?
Yes Mocha is able to interact with ES modules, you just have
I want the best of both world: get started fast and cherry-pick the languages I'm actually highlighting. I know I'm bad ^^ |
So be it. |
How are things looking now? I'm curious if other packages (with lots of individual files) are shipping BOTH ESM and CJS versions via npm and if so how they are doing it... I'm thinking of rolling v11 perhaps in April/May and seems a good time to revisit this... |
Hey! Yes, there are a few packages that have started doing that, on the top of my head I can think of Rollup and Preact, I know there are more. I'm not sure they qualify for the lot of individual files part though. On Node.js side, ES modules support is no longer experimental (nodejs/node#35781) and is considered stable. Node.js v10.x is planned to go end-of-life at the end of April 2021, which would mean all maintained Node.js release lines (v12.x, v14.x, v16.x) would have support for ES modules. IMHO, considering the time frame, I think we should go all-in with ESM and ditch CJS in the npm package:
I can work on a PR to start experimenting with that if that sounds like a plan to you. |
Does this also then work perfectly in v12? Did the ESM support become non-experimental in the latest releases of v12 or do you still need to trigger a special runtime flag?
You mean vs using our pre-built and minified distributable assets? (which we'll still create for users who need/prefer them) I'm all for giving people choices, but are there big advantages using ESM if the library isn't built with that in mind? Someone crazy enough to import everything would be loading/fetching over 180 distinct JS files. It's possible I don't understand the full ESM in-browser story yet since I've always bundled on every web app I've worked on.
I'm not super worried about the size, thought it is a consideration. More worried about maintaining dual build, and CI pipelines... but the end result is the same: A single final product be nicer than two. :)
Is there a reason the npm build process couldn't mostly do a |
Yes, v12.20.0 has the same implementation as current v15.x (with the exception of top-level await, but that's because it's using an older version of V8), no flag is needed, and the experimental warning has been removed.
In some projects of mine I was using highlight.js to highlight one specific language, so that would be only two files to fetch, correct? Otherwise, I agree you should use a bundler or the pre-built file if you want to include everything.
Yes probably, since a010c15 that should be possible. There some documentation and update to make to |
Looks like the modules themselves almost work as-is (except for our importing of
Well our raw source tree is broken up into separate files for organization. Just the library + one languages is maybe 7-8 different small files. Perhaps (for API privacy concerns as well) we still need to build cooked ESM assets for:
Thoughts? |
On Node.js, you can do that: import { readFile } from 'fs/promises';
const { version } = await readFile(new URL('../package.json', import.meta.url)).then(JSON.parse);
console.log(version); // Outputs '10.6.0'. Doing so would not work on the browser, so that's probably not the way to go for the distributed package… Given that plus the fact that the source files are broken up into several files, it seems the way forward would be to update the |
FYI it's expected to stop being necessary soon: nodejs/node#37141. |
@aduh95 If you wanted to help further you could take a look at that PR and provide any thoughts. Also if you wanted to muck around with getting the test suite fully operational again that'd be awesome. Best case I'd guess it's changing a bunch of requires to imports, but I'm not really sure? Looks pretty clean so far. |
I guess you're right, if we keep the same file structure for CJS module and add |
And what would the downsides of such an approach be? |
I don't think there is any downside, in the OP I was suggesting adding ESM as a non-breaking change using conditional exports so it seems we've just circled back :) |
Sometimes we take the long way around. :-) I'll take another swing at this in a bit with this goal in mind. |
Can you have a look at #3007 now? |
@joshgoebel FYI: I’ve started changing the modules that I maintain to ESM-only. Starting from the low-level projects, and reaching lowlight somewhere next month probably. Let me know if I can advise on something |
@joshgoebel I tried that with micromark in November and users ran into a ton of problems with tools, such as webpack 4 (still used in CRA and Next): remarkjs/react-markdown#518. I’m not optimistic that you can push dual esm/cjs in a minor release. |
How did you try it though? I was planning to leave the core library/package.json still CJS ( Looks like you said Webpack fixed their issues in version 5? And we're gearing up for v11, so it doesn't have to be a minor release, I just thought if we could divorce it from v11 that'd be one less thing, but if it can't be, that's fine also. |
micromark/micromark#36 is the main chunk of the work.
I had the same idea. It turned out to be incorrect. Bundlers and other tools have been running faux-ESM for so long, that they never bothered to make them spec compliant / work.
Agreed.
Yep. But lots of users are still on broken tools. |
So if someone was literally using our canonical requires:
Would those still break even assuming |
I believe that’s indeed the issue. Webpack 4 will “magically” start using ESM in your above example, even thought it’s clearly CJS expecting CJS, and it doesn’t understand that actual ESM 🤷♂️ (edit: to clarify, something in between your 2 cases) |
How can you still support JS requires with file extensions using conditional exports subpath patterns?
It always wants to re-add the extension, even if it's already there. And I think using/requiring extensions is a very common pattern, there is even a linter setting to require them. |
That depends on the |
I think that would be a breaking change indeed. We could hack our way around it by adding a function emitWarning() {
if (!emitWarning.warned) {
emitWarning.warned = true;
process.emitWarning(
'Using file extension in specifier is deprecated, use "highlight.js/lib/languages/swift" instead'
);
}
}
emitWarning();
exports = require('./swift.js'); |
I've read them. They don't seem to address this that I see other than acknowledging the problem at one point. I was posting it here hoping someone knows the solution. Optimally there would be a way to make it "just work" extension or not - without having to have a manual list of 180 languages in exports. |
Ha, indeed. Before we went there though I think I'd just bloat the package.json with 180 entries for every language and give up on |
I don't think that fit your use-case, but I thought I should mention it anyway: you could also change "exports": {
"./lib/languages/*": { "require": ["./lib/languages/*.js", "./lib/languages/*"], ... }
}, That would still fail for Node.js (see nodejs/node#37928 (comment)), but would work for some bundlers – I know that works in Webpack 5, not sure for others. Depending on how breaking you are wanting to go with this, it may be an acceptable compromise. |
What does having require be an array do??? I haven't seen that.
I wonder if we shouldn't just forget |
See https://webpack.js.org/guides/package-exports/#alternatives:
I'll take that over the current CJS-only package, but… There are breaking changes in v11 anyway, and AFAIK Again, it depends what vision you have for |
Ok, but what does Node do with such constructs?
Yes, but if I got this to a "very happy with" point I was considering perhaps pushing a minor release of 10 that's dual ESM/CJS just to get a heads up on packaging issues.
True, but that doesn't mean it isn't done - and I'd prefer not to break it if avoidable. Our very own eslint config requires extensions for imports. Though I'm aware this is different than requires.
For v11, yes. For a slipstream v10 release, less so.
We're breaking enough other things, so it'd be nice if the module thing "just worked". :-) What is the downside to just listing all 180 languages (with |
It would only use the first one basically, and ignore what comes after; in our case, Node.js would still throw a
Oh I see, in that case I agree, it's probably safer to avoid
The upside of having |
Ah, now that indeed make sense. So something like 1d20d88. |
Tagging to autoclose. Next release will NOT be ESM only. We'll include ESM in an |
@aduh95 Merged (with conditional exports for now). Should be released when |
Is your request related to a specific problem you're having?
I'm always frustrated when starting a project, I don't want to set up a whole build chain and just want to get started:
And I get an error
Error: 'default' is not exported by /node_modules/highlight.js/lib/core.js
...The solution you'd prefer / feature you'd like to see added...
I'd much rather prefer having standard ES6 modules in the npm package, and being able to use them as advertised in the
README.md
.Any alternative solutions you considered...
s/module.exports =/export default/
on thenode_modules/highlight.js/
files, but that's not very convenient.Additional context...
Support for ESM has landed in Node.js current and LTS lines recently, with features such as Conditional Exports (useful in case we want to keep the CJS version around, still required for Node.js v10 support).
Having ESM files would also make the library compatible with Deno for free, which would be nice.
The text was updated successfully, but these errors were encountered: