Skip to content

Commit 8038445

Browse files
committed
fix: Correctly zip linked packages
1 parent 4f772fc commit 8038445

File tree

5 files changed

+104
-4
lines changed

5 files changed

+104
-4
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"name": "local-package",
3+
"version": "0.0.0"
4+
}

packages/wxt/e2e/tests/zip.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,76 @@ describe('Zipping', () => {
7474
`);
7575
});
7676

77+
it('should download local packages and produce a valid build when zipping sources', async () => {
78+
const project = new TestProject({
79+
name: 'test',
80+
version: '1.0.0',
81+
dependencies: {
82+
'@local/file': `file:../../tests/__fixtures__/local-package`,
83+
'@local/link': `link:../../tests/__fixtures__/local-package`,
84+
},
85+
});
86+
project.addFile(
87+
'entrypoints/background.ts',
88+
'export default defineBackground(() => {});',
89+
);
90+
const unzipDir = project.resolvePath('.output/test-1.0.0-sources');
91+
const sourcesZip = project.resolvePath('.output/test-1.0.0-sources.zip');
92+
93+
await project.zip({
94+
browser: 'firefox',
95+
zip: { downloadPackages: ['@local/file', '@local/link'] },
96+
});
97+
expect(await project.fileExists('.output/')).toBe(true);
98+
99+
await extract(sourcesZip, { dir: unzipDir });
100+
// Update package json wxt path
101+
const packageJsonPath = project.resolvePath(unzipDir, 'package.json');
102+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
103+
packageJson.dependencies.wxt = '../../../../..';
104+
await writeFile(
105+
packageJsonPath,
106+
JSON.stringify(packageJson, null, 2),
107+
'utf-8',
108+
);
109+
110+
// Build zipped extension
111+
await expect(
112+
spawn('pnpm', ['i', '--ignore-workspace', '--frozen-lockfile', 'false'], {
113+
cwd: unzipDir,
114+
}),
115+
).resolves.not.toHaveProperty('exitCode');
116+
await expect(
117+
spawn('pnpm', ['wxt', 'build', '-b', 'firefox'], {
118+
cwd: unzipDir,
119+
}),
120+
).resolves.not.toHaveProperty('exitCode');
121+
122+
await expect(project.fileExists(unzipDir, '.output')).resolves.toBe(true);
123+
expect(
124+
await project.serializeFile(
125+
project.resolvePath(unzipDir, 'package.json'),
126+
),
127+
).toMatchInlineSnapshot(`
128+
".output/test-1.0.0-sources/package.json
129+
----------------------------------------
130+
{
131+
"name": "test",
132+
"description": "Example description",
133+
"version": "1.0.0",
134+
"dependencies": {
135+
"wxt": "../../../../..",
136+
"@local/file": "file:../../tests/__fixtures__/local-package",
137+
"@local/link": "link:../../tests/__fixtures__/local-package"
138+
},
139+
"resolutions": {
140+
"@local/file@file:../../tests/__fixtures__/local-package": "file://./.wxt/local_modules/local-package-0.0.0.tgz",
141+
"@local/link@link:../../tests/__fixtures__/local-package": "file://./.wxt/local_modules/local-package-0.0.0.tgz"
142+
}
143+
}"
144+
`);
145+
});
146+
77147
it('should correctly apply template variables for zip file names based on provided config', async () => {
78148
const project = new TestProject({
79149
name: 'test',

packages/wxt/src/core/package-managers/npm.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import spawn from 'nano-spawn';
66

77
export const npm: WxtPackageManagerImpl = {
88
overridesKey: 'overrides',
9-
async downloadDependency(id, downloadDir) {
9+
async downloadDependency(id, downloadDir, options) {
1010
await ensureDir(downloadDir);
11-
const res = await spawn('npm', ['pack', id, '--json'], {
11+
const normalizedId = normalizeId(id, options?.cwd);
12+
const res = await spawn('npm', ['pack', normalizedId, '--json'], {
1213
cwd: downloadDir,
1314
});
1415
const packed: PackedDependency[] = JSON.parse(res.stdout);
@@ -82,3 +83,17 @@ interface PackedDependency {
8283
version: string;
8384
filename: string;
8485
}
86+
87+
/** Normalizes `file:` or `link:` package ids to point to an absolute path so they can be resolved from downloadDir. */
88+
function normalizeId(id: string, cwd?: string) {
89+
// this regex matches file: and link: dependencies with optional alias
90+
const match = id.match(/^(@?[^@]+)(?:@[^@]+)?@(?:file|link):(.+)$/);
91+
92+
if (!match) {
93+
return id;
94+
}
95+
96+
const [_, dependency, relativePath] = match;
97+
98+
return `${dependency}@file:${path.resolve(cwd ?? '', relativePath)}`;
99+
}

packages/wxt/src/core/zip.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,15 @@ async function downloadPrivatePackages() {
184184
const tgzPath = await wxt.pm.downloadDependency(
185185
id,
186186
wxt.config.zip.downloadedPackagesDir,
187+
{ cwd: wxt.config.root },
187188
);
188189
files.push(tgzPath);
189-
overrides[id] = tgzPath;
190+
191+
// make sure alias packages are correctly overridden
192+
// alias@name@spec -> alias@spec
193+
const normalizedId = id.replace(/^(.+)(@.+)@(.+)$/, '$1@$3');
194+
195+
overrides[normalizedId] = tgzPath;
190196
}
191197
}
192198

packages/wxt/src/types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1492,9 +1492,14 @@ export interface WxtPackageManager extends Nypm.PackageManager {
14921492
*
14931493
* @param id Name of the package to download, can include a version (like `[email protected]`)
14941494
* @param downloadDir Where to store the package.
1495+
* @param options Working directory used to resolve local packages
14951496
* @returns Absolute path to downloaded file.
14961497
*/
1497-
downloadDependency: (id: string, downloadDir: string) => Promise<string>;
1498+
downloadDependency: (
1499+
id: string,
1500+
downloadDir: string,
1501+
options?: { cwd?: string },
1502+
) => Promise<string>;
14981503
/**
14991504
* Run `npm ls`, `pnpm ls`, or `bun pm ls`, or `yarn list` and return the results.
15001505
*

0 commit comments

Comments
 (0)