Skip to content

Commit d06b485

Browse files
committed
fix: preview package tarballs (#411)
1 parent ad00625 commit d06b485

File tree

1 file changed

+69
-50
lines changed

1 file changed

+69
-50
lines changed

docs/scripts/pack.ts

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,17 @@ import { promisify } from 'node:util';
66

77
const exec = promisify(cp.exec);
88

9-
interface TurboDryRun {
10-
packages: Array<string>;
11-
tasks: Array<Task>;
12-
}
13-
14-
interface Task {
15-
taskId: string;
16-
task: string;
17-
package: string;
18-
hash: string;
19-
command: string;
20-
outputs: Array<string>;
21-
logFile: string;
22-
directory: string;
23-
dependencies: Array<string>;
24-
dependents: Array<string>;
9+
interface PackageJson {
10+
name: string;
11+
version: string;
12+
private?: boolean;
13+
dependencies?: Record<string, string>;
14+
devDependencies?: Record<string, string>;
15+
peerDependencies?: Record<string, string>;
2516
}
2617

2718
const rootDir = fileURLToPath(new URL('../../', import.meta.url));
19+
const packagesDir = path.join(rootDir, 'packages');
2820
const outDir = fileURLToPath(new URL('../public', import.meta.url));
2921

3022
async function main() {
@@ -33,53 +25,80 @@ async function main() {
3325
// Ensure output directory exists
3426
await fs.mkdir(outDir, { recursive: true });
3527

36-
const { stdout: turboStdout } = await exec('turbo run build --dry-run=json', {
37-
cwd: new URL('../', import.meta.url),
38-
});
28+
// Scan the packages directory for all packages
29+
const packageDirs = await fs.readdir(packagesDir);
30+
const packages: Array<{
31+
name: string;
32+
dir: string;
33+
packageJson: PackageJson;
34+
}> = [];
3935

40-
const turboJson: TurboDryRun = JSON.parse(turboStdout);
41-
42-
for (const task of turboJson.tasks) {
43-
const dir = path.join(rootDir, task.directory);
36+
for (const packageDir of packageDirs) {
37+
const dir = path.join(packagesDir, packageDir);
4438
const packageJsonPath = path.join(dir, 'package.json');
45-
const originalPackageJson = await fs.readFile(packageJsonPath, 'utf8');
46-
const originalPackageObj = JSON.parse(originalPackageJson);
39+
40+
try {
41+
const stat = await fs.stat(packageJsonPath);
42+
if (!stat.isFile()) continue;
43+
} catch {
44+
continue; // Skip directories without package.json
45+
}
46+
47+
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf8');
48+
const packageJson: PackageJson = JSON.parse(packageJsonContent);
4749

4850
// Skip private packages
49-
if (originalPackageObj.private) continue;
51+
if (packageJson.private) continue;
5052

51-
const packageObj = JSON.parse(originalPackageJson);
52-
packageObj.version += `-${sha.trim()}`;
53+
packages.push({ name: packageJson.name, dir, packageJson });
54+
}
5355

54-
// Update dependencies to use preview URLs
55-
if (task.dependencies.length > 0) {
56-
for (const dependency of task.dependencies) {
57-
const name = dependency.split('#')[0];
58-
const escapedName = name.replace(/^@(.+)\//, '$1-');
59-
const tarballUrl = `https://${process.env.VERCEL_URL}/${escapedName}.tgz`;
56+
// Create a set of all package names for dependency resolution
57+
const packageNames = new Set(packages.map((p) => p.name));
6058

61-
if (packageObj.dependencies && name in packageObj.dependencies) {
62-
packageObj.dependencies[name] = tarballUrl;
63-
}
64-
if (packageObj.devDependencies && name in packageObj.devDependencies) {
65-
packageObj.devDependencies[name] = tarballUrl;
59+
for (const { name, dir, packageJson } of packages) {
60+
const packageJsonPath = path.join(dir, 'package.json');
61+
const originalPackageJson = JSON.stringify(packageJson, null, 2);
62+
63+
// Create modified package.json with preview version
64+
const modifiedPackageJson: PackageJson = JSON.parse(originalPackageJson);
65+
modifiedPackageJson.version += `-${sha}`;
66+
67+
// Update workspace dependencies to use preview tarball URLs
68+
const updateDeps = (deps: Record<string, string> | undefined) => {
69+
if (!deps) return;
70+
for (const depName of Object.keys(deps)) {
71+
if (packageNames.has(depName)) {
72+
const escapedName = depName.replace(/^@(.+)\//, '$1-');
73+
deps[depName] =
74+
`https://${process.env.VERCEL_URL}/${escapedName}.tgz`;
6675
}
6776
}
68-
}
77+
};
6978

70-
// Write modified package.json
71-
await fs.writeFile(packageJsonPath, JSON.stringify(packageObj, null, 2));
79+
updateDeps(modifiedPackageJson.dependencies);
80+
updateDeps(modifiedPackageJson.devDependencies);
81+
updateDeps(modifiedPackageJson.peerDependencies);
7282

73-
// Pack the package
74-
await exec(`pnpm pack --out="${outDir}/%s.tgz"`, {
75-
cwd: dir,
76-
});
77-
78-
// Restore original package.json
79-
await fs.writeFile(packageJsonPath, originalPackageJson);
83+
// Write modified package.json
84+
await fs.writeFile(
85+
packageJsonPath,
86+
JSON.stringify(modifiedPackageJson, null, 2)
87+
);
88+
89+
try {
90+
// Pack the package
91+
await exec(`pnpm pack --out="${outDir}/%s.tgz"`, { cwd: dir });
92+
console.log(`Packed ${name}`);
93+
} finally {
94+
// Always restore original package.json
95+
await fs.writeFile(packageJsonPath, originalPackageJson);
96+
}
8097
}
8198

82-
console.log(`Successfully packed preview packages to ${outDir}`);
99+
console.log(
100+
`\nSuccessfully packed ${packages.length} preview packages to ${outDir}`
101+
);
83102
}
84103

85104
async function getSha(): Promise<string> {

0 commit comments

Comments
 (0)