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')
1928const fs = require ( 'fs' )
2029const 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
2433const cjsPath = path . join ( __dirname , '../dist/index.cjs' )
34+ const mjsPath = path . join ( __dirname , '../dist/index.mjs' )
2535const 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)
2839assert . ok (
2940 ! cjs . includes ( 'import(' ) ,
3041 'dist/index.cjs contains import() — breaks hermesc (Hermes bytecode compiler for React Native)'
3142)
3243console . log ( '1. No import() expressions in dist/index.cjs' )
3344console . 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)
3647assert . ok (
3748 ! cjs . includes ( 'new Function(' ) ,
3849 'dist/index.cjs contains new Function() — breaks browser strict Content-Security-Policy (unsafe-eval)'
3950)
4051console . log ( '2. No new Function() in dist/index.cjs' )
4152console . 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 ( / i m p o r t \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.' )
0 commit comments