Hacker News new | ask | show | jobs
by mattwad 1121 days ago
If you have one build pipeline, I would recommend it. But it's still been a nightmare for me. Key issues are some packages are 5+ yrs old and not maintained, and we have a very complicated setup, one common repo shared by a Next.js app and custom Koa app. Every tool you work with, like Jest, needs its own workarounds.

I have noticed more and more libs are exporting ESM, but lord knows when we can stop adding special compiler rules.

2 comments

Kinda niche, I wrote Bazel rules (https://github.com/rivethealth/rules_javascript), and with a build setting `--//javascript:module`.

Jest tests automatically use the CJS version. Webpack builds use the ESM version. (And all my stuff is in TypeScript, so it needs a build step anyway.)

Jest on jsdom is just terrible though. It's a fake browser environment that acts like no browser that your users use, so the tests are far less meaningful that if you used a real browser.
If it matters that much that your tests are in a real browser environment what you are writing are likely integration tests, rather than unit tests. jsdom is great for unit tests that need to test a bare minimum of side effects.

I know the distinction between unit tests and integration tests doesn't matter to some, but I still see a huge usefulness in distinguishing because unit tests should run in the "inner loop" every time a developer is touching code (so must be fast to avoid sapping productivity) and integration tests can be delayed until the "outer loop" (CI processes and UAT processes) so are allowed to be slower. Booting up a "real" browser is definitely on my slow things list and not something I think belongs in unit tests.

Well, for browser tests I use Selenium.

(Tho I still use jest as the test runner.)

dependencies that we need which are still CJS-only are what kill our ability to switch completely to ESM :(
You can use Parcel or esbuild just on that CJS dependency (rather than as a top-level bundler for your whole project), and then cache the ESM result somewhere. If the package is that old and that unmaintained you can just about cache those ESM builds indefinitely. (That's what Vite kind of does under the hood. That's what snowpack used to do.)

I think npm should probably support doing that at install time.

ESM importing CJS works in Node, mostly, now, but it does have quite a bit of runtime overhead and prebaking it would be good. Especially because it is unlikely to ever see a CJS loader in the browser (and that would be awful if it did exist).

if you use a package manager like `pnpm` you can use the `.pnpmfile.cjs`[0] to intercept packages and add `"type": "commonjs"` to the package.json.

This tells node that it needs to load it as a CommonJS package and should work fine with ESM.

There's also creating a require function from `node:module` package[1]

[0]: https://pnpm.io/pnpmfile

[1]: https://nodejs.org/dist/latest-v18.x/docs/api/module.html#mo...