Skip to content

Commit a4f6916

Browse files
fix(repo): Ensure Rspack dependencies are always installed (clerk#4481)
Co-authored-by: Nikos Douvlis <nikosdouvlis@gmail.com>
1 parent a493238 commit a4f6916

File tree

3 files changed

+249
-0
lines changed

3 files changed

+249
-0
lines changed

package-lock.json

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

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"changeset": "changeset",
1515
"changeset:empty": "npm run changeset -- --empty",
1616
"clean": "turbo clean",
17+
"dependencies": "node scripts/patch-incorrect-lockfile.mjs",
1718
"dev": "TURBO_UI=0 FORCE_COLOR=1 turbo dev --filter=@clerk/* --filter=!@clerk/clerk-expo --filter=!@clerk/tanstack-start --filter=!@clerk/elements --filter=!@clerk/tailwindcss-transformer --filter=!@clerk/remix --filter=!@clerk/ui --filter=!@clerk/chrome-extension",
1819
"dev:js": "TURBO_UI=0 FORCE_COLOR=1 turbo dev:current --filter=@clerk/clerk-js",
1920
"format": "prettier --write .",

scripts/patch-incorrect-lockfile.mjs

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//@ts-check
2+
3+
/**
4+
* This file adapted from Next.js' automatic SWC patching script.
5+
* https://github.com/vercel/next.js/blob/f771c6d78783684629c143329273b348990fcbe0/packages/next/src/lib/patch-incorrect-lockfile.ts
6+
*/
7+
8+
import { spawn } from 'child_process';
9+
import { promises } from 'fs';
10+
import path from 'path';
11+
12+
import lockfileParsed from '../package-lock.json' with { type: 'json' };
13+
14+
const registry = 'https://registry.npmjs.org/';
15+
16+
/**
17+
* Run `npm install` a second time to trigger npm's lockfile formatting. This prevents an additional diff to the
18+
* lockfile when the install is run a second time.
19+
*/
20+
async function formatPkgLock() {
21+
return /** @type {Promise<void>} */ (
22+
new Promise((resolve, reject) => {
23+
const npm = spawn('npm', ['install', '--package-lock-only'], {
24+
cwd: process.cwd(),
25+
env: process.env,
26+
stdio: 'inherit',
27+
});
28+
29+
npm.on('close', code => {
30+
if (code === 0) {
31+
resolve();
32+
}
33+
reject(code);
34+
});
35+
})
36+
);
37+
}
38+
39+
/** @typedef {Awaited<ReturnType<typeof fetchPkgInfo>>} PkgInfo */
40+
41+
/**
42+
*
43+
* @param {string} pkg
44+
* @param {string} version
45+
* @returns
46+
*/
47+
async function fetchPkgInfo(pkg, version) {
48+
// https://registry.npmjs.org/@rspack/binding-linux-x64-gnu
49+
const res = await fetch(`${registry}${pkg}/${version}`);
50+
51+
if (!res.ok) {
52+
throw new Error(`Failed to fetch registry info for ${pkg}, got status ${res.status}`);
53+
}
54+
const versionData = await res.json();
55+
56+
return {
57+
version: versionData.version,
58+
os: versionData.os,
59+
cpu: versionData.cpu,
60+
engines: versionData.engines,
61+
tarball: versionData.dist.tarball,
62+
integrity: versionData.dist.integrity,
63+
};
64+
}
65+
66+
/**
67+
* Attempts to patch npm package-lock.json when it
68+
* fails to include optionalDependencies for other platforms
69+
* this can occur when the package-lock is rebuilt from a current
70+
* node_modules install instead of pulling fresh package data
71+
*/
72+
async function patchIncorrectLockfile() {
73+
const expectedRspackPkgs = Object.entries(
74+
lockfileParsed['packages']['node_modules/@rspack/binding']['optionalDependencies'] || {},
75+
).filter(([pkg]) => pkg.startsWith('@rspack/binding-'));
76+
77+
/**
78+
*
79+
* @param {string} pkg
80+
* @param {PkgInfo} pkgData
81+
*/
82+
const patchPackage = (pkg, pkgData) => {
83+
lockfileParsed.packages[pkg] = {
84+
version: pkgData.version,
85+
resolved: pkgData.tarball,
86+
integrity: pkgData.integrity,
87+
cpu: pkgData.cpu,
88+
optional: true,
89+
os: pkgData.os,
90+
engines: pkgData.engines,
91+
};
92+
};
93+
94+
try {
95+
/** @type {[string, string][]} */
96+
const missingRspackPkgs = [];
97+
98+
/** @type {string|undefined} */
99+
let pkgPrefix;
100+
101+
pkgPrefix = '';
102+
for (const pkg of Object.keys(lockfileParsed.packages)) {
103+
if (pkg.endsWith('node_modules/@rspack/core')) {
104+
pkgPrefix = pkg.substring(0, pkg.length - 12);
105+
}
106+
}
107+
108+
if (!pkgPrefix) {
109+
// unable to locate the next package so bail
110+
return;
111+
}
112+
113+
for (const pkg of expectedRspackPkgs) {
114+
if (!lockfileParsed.packages[`${pkgPrefix}${pkg[0]}`]) {
115+
missingRspackPkgs.push(pkg);
116+
}
117+
}
118+
119+
if (missingRspackPkgs.length === 0) {
120+
return;
121+
}
122+
console.warn(`Found lockfile missing swc dependencies,`, 'patching...');
123+
124+
const pkgsData = await Promise.all(missingRspackPkgs.map(([pkg, version]) => fetchPkgInfo(pkg, version)));
125+
126+
for (let i = 0; i < pkgsData.length; i++) {
127+
const pkg = missingRspackPkgs[i][0];
128+
const pkgData = pkgsData[i];
129+
130+
patchPackage(`${pkgPrefix}${pkg}`, pkgData);
131+
}
132+
133+
await promises.writeFile(path.join(process.cwd(), 'package-lock.json'), JSON.stringify(lockfileParsed, null, 2));
134+
console.warn(
135+
'Lockfile was successfully patched, please run "npm install" to ensure Rspack dependencies are downloaded',
136+
);
137+
await formatPkgLock();
138+
} catch (err) {
139+
console.error(`Failed to patch lockfile, please try uninstalling and reinstalling next in this workspace`);
140+
console.error(err);
141+
}
142+
}
143+
144+
await patchIncorrectLockfile();

0 commit comments

Comments
 (0)