Msw: TypeScript requires `dom` library even for `node` only projects.

Created on 30 Sep 2020  路  5Comments  路  Source: mswjs/msw

Environment

| Name | Version |
| ---- | ------- |
| msw | 0.21.2 |
| node | 12.16.3 |
| OS | macOS catalina 10.15.7 (19H2) |

Problem

The msw TypeScript compilation requires dom library even for node only projects.

tsconfig.json

  {
    "compilerOptions": {
      "module": "commonjs",
      "target": "es6",
      "outDir": "out",
-     "lib": ["es6", "dom"],
+     "lib": ["es6"],
      "sourceMap": true,
      "strict": true,
    },
    "include": ["src/**/*"]
  }

Current behavior

When the dom library is missing, TS can't resolve types like Request, URL, and ServiceWorker.

node_modules/msw/lib/types/utils/handlers/requestHandler.d.ts:9:82 - error TS2304: Cannot find name 'RequestInit'.

9     fetch: (input: string | MockedRequest<DefaultRequestBodyType>, requestInit?: RequestInit) => any;
                                                                                   ~~~~~~~~~~~

node_modules/msw/lib/types/utils/handlers/requestHandler.d.ts:13:10 - error TS2304: Cannot find name 'URL'.

13     url: URL;
            ~~~

node_modules/msw/lib/types/utils/handlers/requestHandler.d.ts:14:13 - error TS2304: Cannot find name 'Request'.

14     method: Request['method'];
               ~~~~~~~

Expected behavior

TypeScript should compile msw without dom library when used only for a node project.

Screenshots

Example project: https://gitlab.com/viktomas/showcase-msw-bug

bug help wanted discussion node typescript

Most helpful comment

@timdeschryver, I've tried that but that quickly leads to re-annotating half of the DOM. There are a ton of things missing ( fetch, XMLHttpRequest) or existing in a incompatible form (Event) between the DOM and NodeJS.

I'm thinking if we can output an entirely separate build for NodeJS that would derive from the same source, guaranteeing its integrity, but would have its own bundling and types. That way we could annotate the same utilities differently for NodeJS. That still doesn't solve the issue that those utilities quite heavily rely on certain DOM types.

And I've completely forgot about the entry points. Even if we configure it the way described above the users won't still see the difference, as they import utilities from msw and not msw/node. At this point I'm completely lost.

All 5 comments

Hi, @viktomas. Thanks for reporting this.

As MSW compiles into a package potentially used for both browser and Node it's impossible to strip off certain types at the build time of the library. The end user controls where the msw package is being used. The /node entry point contains only certain APIs. It's expected you reuse the code between browser and Node, however, I understand the type difference it implies.

What implications do you see in adding the "dom" to your tsconfig.json? How would you suggest we solve this issue?

@kettanaito Thanks for your reply.

The app that I'm testing using msw runs only in node and never in browser (https://gitlab.com/gitlab-org/gitlab-vscode-extension). And so adding the dom to libraries fixes this type issue but allows the use of types and interfaces that are not supported by node.

I don't have a simple solution in mind except for creating separate packages for node and browser apps.

Unfortunately, bundling a separate Node package is not an option. That would contradict our API design: you should be able to reuse what msw exports (i.e. request handlers). It would be a bad decision to force people to import request handlers (rest, graphql, etc.) from a different package, cutting off an option to import the same module you use for in-browser mocking.

If we duplicate the entire API under msw/node, that would produce a confusing API by itself:

import { rest } from 'msw'
import { rest, setupServer } from 'msw/node'

I'm not even fond of the msw/node directory, but it indeed is designed to run in a different environment, so we've settled with that choice.

As of now I see two contradictory factors:

  1. API design to reuse rest, graphql and friends from the msw package, that is compiled with type definitions from the dom library.
  2. Dependency on the dom definitions in a purely NodeJS projects.

We need a TypeScript wizardry to resolve this, as with my knowledge of TS I don't see how to combine these two at the moment. I'm open to suggestions.

I wonder if we could define these types in MSW, similar to how node-fetch does it. This isn't ideal, since we'll have to keep those types up-to-date, but on the other hand... I think these are stable.

@timdeschryver, I've tried that but that quickly leads to re-annotating half of the DOM. There are a ton of things missing ( fetch, XMLHttpRequest) or existing in a incompatible form (Event) between the DOM and NodeJS.

I'm thinking if we can output an entirely separate build for NodeJS that would derive from the same source, guaranteeing its integrity, but would have its own bundling and types. That way we could annotate the same utilities differently for NodeJS. That still doesn't solve the issue that those utilities quite heavily rely on certain DOM types.

And I've completely forgot about the entry points. Even if we configure it the way described above the users won't still see the difference, as they import utilities from msw and not msw/node. At this point I'm completely lost.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

luistak picture luistak  路  3Comments

otaciliolacerda picture otaciliolacerda  路  3Comments

lukesmurray picture lukesmurray  路  3Comments

slowselfip picture slowselfip  路  3Comments

danielstreit picture danielstreit  路  3Comments