Skip to content

Commit c111ea7

Browse files
authored
fix(pnp): ensure URL is imported on Node.js < 20 (#6060)
**What's the problem this PR addresses?** Before nodejs/node#46904 using a custom global URL class wasn't supported by `fileURLToPath`. Closes #6030 Fixes #5915 **How did you fix it?** - Created a rollup plugin to ensure that the builtin URL class is always used on Node.js < v20. - Removed all imports of `URL` since it's a global and to avoid mixing custom and builtin URL class instances. **Checklist** - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). - [x] I have set the packages that need to be released for my changes to be effective. - [x] I will check that all automated PR checks pass before the PR gets reviewed.
1 parent eae38cb commit c111ea7

File tree

17 files changed

+105
-64
lines changed

17 files changed

+105
-64
lines changed

.eslintrc.js

+12
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,17 @@ module.exports = {
4444
message: `Use 'httpUtils' instead`,
4545
},
4646
],
47+
'no-restricted-imports': [
48+
`error`,
49+
{
50+
patterns: [
51+
{
52+
group: [`url`, `node:url`],
53+
importNames: [`URL`],
54+
message: `URL is a global, no need to import it`,
55+
},
56+
],
57+
},
58+
],
4759
},
4860
};

.pnp.cjs

+4-24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.pnp.loader.mjs

+3-23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.yarn/versions/ae9dd917.yml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
releases:
2+
"@yarnpkg/cli": patch
3+
"@yarnpkg/core": patch
4+
"@yarnpkg/fslib": patch
5+
"@yarnpkg/plugin-essentials": patch
6+
"@yarnpkg/plugin-npm": patch
7+
"@yarnpkg/pnp": patch
8+
9+
declined:
10+
- "@yarnpkg/plugin-compat"
11+
- "@yarnpkg/plugin-constraints"
12+
- "@yarnpkg/plugin-dlx"
13+
- "@yarnpkg/plugin-exec"
14+
- "@yarnpkg/plugin-file"
15+
- "@yarnpkg/plugin-git"
16+
- "@yarnpkg/plugin-github"
17+
- "@yarnpkg/plugin-http"
18+
- "@yarnpkg/plugin-init"
19+
- "@yarnpkg/plugin-interactive-tools"
20+
- "@yarnpkg/plugin-link"
21+
- "@yarnpkg/plugin-nm"
22+
- "@yarnpkg/plugin-npm-cli"
23+
- "@yarnpkg/plugin-pack"
24+
- "@yarnpkg/plugin-patch"
25+
- "@yarnpkg/plugin-pnp"
26+
- "@yarnpkg/plugin-pnpm"
27+
- "@yarnpkg/plugin-stage"
28+
- "@yarnpkg/plugin-typescript"
29+
- "@yarnpkg/plugin-version"
30+
- "@yarnpkg/plugin-workspace-tools"
31+
- vscode-zipfs
32+
- "@yarnpkg/builder"
33+
- "@yarnpkg/doctor"
34+
- "@yarnpkg/extensions"
35+
- "@yarnpkg/libzip"
36+
- "@yarnpkg/nm"
37+
- "@yarnpkg/pnpify"
38+
- "@yarnpkg/sdks"
39+
- "@yarnpkg/shell"

packages/acceptance-tests/pkg-tests-core/sources/utils/makeTemporaryEnv.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {npath} from '@yarnpkg/fslib';
22
import {delimiter} from 'path';
3-
import {URL} from 'url';
43

54
import * as exec from './exec';
65
import * as tests from './tests';

packages/plugin-essentials/sources/commands/plugin/import.ts

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {YarnVersion, formatUtils, httpUtils, structUtils, hashUtils}
55
import {PortablePath, npath, ppath, xfs} from '@yarnpkg/fslib';
66
import {Command, Option, Usage} from 'clipanion';
77
import semver from 'semver';
8-
import {URL} from 'url';
98
import {runInNewContext} from 'vm';
109

1110
import {getAvailablePlugins} from './list';

packages/plugin-npm/sources/NpmSemverFetcher.ts

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {Configuration, Fetcher, FetchOptions, MinimalFetchOptions} from '@yarnpk
22
import {structUtils, tgzUtils, semverUtils} from '@yarnpkg/core';
33
import {Locator, MessageName, ReportError} from '@yarnpkg/core';
44
import semver from 'semver';
5-
import {URL} from 'url';
65

76
import {PROTOCOL} from './constants';
87
import * as npmConfigUtils from './npmConfigUtils';

packages/plugin-npm/sources/npmHttpUtils.ts

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {Filename, PortablePath, ppath, xfs}
44
import {prompt} from 'enquirer';
55
import pick from 'lodash/pick';
66
import semver from 'semver';
7-
import {URL} from 'url';
87

98
import {Hooks} from './index';
109
import * as npmConfigUtils from './npmConfigUtils';

