Skip to content

Commit ebfbb42

Browse files
committed
fix(misc): fix build
1 parent 26c6bbc commit ebfbb42

2 files changed

Lines changed: 59 additions & 15 deletions

File tree

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
/**
2-
* Hermes + CSP Compatibility Test
2+
* Bundle compatibility test — Hermes, browser CSP, and SSR/Edge bundlers.
33
*
4-
* Asserts dist/index.cjs contains:
5-
* - No import() expressions -> hermesc (React Native bytecode compiler) rejects
6-
* import() at parse time, before dead-code elimination.
7-
* - No new Function() calls -> browsers with a strict Content-Security-Policy
8-
* (no 'unsafe-eval') block new Function() identically to eval() at runtime.
4+
* Three constraints, each verified against the relevant dist file:
95
*
10-
* Both constraints are satisfied by aliasing @supabase/tracing to its
11-
* `main`-field file (dist/main/index.js) for the CJS bundle — see
12-
* tsdown.config.ts. That file is tsc's CJS output, where the dynamic
13-
* `import()` has already been lowered to a runtime `require()`.
6+
* 1. `dist/index.cjs` contains no `import(` expression.
7+
* hermesc (the Hermes bytecode compiler used by React Native release
8+
* builds) rejects `import()` at parse time, before dead-code elimination.
9+
* Satisfied by aliasing @supabase/tracing to its `main`-field file
10+
* (dist/main/index.js — tsc's CJS output, where dynamic `import()` is
11+
* already lowered to `require()`). See `tsdown.config.ts`.
12+
*
13+
* 2. `dist/index.cjs` contains no `new Function(` call.
14+
* Browsers with a strict Content-Security-Policy (no `'unsafe-eval'`)
15+
* block `new Function()` identically to `eval()` at runtime.
16+
*
17+
* 3. Every `import(` in `dist/index.mjs` is flanked by bundler-ignore
18+
* magic comments (`webpackIgnore`, `@vite-ignore`, `turbopackIgnore`).
19+
* Without these, Turbopack (Next.js Edge), webpack, and Vite each
20+
* fail to build downstream consumers with
21+
* `Module not found: Can't resolve '@opentelemetry/api'` when the
22+
* optional peer dep is not installed.
1423
*
1524
* Run with: node test/bundle-hermes-compat.test.cjs
1625
*/
@@ -19,25 +28,49 @@ const assert = require('assert')
1928
const fs = require('fs')
2029
const path = require('path')
2130

22-
console.log('Testing Hermes + CSP compatibility of dist/index.cjs...\n')
31+
console.log('Testing bundle compatibility (Hermes / CSP / Edge bundlers)...\n')
2332

2433
const cjsPath = path.join(__dirname, '../dist/index.cjs')
34+
const mjsPath = path.join(__dirname, '../dist/index.mjs')
2535
const cjs = fs.readFileSync(cjsPath, 'utf8')
36+
const mjs = fs.readFileSync(mjsPath, 'utf8')
2637

27-
// Check 1: no import() expressions (breaks hermesc / React Native)
38+
// Check 1: dist/index.cjs has no import() expressions (breaks hermesc / React Native)
2839
assert.ok(
2940
!cjs.includes('import('),
3041
'dist/index.cjs contains import() — breaks hermesc (Hermes bytecode compiler for React Native)'
3142
)
3243
console.log('1. No import() expressions in dist/index.cjs')
3344
console.log(' Hermes-safe (React Native compatible)\n')
3445

35-
// Check 2: no new Function() (breaks browser strict CSP)
46+
// Check 2: dist/index.cjs has no new Function() (breaks browser strict CSP)
3647
assert.ok(
3748
!cjs.includes('new Function('),
3849
'dist/index.cjs contains new Function() — breaks browser strict Content-Security-Policy (unsafe-eval)'
3950
)
4051
console.log('2. No new Function() in dist/index.cjs')
4152
console.log(' CSP-safe (no unsafe-eval required)\n')
4253

43-
console.log('All Hermes + CSP compatibility checks passed.')
54+
// Check 3: every import() in dist/index.mjs has the bundler-ignore magic
55+
// comments so downstream SSR/Edge bundlers (Turbopack, webpack, Vite) don't
56+
// try to statically resolve the optional `@opentelemetry/api` peer dep.
57+
const requiredIgnoreTags = ['webpackIgnore', '@vite-ignore', 'turbopackIgnore']
58+
const importMatches = [...mjs.matchAll(/import\s*\(([\s\S]{0,400}?)\)/g)]
59+
assert.ok(
60+
importMatches.length > 0,
61+
'Expected at least one import() in dist/index.mjs (sanity check — if the bundle was refactored to remove all dynamic imports, this test needs updating)'
62+
)
63+
for (const m of importMatches) {
64+
const body = m[1]
65+
for (const tag of requiredIgnoreTags) {
66+
assert.ok(
67+
body.includes(tag),
68+
`dist/index.mjs has an import() expression missing /* ${tag} */ — downstream bundlers will try to statically resolve it (e.g. Next.js Edge fails with "Module not found: Can't resolve '@opentelemetry/api'"). Expression: ${m[0].slice(0, 200)}`
69+
)
70+
}
71+
}
72+
console.log(`3. All ${importMatches.length} import() expressions in dist/index.mjs carry`)
73+
console.log(` /* ${requiredIgnoreTags.join(' */ /* ')} */`)
74+
console.log(' SSR/Edge bundlers will not try to statically resolve them\n')
75+
76+
console.log('All bundle compatibility checks passed.')

packages/shared/tracing/src/extract.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,18 @@ const OTEL_PKG = '@opentelemetry/api'
1616

1717
function loadOtel(): Promise<any | null> {
1818
if (otelModulePromise === null) {
19-
otelModulePromise = (import(OTEL_PKG) as Promise<any>).catch(() => null)
19+
// Magic comments tell each major SSR/Edge bundler to skip static
20+
// resolution of this dynamic import — `@opentelemetry/api` is an
21+
// optional peer dep, so it may not be installed in the consumer app.
22+
// Without these, Turbopack (Next.js Edge), webpack, and Vite each
23+
// error with `Module not found: Can't resolve '@opentelemetry/api'`
24+
// when the peer dep is absent. The variable specifier (OTEL_PKG)
25+
// also helps for bundlers that don't honor the comments.
26+
otelModulePromise = (
27+
import(
28+
/* webpackIgnore: true */ /* @vite-ignore */ /* turbopackIgnore: true */ OTEL_PKG
29+
) as Promise<any>
30+
).catch(() => null)
2031
}
2132
return otelModulePromise
2233
}

0 commit comments

Comments
 (0)