Skip to content

Commit 063decf

Browse files
committed
test(ci): guard react package exports too via shared scripts/check-exports.mjs
1 parent fabaae7 commit 063decf

6 files changed

Lines changed: 52 additions & 30 deletions

File tree

.github/workflows/embed.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ jobs:
3939

4040
- name: Bundle size budgets
4141
run: npm run --workspace @simplepdf/embed check:size
42+
43+
- name: Export load
44+
run: npm run --workspace @simplepdf/embed check:exports

.github/workflows/react.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ jobs:
3838
- name: Build the core
3939
run: npm run --workspace @simplepdf/embed build
4040

41+
- name: Build react-embed-pdf
42+
run: npm run --workspace @simplepdf/react-embed-pdf build
43+
4144
- name: Formatting
4245
run: npm run --workspace @simplepdf/react-embed-pdf test:format
4346

@@ -46,3 +49,6 @@ jobs:
4649

4750
- name: Tests
4851
run: npm run --workspace @simplepdf/react-embed-pdf test
52+
53+
- name: Export load
54+
run: npm run --workspace @simplepdf/react-embed-pdf check:exports

embed/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
"pretest": "npm run generate",
6464
"test": "vitest run",
6565
"test:watch": "vitest",
66-
"check:size": "npm run build && node scripts/check-bundle-size.mjs"
66+
"check:size": "npm run build && node scripts/check-bundle-size.mjs",
67+
"check:exports": "node ../scripts/check-exports.mjs ."
6768
},
6869
"peerDependencies": {
6970
"@tanstack/ai": "^0.38.0",

embed/scripts/check-bundle-size.mjs

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// Build verification, run after `npm run build`. (1) Gzips each public entry's local
1+
// Bundle-size budget guard, run after `npm run build`. Gzips each public entry's local
22
// closure (the entry file plus the dist chunks it imports; peer deps are external and
3-
// never counted) and fails if any entry exceeds its budget. (2) Loads every public
4-
// subpath per its export conditions, so an entry that resolves but throws at load (e.g.
5-
// a CJS bundle requiring an ESM-only peer) fails here, not at the consumer.
3+
// never counted) and fails if any entry exceeds its budget. Export loadability is guarded
4+
// separately by ../../scripts/check-exports.mjs (the `check:exports` script).
65

76
import { existsSync, readFileSync } from 'node:fs'
8-
import { createRequire } from 'node:module'
97
import { dirname, join } from 'node:path'
108
import { fileURLToPath } from 'node:url'
119
import { gzipSync } from 'node:zlib'
@@ -58,26 +56,4 @@ const allWithinBudget = Object.entries(BUDGETS).map(([entry, budget]) => {
5856
console.log(`${ok ? '✓' : '✗'} ${entry}: ${size} B gzip (budget ${budget} B)`)
5957
return ok
6058
})
61-
// Load every public subpath the way its export map advertises it.
62-
const require = createRequire(import.meta.url)
63-
const pkg = JSON.parse(readFileSync(join(DIST, '..', 'package.json'), 'utf8'))
64-
const load = { require: (spec) => require(spec), import: (spec) => import(spec) }
65-
const exportsLoad = []
66-
for (const [subpath, conditions] of Object.entries(pkg.exports)) {
67-
const spec = subpath === '.' ? pkg.name : `${pkg.name}/${subpath.slice(2)}`
68-
for (const condition of ['require', 'import']) {
69-
if (conditions[condition] === undefined) {
70-
continue
71-
}
72-
try {
73-
await load[condition](spec)
74-
console.log(`✓ ${spec} [${condition}] loads`)
75-
exportsLoad.push(true)
76-
} catch (error) {
77-
console.error(`✗ ${spec} [${condition}]: ${error.code ?? error.message}`)
78-
exportsLoad.push(false)
79-
}
80-
}
81-
}
82-
83-
process.exit([...allWithinBudget, ...exportsLoad].every(Boolean) ? 0 : 1)
59+
process.exit(allWithinBudget.every(Boolean) ? 0 : 1)

react/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
"format": "npm run prettier -- --write",
4545
"prepublishOnly": "rimraf dist && npm run build",
4646
"build": "rollup -c",
47-
"start": "rollup -c -w"
47+
"start": "rollup -c -w",
48+
"check:exports": "node ../scripts/check-exports.mjs ."
4849
},
4950
"dependencies": {
5051
"@simplepdf/embed": "^0.5.0"

scripts/check-exports.mjs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Export-load guard, shared by the workspace packages. Loads every public subpath of a
2+
// built package per its export conditions (require + import), so an entry that resolves
3+
// but throws at load (e.g. a CJS bundle requiring an ESM-only peer) fails CI, not the
4+
// consumer. Run after that package's build.
5+
//
6+
// node ../scripts/check-exports.mjs <packageDir> (defaults to the cwd)
7+
8+
import { readFileSync } from 'node:fs'
9+
import { createRequire } from 'node:module'
10+
import { resolve } from 'node:path'
11+
12+
const packageDir = resolve(process.argv[2] ?? '.')
13+
const pkg = JSON.parse(readFileSync(resolve(packageDir, 'package.json'), 'utf8'))
14+
const require = createRequire(import.meta.url)
15+
const load = { require: (spec) => require(spec), import: (spec) => import(spec) }
16+
17+
const results = []
18+
for (const [subpath, conditions] of Object.entries(pkg.exports)) {
19+
const spec = subpath === '.' ? pkg.name : `${pkg.name}/${subpath.slice(2)}`
20+
for (const condition of ['require', 'import']) {
21+
if (conditions[condition] === undefined) {
22+
continue
23+
}
24+
try {
25+
await load[condition](spec)
26+
console.log(`✓ ${spec} [${condition}]`)
27+
results.push(true)
28+
} catch (error) {
29+
console.error(`✗ ${spec} [${condition}]: ${error.code ?? error.message}`)
30+
results.push(false)
31+
}
32+
}
33+
}
34+
35+
process.exit(results.every(Boolean) ? 0 : 1)

0 commit comments

Comments
 (0)