Skip to content

Instantly share code, notes, and snippets.

@ry
Last active May 3, 2023 01:50
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ry/f410f6977a164477953e903bcf9d7d74 to your computer and use it in GitHub Desktop.
Save ry/f410f6977a164477953e903bcf9d7d74 to your computer and use it in GitHub Desktop.

The Duplicate Dependency Problem

Deno's module resolution and package management currently face a challenge in handling duplicate modules. To illustrate this issue, let's consider an example.

Suppose we are building a single-page application (SPA) with Deno and React, and we want to use the "react-spectrum" component library for React. We would begin by adding these dependencies to our deps.ts file:

export * as React from "https://esm.sh/react@17.0.1";
export * as ReactDOM from "https://esm.sh/react-dom@17.0.1";
export * as ReactSpectrum from "https://esm.sh/react-spectrum@1.2.3";

Running deno info produces the following output:

file:///Users/lucacasonato/projects/github.com/denoland/corp/test.ts (185B)
├─┬ https://esm.sh/react-dom@17.0.1 (192B)
│ ├─┬ https://cdn.esm.sh/v64/@types/react-dom@17.0.11/index.d.ts (4.02KB)
│ │ └─┬ https://cdn.esm.sh/v64/@types/react@17.0.38/index.d.ts (148.67KB)
│ │   ├── https://cdn.esm.sh/v64/@types/react@17.0.38/global.d.ts (7.01KB)
│ │   ├── https://cdn.esm.sh/v64/@types/prop-types@15.7.4/index.d.ts (3.58KB)
│ │   ├── https://cdn.esm.sh/v64/@types/scheduler@0.16.2/tracing.d.ts (4.03KB)
│ │   └── https://cdn.esm.sh/v64/csstype@3.0.10/index.d.ts (844.54KB)
│ ├─┬ https://cdn.esm.sh/v64/react-dom@17.0.1/deno/react-dom.js (118.43KB)
│ │ ├── https://cdn.esm.sh/v64/object-assign@4.1.1/deno/object-assign.js (1.7KB)
│ │ ├─┬ https://cdn.esm.sh/v64/react@17.0.1/deno/react.js (8.13KB)
│ │ │ └── https://cdn.esm.sh/v64/object-assign@4.1.1/deno/object-assign.js *
│ │ └── https://cdn.esm.sh/v64/scheduler@0.20.2/deno/scheduler.js (6.31KB)
├─┬ https://esm.sh/react-spectrum@1.2.3 (214B)
│ ├─┬ https://cdn.esm.sh/v64/react-spectrum@1.2.3/dist/Spectrum.d.ts (1.68KB)
│ │ └── https://cdn.esm.sh/v64/@types/react@17.0.38/index.d.ts *
│ ├─┬ https://cdn.esm.sh/v64/react-spectrum@1.2.3/deno/react-spectrum.js (2.96KB)
│ │ └─┬ https://cdn.esm.sh/v64/react@17.0.2/deno/react.js (8.13KB)
│ │   └── https://cdn.esm.sh/v64/object-assign@4.1.1/deno/object-assign.js *
└─┬ https://esm.sh/react@17.0.1 (172B)
  ├── https://cdn.esm.sh/v64/@types/react@17.0.38/index.d.ts *
  ├── https://cdn.esm.sh/v64/react@17.0.1/deno/react.js *

Notice that two different versions of React appear in the output: react@17.0.1 and react@17.0.2. This incompatibility can cause our code to malfunction as the two versions of React are not compatible.

In this case, resolving the issue is relatively simple. We need to update the direct React dependency in our deps.ts file to match the version used by the react-spectrum package:

- export * as React from "https://esm.sh/react@17.0.1";
- export * as ReactDOM from "https://esm.sh/react-dom@17.0.1";
+ export * as React from "https://esm.sh/react@17.0.2";
+ export * as ReactDOM from "https://esm.sh/react-dom@17.0.2";
export * as ReactSpectrum from "https://esm.sh/react-spectrum@1.2.3";

However, in situations where multiple dependencies rely on different versions of React, simply changing the imported version of React is insufficient.

Fortunately, ESM.sh offers a solution for locking the version of a transitive dependency using a query parameter:

export * as React from "https://esm.sh/react@17.0.1";
export * as ReactDOM from "https://esm.sh/react-dom@17.0.1";
- export * as ReactSpectrum from "https://esm.sh/react-spectrum@1.2.3";
+ export * as ReactSpectrum from "https://esm.sh/react-spectrum@1.2.3?deps=react@17.0.1";

However, this manual approach becomes increasingly difficult when applied to each module in a complex project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment