Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2862602

Browse files
committedSep 27, 2024·
fix: make sources zip work with Yarn Berry
1 parent 9289f19 commit 2862602

File tree

10 files changed

+185
-6
lines changed

10 files changed

+185
-6
lines changed
 
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/.yarn/** linguist-vendored
2+
/.yarn/releases/* binary
3+
/.yarn/plugins/**/* binary
4+
/.pnp.* binary linguist-generated
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.yarn/*
2+
!.yarn/patches
3+
!.yarn/plugins
4+
!.yarn/releases
5+
!.yarn/sdks
6+
!.yarn/versions
7+
8+
# Swap the comments on the following lines if you wish to use zero-installs
9+
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
10+
# Documentation here: https://yarnpkg.com/features/caching#zero-installs
11+
12+
#!.yarn/cache
13+
.pnp.*
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "yarn-berry-ls",
3+
"packageManager": "yarn@4.4.0",
4+
"dependencies": {
5+
"mime-types": "2.1.35"
6+
},
7+
"devDependencies": {
8+
"flatten": "1.0.3"
9+
}
10+
}

‎packages/wxt/src/core/package-managers/__tests__/fixtures/simple-yarn-berry-project/yarn.lock

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎packages/wxt/src/core/package-managers/__tests__/fixtures/simple-yarn-project/package.json renamed to ‎packages/wxt/src/core/package-managers/__tests__/fixtures/simple-yarn-classic-project/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "yarn-ls",
2+
"name": "yarn-classic-ls",
33
"packageManager": "yarn@1.22.22",
44
"dependencies": {
55
"mime-types": "2.1.35"

‎packages/wxt/src/core/package-managers/__tests__/yarn.test.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import path from 'node:path';
33
import { yarn } from '../yarn';
44

55
describe('Yarn Package Management Utils', () => {
6-
describe('listDependencies', () => {
7-
const cwd = path.resolve(__dirname, 'fixtures/simple-yarn-project');
6+
describe('listDependencies (Yarn 1 / Classic)', () => {
7+
const cwd = path.resolve(__dirname, 'fixtures/simple-yarn-classic-project');
88

99
it('should list direct dependencies', async () => {
1010
const actual = await yarn.listDependencies({ cwd });
@@ -24,4 +24,25 @@ describe('Yarn Package Management Utils', () => {
2424
]);
2525
});
2626
});
27+
28+
describe('listDependencies (Yarn 2+ / Berry)', () => {
29+
const cwd = path.resolve(__dirname, 'fixtures/simple-yarn-berry-project');
30+
31+
it('should list direct dependencies', async () => {
32+
const actual = await yarn.listDependencies({ cwd });
33+
expect(actual).toEqual([
34+
{ name: 'mime-types', version: 'npm:2.1.35' },
35+
{ name: 'flatten', version: 'npm:1.0.3' },
36+
]);
37+
});
38+
39+
it('should list all dependencies', async () => {
40+
const actual = await yarn.listDependencies({ cwd, all: true });
41+
expect(actual).toEqual([
42+
{ name: 'mime-types', version: 'npm:2.1.35' },
43+
{ name: 'mime-db', version: 'npm:1.52.0' },
44+
{ name: 'flatten', version: 'npm:1.0.3' },
45+
]);
46+
});
47+
});
2748
});

‎packages/wxt/src/core/package-managers/yarn.ts

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import { dirname, resolve } from "node:path";
2+
import { fileURLToPath } from "node:url";
3+
import { pathExists } from "fs-extra";
14
import { Dependency } from '../../types';
25
import { WxtPackageManagerImpl } from './types';
36
import { dedupeDependencies, npm } from './npm';
47

5-
export const yarn: WxtPackageManagerImpl = {
8+
// Yarn 1 (Classic) package manager implementation
9+
export const yarnClassic: WxtPackageManagerImpl = {
610
overridesKey: 'resolutions',
711
downloadDependency(...args) {
812
return npm.downloadDependency(...args);
@@ -39,6 +43,89 @@ export const yarn: WxtPackageManagerImpl = {
3943
},
4044
};
4145

46+
// Returns the absolute path of the root directory of a Yarn Berry mono-repository
47+
const getMonorepoRootDir = async () => {
48+
let monorepoRootDir = dirname(fileURLToPath(import.meta.url));
49+
while (!(await pathExists(resolve(monorepoRootDir, "yarn.lock"))) && monorepoRootDir !== "/") {
50+
monorepoRootDir = dirname(monorepoRootDir);
51+
}
52+
return monorepoRootDir;
53+
}
54+
55+
// yarn 2+ (Berry) package manager implementation
56+
export const yarnBerry: WxtPackageManagerImpl = {
57+
overridesKey: 'resolutions',
58+
async downloadDependency(id: string, downloadDir: string) {
59+
const { execa } = await import('execa');
60+
if (!id.includes("@workspace:")) {
61+
return npm.downloadDependency(id.replace('@npm:', '@'), downloadDir);
62+
}
63+
const monorepoRootDir = await getMonorepoRootDir();
64+
const [dependencyName, dependencyDirRelativeToMonorepoRootDir] = id.split("@workspace:");
65+
const dependencyDir = resolve(monorepoRootDir, dependencyDirRelativeToMonorepoRootDir);
66+
const packedFilename = `${dependencyName.replace("@", "").replace("/", "-")}.tgz`;
67+
const archivePath = resolve(downloadDir, packedFilename);
68+
await execa('yarn', ['pack', '--out', archivePath], {
69+
cwd: dependencyDir
70+
});
71+
return archivePath;
72+
},
73+
async listDependencies(options) {
74+
const monorepoRootDir = await getMonorepoRootDir();
75+
let currentWorkspace = '.';
76+
if (monorepoRootDir !== '/' && options?.cwd?.startsWith(monorepoRootDir)) {
77+
currentWorkspace = options.cwd.substring(monorepoRootDir.length);
78+
}
79+
80+
const args = ['info', '--name-only', '--json'];
81+
if (options?.all) {
82+
args.push('--all');
83+
args.push("--recursive");
84+
}
85+
const { execa } = await import('execa');
86+
const res = await execa('yarn', args, { cwd: options?.cwd });
87+
const lines = res.stdout.split('\n').map((line) => JSON.parse(line));
88+
89+
const dependencies: Dependency[] = [];
90+
91+
while (lines.length > 0) {
92+
const line = lines.pop();
93+
// example output formats
94+
// - "foo@npm:0.0.1"
95+
// - "@acme/foo@npm:1.2.3"
96+
// - "@acme/bar@workspace:packages/bar"
97+
// - "typescript@patch:typescript@npm%3A5.6.2#optional!builtin<compat/typescript>::version=5.6.2&hash=8c6c40"
98+
const name = line.substring(0, line.substring(1).indexOf('@') + 1);
99+
const version = line.substring(name.length + 1);
100+
let isCurrentPackage = false;
101+
if (version.startsWith('workspace:')) {
102+
isCurrentPackage = version.substring('workspace:'.length) === currentWorkspace;
103+
}
104+
if (name === '' || version === '' || isCurrentPackage) continue;
105+
dependencies.push({ name, version });
106+
}
107+
108+
return dedupeDependencies(dependencies);
109+
},
110+
};
111+
112+
// Yarn 1 (Classic) and Yarn 2+ (Berry) have different CLI and output formats
113+
export const yarn: WxtPackageManagerImpl = {
114+
overridesKey: 'resolutions',
115+
async downloadDependency(id: string, downloadDir: string) {
116+
const { execa } = await import('execa');
117+
const execRes = await execa('yarn', ['--version']);
118+
const _yarn = execRes.stdout.startsWith('1.') ? yarnClassic : yarnBerry;
119+
return _yarn.downloadDependency(id, downloadDir);
120+
},
121+
async listDependencies(options) {
122+
const { execa } = await import('execa');
123+
const execRes = await execa('yarn', ['--version'], { cwd: options?.cwd });
124+
const _yarn = execRes.stdout.startsWith('1.') ? yarnClassic : yarnBerry;
125+
return _yarn.listDependencies(options);
126+
}
127+
};
128+
42129
type JsonLine =
43130
| { type: unknown; data: unknown }
44131
| { type: 'tree'; data: JsonLineTree };

‎packages/wxt/src/core/zip.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,12 @@ async function downloadPrivatePackages() {
177177
wxt.config.zip.downloadedPackagesDir,
178178
);
179179
files.push(tgzPath);
180-
overrides[id] = tgzPath;
180+
// removes protocols that may cause issues with Yarn Berry
181+
// FIXME: should we replace the version of the dependency listed in the
182+
// dependencies / devDependencies fields of the package.json file with a
183+
// link to the tgz file instead of using altered overrides entries?
184+
const overrideKey = id.replace(/@(npm|workspace):.*$/, '');
185+
overrides[overrideKey] = tgzPath;
181186
}
182187
}
183188

‎packages/wxt/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1438,7 +1438,8 @@ export interface WxtPackageManager extends Nypm.PackageManager {
14381438
/**
14391439
* Run `npm ls`, `pnpm ls`, or `bun pm ls`, or `yarn list` and return the results.
14401440
*
1441-
* WARNING: Yarn always returns all dependencies
1441+
* WARNING: Yarn Classic always returns all dependencies
1442+
* WARNING: Yarn Berry prefixes dependency versions with a protocol name (such as `npm:` or `workspace:`)
14421443
*/
14431444
listDependencies: (options?: {
14441445
cwd?: string;

0 commit comments

Comments
 (0)
Please sign in to comment.