packages/plugin-npm/sources/npmPublishUtils.ts

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {PortablePath, xfs, npath} from '@yarnpkg/fslib';
44
import {packUtils} from '@yarnpkg/plugin-pack';
55
import {createHash} from 'crypto';
66
import ssri from 'ssri';
7-
import {URL} from 'url';
87

98
import {normalizeRegistry} from './npmConfigUtils';
109

packages/yarnpkg-core/sources/Plugin.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {PortablePath} from '@yarnpkg/fslib';
22
import {CommandClass} from 'clipanion';
33
import {Writable, Readable} from 'stream';
4-
import {URL} from 'url';
54

65
import {PluginConfiguration, Configuration, ConfigurationDefinitionMap, PackageExtensionData} from './Configuration';
76
import {Fetcher} from './Fetcher';

packages/yarnpkg-core/sources/httpUtils.ts

-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {Agent as HttpsAgent} from 'https';
44
import {Agent as HttpAgent, IncomingHttpHeaders} from 'http';
55
import micromatch from 'micromatch';
66
import tunnel, {ProxyOptions} from 'tunnel';
7-
import {URL} from 'url';
87

98
import {ConfigurationValueMap, Configuration} from './Configuration';
109
import {MessageName} from './MessageName';

packages/yarnpkg-fslib/sources/NodePathFS.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import buffer from 'buffer';
2-
import {URL, fileURLToPath} from 'url';
3-
import {inspect} from 'util';
1+
import buffer from 'buffer';
2+
import {fileURLToPath} from 'url';
3+
import {inspect} from 'util';
44

5-
import {FakeFS} from './FakeFS';
6-
import {ProxiedFS} from './ProxiedFS';
7-
import {npath, NativePath} from './path';
5+
import {FakeFS} from './FakeFS';
6+
import {ProxiedFS} from './ProxiedFS';
7+
import {npath, NativePath} from './path';
88

99
/**
1010
* Adds support for file URLs and Buffers to the wrapped `baseFs`, but *not* inside the typings.

packages/yarnpkg-pnp/rollup.config.js

+38
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import {brotliCompressSync} from 'zlib';
88

99
import pkg from './package.json';
1010

11+
/**
12+
* @returns {import('rollup').Plugin}
13+
*/
1114
function wrapOutput() {
1215
return {
1316
name: `wrap-output`,
@@ -25,6 +28,39 @@ function wrapOutput() {
2528
};
2629
}
2730

31+
/**
32+
* Before https://github.com/nodejs/node/pull/46904 using a custom global URL class
33+
* wasn't supported by `fileURLToPath` so this plugin ensures that for Node.js < 20
34+
* we always use the builtin URL class.
35+
* TODO: Remove this plugin when dropping support for Node.js < 20
36+
* @returns {import('rollup').Plugin}
37+
*/
38+
function importURL() {
39+
return {
40+
name: `import-url`,
41+
resolveId(id) {
42+
if (id === `virtual:url`) return `\0virtual:url`;
43+
44+
return undefined;
45+
},
46+
load(id) {
47+
if (id === `\0virtual:url`) {
48+
return `
49+
import { URL as nodeURL } from 'url';
50+
export const URL = Number(process.versions.node.split('.', 1)[0]) < 20 ? nodeURL : globalThis.URL;
51+
`;
52+
}
53+
return undefined;
54+
},
55+
transform(code, id) {
56+
if (code.includes(`new URL`) || code.includes(`instanceof URL`))
57+
return `import {URL} from 'virtual:url';\n${code}`;
58+
59+
return undefined;
60+
},
61+
};
62+
}
63+
2864
// eslint-disable-next-line arca/no-default-export
2965
export default defineConfig([
3066
{
@@ -53,6 +89,7 @@ export default defineConfig([
5389
},
5490
}),
5591
cjs({transformMixedEsModules: true, extensions: [`.js`, `.ts`]}),
92+
importURL(),
5693
wrapOutput(),
5794
],
5895
},
@@ -80,6 +117,7 @@ export default defineConfig([
80117
},
81118
}),
82119
cjs({requireReturnsDefault: `preferred`}),
120+
importURL(),
83121
wrapOutput(),
84122
],
85123
},

packages/yarnpkg-pnp/sources/esm-loader/built-loader.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/yarnpkg-pnp/sources/esm-loader/loaderUtils.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {NativePath} from '@yarnpkg/fslib';
22
import fs from 'fs';
33
import path from 'path';
4-
import {URL} from 'url';
54

65
import * as nodeUtils from '../loader/nodeUtils';
76

packages/yarnpkg-pnp/sources/hook.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/yarnpkg-pnp/sources/loader/applyPatch.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {FakeFS, PosixFS, npath, patchFs, PortablePath, NativePath, VirtualFS} from '@yarnpkg/fslib';
22
import fs from 'fs';
33
import {Module, isBuiltin} from 'module';
4-
import {URL, fileURLToPath} from 'url';
4+
import {fileURLToPath} from 'url';
55

66
import {PnpApi} from '../types';
77

0 commit comments

Comments
 (0)