-
-
Notifications
You must be signed in to change notification settings - Fork 132
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
feat: distribute the library for browser and node in ESM and CJS #313
Conversation
fb23783
to
083dcc2
Compare
@cdimitroulas, This is fantastic! While we're at it, folks, what is your opinion on #52? I think it would be great to be able to import interceptors directly from the root of the package like so: import { ClientRequestInterecptor } from '@mswjs/interceptors/ClientRequestInterceptor' This is possible via |
I think this should work everywhere that We may need to add fake folders/package.json for older versions of typescript and node to handle, but otherwise i think this is the path we should be on here. we should add a block like this to the package.json (once we configure both esm and cjs builds from tsup)
then we'll probably also need a folder for each of these (empty, just with a package.json) |
@mattcosta7 I've added the "exports" field to package.json, please take a look and maybe also test out the build locally to see if it matches your expectations.
I think this should work fine based on the current build output ( |
@mattcosta7 @kettanaito when you have a moment I would appreciate if we could finalize some of these discussions so I can finalize the code and mark the PR as ready for review |
package.json
Outdated
"import": "./lib/interceptors/ClientRequest/index.mjs", | ||
"types": "./lib/interceptors/ClientRequest/index.d.ts" | ||
}, | ||
"./lib/interceptors/fetch": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we drop ./lib/interceptors/
from the exports paths? So that you could import interceptors like so:
import X from '@mswjsw/interceptors/ClientRequest'
The more we work on this, the more I think it needs to be a separate change. I wouldn't want to ask you to restructure all of your work, so if you feel it's already under substantial progress, we can ship this together with the remix-run
change. If not, I think we're safer releasing the exports
changes separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've moved it to a separate PR. Let's tackle that once we get the new bundling merged since I'm not sure if it depends on this work or not.
I've opened a draft PR on my fork just to keep a record of the work: cdimitroulas#1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think these changes are dependent. Thanks for moving it away 👍
Hey, @cdimitroulas. I was having a couple of busy weeks at work. I've updated all the discussions, summarizing them below:
I wouldn't want to introduce empty placeholder directories like @mattcosta7 mentions but I think we need that for full compatibility. Do you know if there's a support map for |
27459f4
to
c1ab348
Compare
c1ab348
to
ffacd94
Compare
I'm not sure such a thing exists, I did find this helpful SO answer which is relevant: Not sure about bundler support but I imagine it's as you say and they all support it (at least on more recent versions) |
I've added Now, seems like all browser tests are failing because some Node code ends up in
@cdimitroulas, do you have some suspicion as to why this happens? |
No idea, I'll try to figure it out |
It's not all the browser tests that are failing, the It seems that a chunk that is split off by the code-splitting that is used by both the
This suggests that it's somehow related to |
It seems remix is configured to automatically deal with this stuff... https://remix.run/docs/en/v1/guides/constraints#server-code-pruning |
OOof hmm. I think since we're bundling this with a node target, we're probably only getting the node imports for remix-run/fetch? I wonder if we actually need a 'browser' build that's separate from the node build, which could potentially be a separate tsup config? the docs specificy - https://tsup.egoist.dev/#target-environment that target environment is node14 by default? do we need one that targets browsers to get the browser build of that library? (just guessing) |
I think the correct flag is esbuild's
|
I'm going to see if there's a way to exclude |
I was able to get the tests to pass, but I'm not sure how the build output should look like when building for node/browser separately. Here's a gist showing the changes I made as I don't feel like this is something I want to commit here: |
@mattcosta7 I reordered the keys in the exports as per your suggestion |
@mattcosta7, thanks for the review! And @cdimitroulas, thank you so much for addressing those points so quickly! I've rebased this branch, and solved the package.json conflict. Will continue with testing in MSW, let's see if the order of those fields solved the issue for the IIFE build. |
@kettanaito did the latest changes fix the problems you saw when testing in MSW? |
Hey, @cdimitroulas. I haven't tested that yet. Planning on returning to open source this/next week, need to arrange a few other things. The changes to Interceptors look good from what I can gather. The order sensitivity that @mattcosta7 mentioned was a great addition to this, now to see what exactly gets bundled in when tsup builds into IIFE. For some reason, I suspect it doesn't respect the |
The IIFE integration test passes in MSW with these changes to Interceptors linked:
🎉 |
There are, however, failing unit tests because somewhere in Interceptors we rely on
This happens because
"main": "./src/lib.js",
"module": "./src/lib.mjs",
"browser": "./src/lib.js",
"types": "./src/lib.d.ts",
"exports": {
".": {
"import": "./src/lib.mjs",
"require": "./src/lib.js"
}
}, // src/lib.mjs
// In node `export { TextEncoder }` throws:
// "Export 'TextEncoder' is not defined in module"
// To workaround we first define constants and then export with as.
const Encoder = TextEncoder
const Decoder = TextDecoder
export { Encoder as TextEncoder, Decoder as TextDecoder } Those globals won't be defined in Jest. They are defined in Node.js. This may have something to do with how we require/bundle // lib.js
"use strict"
exports.TextEncoder =
typeof TextEncoder !== "undefined" ? TextEncoder : require("util").TextEncoder
exports.TextDecoder =
typeof TextDecoder !== "undefined" ? TextDecoder : require("util").TextDecoder
|
Solution to
|
Issue: Jest doesn't understand the
|
Jumping from Jest v26 -> v27 doesn't seem too bad https://jestjs.io/blog/2021/05/25/jest-27#features-coming-with-breaking-changes Jumping from v27 -> v28 requires working through this guide though |
I wonder if Jest 27 brings in ESM support... The references I find mention Jest 28 if not 29. All and all, this looks like an endless loop of testing setup update that I've been postponing for forever. I don't mind doing it in MSW's repo, it just takes time. Everything does. Working on that mswjs/msw#1394 |
I wonder if we just used |
offhand, i'm not sure of node support, would we need to lose backward support? (ie, would we only support versions where unidici already exists? and referenceable on globalThis?) the less we need to bundle, the better I think - so if so, it sounds worth exploring |
Eventually, yes! That's the plan for this autumn when Node 16 goes to pass and we only have the versions of Node that ship global fetch throughout the board. Until then, we need to resort to some polyfill to support Node 16. |
Trying this with the Fetch API branch✅ Build
All the errors seem to have the same origin: they fail to resolve the "exports" to the interceptors. This is likely caused by Jest@26 missing support for "exports". But since we provide backward-compatibility with the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cdimitroulas @mattcosta7 thank you so much for all the work on this. I think the changes are good to go and I'm going to merge them once the CI passes. I still cannot fully test them in MSW due to the old Jest being used there but I've decided to slowly make our way towards that, as updating its test dependencies is a time-consuming endeavor and I don't wish to stall this change any longer.
Released: v0.21.0 🎉This has been released in v0.21.0! Make sure to always update to the latest version ( Predictable release automation by @ossjs/release. |
Is it just me, or does it appear that this change made the presets unreachable now? This sample code no longer works for importing the import { BatchInterceptor } from '@mswjs/interceptors'
import browserInterceptors from '@mswjs/interceptors/lib/presets/browser'
const interceptor = new BatchInterceptor({
name: 'my-interceptor',
interceptors: browserInterceptors,
})
interceptor.on('request', listener) |
Most probably yes @blaenk - we'll need to add these exports explicitly at the top-level somewhere I think and update the docs to reflect this. Do you have capacity to open a PR on that? |
Sorry, I don't have the bandwidth at the moment. For now I pinned to the previous release. |
re #283
Bundle the library, including
remix-run
and other polyfill libs, so that consumers of the lib can consume it without having to bundle/transpile it themselves.