diff --git a/.github/workflows/javascript.yml b/.github/workflows/javascript.yml index 2ccda8115..b67e4da8c 100644 --- a/.github/workflows/javascript.yml +++ b/.github/workflows/javascript.yml @@ -46,16 +46,22 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Node + - name: Set up Node 20 (build) uses: actions/setup-node@v3 with: - node-version: '18' + node-version: 20 cache-dependency-path: ./package-lock.json cache: 'npm' - - name: Run CommonJS example + - name: Build and pack SDK run: | npm install - npm run test-commonjs + npm pack + - name: Set up Node 18 (runtime test) + uses: actions/setup-node@v3 + with: + node-version: '18' + - name: Run CommonJS example + run: npm run test-commonjs -- --skip-build react_native_metro_test: runs-on: ubuntu-latest diff --git a/lib/import.react_native/README.md b/lib/import.react_native/README.md index af5893935..2819dc66f 100644 --- a/lib/import.react_native/README.md +++ b/lib/import.react_native/README.md @@ -2,7 +2,7 @@ Each file in this directory loads one optional React Native dependency (a peer dependency the app may not have installed) and tells the rest of the SDK whether it is available. -The shims are not bundled into the main SDK bundle. Rollup builds each one to the same path under `dist/import.react_native/`, and the main React Native bundles `require` it by relative path (see `rollup.config.mjs`). The rest of this section explains why. +The shims are not bundled into the main SDK bundle. Rolldown builds each one to the same path under `dist/import.react_native/`, and the main React Native bundles `require` it by relative path (see `rolldown.config.mjs`). The rest of this section explains why. ## Why the shims are separate modules @@ -78,18 +78,17 @@ A test goes next to its shim as `.spec.ts`. Spec files are not built as sh - **The package's exports, under the same names:** if the package isn't installed they are `undefined`. A shim may adapt a value as long as it keeps the package's shape. For example, the async-storage shim adds `multiGet` on AsyncStorage v3. - **Only the exports the SDK uses:** this isn't required for correctness. Re-exporting more would still be one `require`. It just keeps the shims small. - **Packages loaded only for side effects:** polyfills like `fast-text-encoding` only need `isAvailable`. -- **A shim can use `export default` when the package has a default export,** as the async-storage shim does. This works because of a setting in `rollup.config.mjs`: +- **A shim can use `export default` when the package has a default export,** as the async-storage shim does: - Shims are built as CommonJS. A default export becomes `exports.default`, and the file is marked with `__esModule`. - - In the main CJS bundles, Rollup by default treats a default import from an external CommonJS module as the whole `module.exports`. `import AsyncStorage from '…/async-storage'` would then get the shim's exports object instead of the storage. - - `rollup.config.mjs` therefore sets `interop: 'esModule'` for shim imports, so the CJS bundles read `exports.default`. - - Shims are only built as CommonJS; the ESM main bundle imports the same CommonJS files. It doesn't need the setting: the app's bundler (Metro, or webpack) reads `exports.default` for a default import from a CommonJS module marked with `__esModule`. + - In the main CJS bundles, Rolldown wraps a `require` of an external CommonJS module in its `__toESM` helper, which reads `exports.default` for a default import when the module is marked with `__esModule`. `import AsyncStorage from '…/async-storage'` therefore gets the storage, not the shim's exports object. (Rollup needed `interop: 'esModule'` for this; Rolldown needs no setting.) + - Shims are only built as CommonJS; the ESM main bundle imports the same CommonJS files. The app's bundler (Metro, or webpack) reads `exports.default` for a default import from a CommonJS module marked with `__esModule`. - **Never throw.** A shim catches the `require` error, sets `isAvailable = false`, and leaves its exports `undefined`. The importer decides what a missing package means. For example, `index.react_native.ts` throws if `TextEncoder` is still missing after the polyfill shims run, and `AsyncStorageCache` throws "Module not found" when there's no AsyncStorage. ### Exactly one `require` in the built file The optional `require` must be the only `require` in the built shim (`dist/import.react_native/.js`). Any other `require` in the module could shift when the optional package is missing. -**The build enforces this.** The `rn-import-shim-check` plugin in `rollup.config.mjs` fails the build if a built shim contains any `require` other than its own package's. The package is taken from the shim's name, so the check also enforces the naming convention. +**The build enforces this.** The `rn-import-shim-check` plugin in `rolldown.config.mjs` fails the build if a built shim contains any `require` other than its own package's. The package is taken from the shim's name, so the check also enforces the naming convention. - **Wrap the `require` directly in `try/catch`.** Metro only treats a `require` as optional when it is directly inside a `try` block. Without that, a missing package fails the app's build. - **Run it at module load, not later in a function.** Only then is a failed `require` thrown to the shim's `catch`. Later, Metro before 0.82.5 reports it as a fatal error instead (see "The bug in Metro before 0.82.5"). @@ -122,4 +121,4 @@ try { export const __platforms: Platform[] = ['react_native']; ``` -Importers use a shim through a normal relative import, for example `import { isAvailable, someExport } from './import.react_native/some-package'`. The Rollup plugin turns that into the relative `require` of the built shim. +Importers use a shim through a normal relative import, for example `import { isAvailable, someExport } from './import.react_native/some-package'`. The `rn-import-shim-external` plugin in `rolldown.config.mjs` turns that into the relative `require` of the built shim. diff --git a/package-lock.json b/package-lock.json index b6dbe29ae..20094c47e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,10 +17,6 @@ "devDependencies": { "@react-native-async-storage/async-storage": "^2", "@react-native-community/netinfo": "^11.3.2", - "@rollup/plugin-alias": "^6.0.0", - "@rollup/plugin-commonjs": "^29.0.0", - "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-terser": "^0.4.4", "@types/chai": "^4.2.11", "@types/mocha": "^5.2.7", "@types/nise": "^1.4.0", @@ -44,8 +40,7 @@ "nock": "11.9.1", "nyc": "^15.0.1", "prettier": "^1.19.1", - "promise-polyfill": "8.1.0", - "rollup": "^4.55.1", + "rolldown": "^1.2.16", "sinon": "^2.3.1", "ts-loader": "^9.3.1", "ts-node": "^10.9.2", @@ -1704,6 +1699,16 @@ "node": ">= 8" } }, + "node_modules/@oxc-project/types": { + "version": "0.156.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.156.0.tgz", + "integrity": "sha512-1Duyg48TdJNdyhEB8Xn1L36bT9Pv6GUtlKjHxOys8xkaF/rQq3XJE+bAurSK/AgIz5mGFsb77cn9Pb20+WCScw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2073,122 +2078,268 @@ } } }, - "node_modules/@rollup/plugin-alias": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-6.0.0.tgz", - "integrity": "sha512-tPCzJOtS7uuVZd+xPhoy5W4vThe6KWXNmsFCNktaAh5RTqcLiSfT4huPQIXkgJ6YCOjJHvecOAzQxLFhPxKr+g==", + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.16.tgz", + "integrity": "sha512-ia3DwAs0OsMGS7+IConptSiyk9pEXkOx/AbJ2n/lAGxH3QkWQus1t8d7gnAT38FCU2sQu8lUbeR6AiZFv4JxaA==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "rollup": ">=4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.0.tgz", - "integrity": "sha512-U2YHaxR2cU/yAiwKJtJRhnyLk7cifnQw0zUpISsocBDoHDJn+HTV74ABqnwr5bEgWUwFZC9oFL6wLe21lHu5eQ==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.16.tgz", + "integrity": "sha512-kx5wBiMB6E7TEvpl2B9gjLU004BkvEm2Dr941BFjx/SontPwSzNuQUIoVKxHHoSjpFIfHMmcguyLOtyn0hObRg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "fdir": "^6.2.0", - "is-reference": "1.2.1", - "magic-string": "^0.30.3", - "picomatch": "^4.0.2" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=16.0.0 || 14 >= 14.17" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz", - "integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.16.tgz", + "integrity": "sha512-qslZrXnKJU4cUpjoAmtAo/KQM9e2IRMlmpig6Zpwj+8KWxW8v+nkAf9216Bsek9lOC1jvg2yCjygCFo2f83msQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rollup/plugin-terser": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", - "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.16.tgz", + "integrity": "sha512-FdF+y48ND13eAyM2mQn+85kvAqNlvRWROy2rhgA463X/0Gv4vGtazZtfaF1mRBLscYvtOlh4QnLjOWiFzX69OQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "serialize-javascript": "^6.0.1", - "smob": "^1.0.0", - "terser": "^5.17.4" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.16.tgz", + "integrity": "sha512-ddjqFM5e95AgLbUPtKIS7V1KTVlA0RUgCVr5mn+/IEhsdy3pr+Vuj/HZ7nlMN2FyxIwUktOH1LEPIQXO1v9y1Q==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.16.tgz", + "integrity": "sha512-tHdKWbFkFBI687iim3LIyIvyL7j66VvQYkDPss5Stn/qyE2tWkR1YD0dXmXPFKKqT/o5ZEJVsaRsWS2meQwGOA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.16.tgz", + "integrity": "sha512-FJiLGAblPBMlBEdbOqw6kW6QcXDWAf/oJu7gYs9ZJZwmg+K+/zjFLxPTIY9izJUzxzc24FHvmseyA0IvJSl17w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.16.tgz", + "integrity": "sha512-hrJpblMsrQ58U9veWpbXzkhV5zStunds6HWLprqq1qauvgBr1E6P+24kLj6lSLI9vjRn/RYpjprhkHQPKGWpNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.16.tgz", + "integrity": "sha512-qJd/dC6j6CwLG9/s/RP2nb1RZ0GIgj7Ioj7x/SYa3RzjVrlzrmH0fhIOpfvqQDeIsdP0loi+kHaMhJzY1PBIaA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.16.tgz", + "integrity": "sha512-Vx7Xg5uUJuNcujJjI70OICaH0EYj80BtOLZTSN7uOYg8QOLlyKnaG0IW7Fn/J0IpJsaKzmDKMhOQv1JBM9m9vg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.16.tgz", + "integrity": "sha512-TNKhgE3uJTsTzatUSSYt0Kgo+Oa2uSlSjz4r1aEIea7HX6ULBym4fAlYUhG1i6pjNf2njfCUAfKwr6C3E9Xg1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.16.tgz", + "integrity": "sha512-7chXdpjXZ8qG0+mIxECN3cT9kvhZ3/oZhMX6Pp876P7CDrIy8nJswva6Mq357JR7eYXfuskwZxMeV1SzoZdHrA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.16.tgz", + "integrity": "sha512-Kwjt+7uNTJK5/MDkGWGVO2KQPnj8yAV75dMpfwyHZrJSXWHrniOB0aUEWlVYf3H1hOqFLIStLdM5QXq6bnKmOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.16.tgz", + "integrity": "sha512-/LH6WfjDRXXJz/p5xl4TmU+jpcnwcxbKEQBW/GZE0JHfN0lGIyTtsUEGaQ/q/GikkGJ2yLKe6pwm7AnEWO8pdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.16.tgz", + "integrity": "sha512-1lv1KvX0Z871zfk7vw+dnXMMnHNyDwMzWG8Kv3HxDXMOhzCX4SHc7HK319fInP0i+0p9D8brkfzL7pJOaGl+tw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.55.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", @@ -2820,13 +2971,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", @@ -5241,16 +5385,6 @@ "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/deepmerge-ts": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", @@ -6020,13 +6154,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -6514,16 +6641,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/geckodriver": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-6.1.0.tgz", @@ -6872,19 +6989,6 @@ "node": ">=8" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -7208,22 +7312,6 @@ "node": ">=8" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -7274,13 +7362,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7311,16 +7392,6 @@ "node": ">=8" } }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/is-running": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-running/-/is-running-2.1.0.tgz", @@ -9771,13 +9842,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -10091,13 +10155,6 @@ "asap": "~2.0.6" } }, - "node_modules/promise-polyfill": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.0.tgz", - "integrity": "sha512-OzSf6gcCUQ01byV4BgwyUCswlaQQ6gzXc23aLQWhicvfX9kfsUiUhgt3CCQej8jDnl8/PhGF31JdHX2/MzF3WA==", - "dev": true, - "license": "MIT" - }, "node_modules/propagate": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", @@ -10586,27 +10643,6 @@ "dev": true, "license": "ISC" }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -10679,6 +10715,40 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rolldown": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.16.tgz", + "integrity": "sha512-bWvlMpFKiTfDKfnK7FC2MPgPeWCf/Kpwsq49ApdW+FQaBZb6O6dZ4MAPbPUjp7hYQrw/RobqCzn64BRrQecGHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.156.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.16", + "@rolldown/binding-android-arm64": "1.2.16", + "@rolldown/binding-darwin-arm64": "1.2.16", + "@rolldown/binding-darwin-x64": "1.2.16", + "@rolldown/binding-freebsd-x64": "1.2.16", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.16", + "@rolldown/binding-linux-arm64-gnu": "1.2.16", + "@rolldown/binding-linux-arm64-musl": "1.2.16", + "@rolldown/binding-linux-ppc64-gnu": "1.2.16", + "@rolldown/binding-linux-s390x-gnu": "1.2.16", + "@rolldown/binding-linux-x64-gnu": "1.2.16", + "@rolldown/binding-linux-x64-musl": "1.2.16", + "@rolldown/binding-openharmony-arm64": "1.2.16", + "@rolldown/binding-win32-arm64-msvc": "1.2.16", + "@rolldown/binding-win32-x64-msvc": "1.2.16" + } + }, "node_modules/rollup": { "version": "4.55.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz", @@ -11179,13 +11249,6 @@ "npm": ">= 3.0.0" } }, - "node_modules/smob": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", - "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", - "dev": true, - "license": "MIT" - }, "node_modules/socks": { "version": "2.8.7", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", @@ -11541,19 +11604,6 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", diff --git a/package.json b/package.json index 8bdece775..dffdf21f3 100644 --- a/package.json +++ b/package.json @@ -73,11 +73,11 @@ "posttest": "npm run lint", "test-ci": "npm run test", "prebuild": "npm run clean", - "build": "npm run validate-platform-isolation && npm run genmsg && tsc && rollup -c rollup.config.mjs && cp dist/index.browser.d.ts dist/index.d.ts", - "build:win": "npm run validate-platform-isolation && npm run genmsg && tsc && rollup -c rollup.config.mjs && copy dist\\index.browser.d.ts dist\\index.d.ts", - "build-browser-umd": "tsc && rollup -c rollup.config.mjs --config-umd", + "build": "npm run validate-platform-isolation && npm run genmsg && tsc && rolldown -c rolldown.config.mjs && cp dist/index.browser.d.ts dist/index.d.ts", + "build:win": "npm run validate-platform-isolation && npm run genmsg && tsc && rolldown -c rolldown.config.mjs && copy dist\\index.browser.d.ts dist\\index.d.ts", + "build-browser-umd": "npm run genmsg && tsc && rolldown -c rolldown.config.mjs -- --config-umd", "coveralls": "nyc --reporter=lcov npm test", - "prepare": "npm run build", + "prepack": "npm run build", "prepublishOnly": "npm test", "genmsg": "./scripts/generate-messages.js ./lib/message/error_message.ts ./lib/message/log_message.ts", "test-typescript": "node ./scripts/run-ts-example.js", @@ -107,10 +107,6 @@ "devDependencies": { "@react-native-async-storage/async-storage": "^2", "@react-native-community/netinfo": "^11.3.2", - "@rollup/plugin-alias": "^6.0.0", - "@rollup/plugin-commonjs": "^29.0.0", - "@rollup/plugin-node-resolve": "^16.0.3", - "@rollup/plugin-terser": "^0.4.4", "@types/chai": "^4.2.11", "@types/mocha": "^5.2.7", "@types/nise": "^1.4.0", @@ -134,8 +130,7 @@ "nock": "11.9.1", "nyc": "^15.0.1", "prettier": "^1.19.1", - "promise-polyfill": "8.1.0", - "rollup": "^4.55.1", + "rolldown": "^1.2.16", "sinon": "^2.3.1", "ts-loader": "^9.3.1", "ts-node": "^10.9.2", diff --git a/rollup.config.mjs b/rolldown.config.mjs similarity index 58% rename from rollup.config.mjs rename to rolldown.config.mjs index aeca0502d..8ea0c7c7a 100644 --- a/rollup.config.mjs +++ b/rolldown.config.mjs @@ -14,10 +14,6 @@ * limitations under the License. */ -import commonjs from '@rollup/plugin-commonjs'; -import nodeResolve from '@rollup/plugin-node-resolve'; -import terser from '@rollup/plugin-terser'; -import alias from '@rollup/plugin-alias'; import { createRequire } from 'module'; import { fileURLToPath } from 'url'; import { readdirSync } from 'fs'; @@ -29,29 +25,11 @@ const __dirname = dirname(__filename); const require = createRequire(import.meta.url); const { dependencies, peerDependencies } = require('./package.json'); -const resolvePlugin = nodeResolve(); - -const resolvePluginNode = nodeResolve({ - exportConditions: ['node'], -}); - -const resolvePluginBrowser = nodeResolve({ - browser: true, - exportConditions: ['browser'], -}); - -const resolvePluginByPlatform = { - node: resolvePluginNode, - browser: resolvePluginBrowser, +const aliasEntries = { + 'error_message': join(__dirname, '.build/message/error_message.gen.js'), + 'log_message': join(__dirname, '.build/message/log_message.gen.js'), }; -const aliasPlugin = alias({ - entries: [ - { find: 'error_message', replacement: join(__dirname, '.build/message/error_message.gen.js') }, - { find: 'log_message', replacement: join(__dirname, '.build/message/log_message.gen.js') }, - ] -}); - const externalDeps = ['https', 'http', 'url'].concat(Object.keys({ ...dependencies, ...peerDependencies } || {})); // uuid@13 is ESM-only and does not provide a CommonJS export. @@ -59,6 +37,16 @@ const externalDeps = ['https', 'http', 'url'].concat(Object.keys({ ...dependenci // into the CJS output instead of leaving it as an external dependency. const externalDepsWithoutUuid = externalDeps.filter(dep => dep !== 'uuid'); +// Every bundle sets the output syntax target, matching tsconfig.json's target (ES6). The input is already ES6 +// (compiled by tsc), but Rolldown's minifier defaults to the newest syntax and would rewrite compiled code back +// into later syntax, e.g. `a == null ? void 0 : a.b` into `a?.b` (ES2020). Rolldown doesn't read the target from +// tsconfig.json. +const transform = { target: 'es2015' }; + +// CJS and UMD outputs set `strict: true`. Rolldown otherwise adds "use strict" only when the source has the +// directive, and tsc's ES module output has none (modules are always strict), so the bundles would run in sloppy +// mode. The Rollup bundles were strict. + // React Native optional import shims (lib/import.react_native) are not bundled into the main bundles. // Each is shipped as its own module at the same relative location in dist, because Metro before 0.82.5 // shifts every later require in a module when an optional dependency is missing. @@ -81,9 +69,13 @@ const RN_IMPORT_SHIMS = listShims(); // -> require("./import.react_native/@react-native-async-storage/async-storage.js") (in dist/index.react_native.min.js) // The bundles are at the root of dist and the shims are built to dist/import.react_native, // so that path points to the built shim. -// Marking the imports external via the `external` option is not enough: Rollup would resolve them to the -// file in .build and write a path from the bundle back into .build (../.build/import.react_native/...). -// Returning a relative id from resolveId makes Rollup write it exactly as given. +// Marking the imports external via the `external` option is not enough: the bundler would resolve them to +// the file in .build and write a path from the bundle back into .build (../.build/import.react_native/...). +// Returning a relative id from resolveId makes the bundler write it exactly as given. +// +// Shims are built as CommonJS with __esModule set, so a default import of a shim must read its `default` +// export. Rolldown's CJS interop for externals (__toESM) already does that for modules with __esModule set, +// so no per-import interop override is needed (Rollup needed `output.interop: 'esModule'` for these). const rnImportShimExternalPlugin = { name: 'rn-import-shim-external', resolveId(source, importer) { @@ -94,15 +86,11 @@ const rnImportShimExternalPlugin = { }, }; -// Shims are built as CommonJS with __esModule set, so a default import of a shim must read its `default` -// export ('esModule'). Rollup's 'default' interop, used for the other externals, would read the whole module. -const rnImportShimInterop = id => (id && id.startsWith(`./${RN_IMPORT_SHIM_DIR}/`) ? 'esModule' : 'default'); - // Fails the build unless every built shim contains exactly one require(), of its own package (the shim's // name). Any other require in a shim could be shifted by the Metro bug when the package is missing. This -// catches imports of other packages, tslib helpers, and code shared between shims (Rollup moves it into a -// shared chunk that the shims require). The shim's own require() is plain code, so Rollup doesn't list it in -// chunk.imports; the generated code is parsed instead, with Rollup's parser. +// catches imports of other packages, tslib helpers, and code shared between shims (the bundler moves it into +// a shared chunk that the shims require). The shim's own require() is plain code, so it isn't listed in +// chunk.imports; the generated code is parsed instead, with the bundler's parser. const rnImportShimCheckPlugin = { name: 'rn-import-shim-check', generateBundle(_, bundle) { @@ -137,149 +125,180 @@ const rnImportShimCheckPlugin = { }; const rnImportShimsBundle = { - plugins: [rnImportShimCheckPlugin], - external: externalDeps, input: Object.fromEntries( RN_IMPORT_SHIMS.map(name => [name, join(BUILD_DIR, RN_IMPORT_SHIM_DIR, `${name}.js`)]) ), output: { exports: 'named', format: 'cjs', + strict: true, dir: join('dist', RN_IMPORT_SHIM_DIR), entryFileNames: '[name].js', }, + plugins: [rnImportShimCheckPlugin], + transform, + external: externalDeps, }; -const cjsBundleFor = (platform, opt = {}) => { - const { minify, ext } = { - minify: true, - ext: '.js', - ...opt, - }; +// Every bundle sets `platform` explicitly. Rolldown otherwise defaults it to 'node' for cjs output and +// 'browser' for other formats, and always adds that platform's export condition, even when conditionNames +// is set. A browser cjs bundle would then resolve the 'node' condition and pull Node-only builds of bundled +// deps (e.g. uuid's dist-node, which requires node:crypto). `platform` also sets the default mainFields, +// and only 'browser' applies the package.json `browser` field's file mappings (aliasFields). +const rolldownPlatformFor = (platform) => { + switch (platform) { + case 'node': + return 'node'; + case 'browser': + return 'browser'; + default: + return 'neutral'; + } +}; +// Resolution on top of each platform's defaults. Rolldown adds 'import'/'require' (by import kind) and +// 'default' to conditionNames on every platform. +// - node, browser: the platform defaults are used as is ('node' or 'browser' plus 'module' conditions; +// mainFields ['main', 'module'] for node, ['browser', 'module', 'main'] and `browser` field mappings +// for browser). +// - react_native: resolves like Metro, which reads the `react-native` and `browser` fields (entry points +// and file mappings, `react-native` first) and the 'react-native' condition. +// - neutral (universal and the platform-independent bundles): unlike node and browser, the platform +// doesn't add the 'module' condition (it only has 'import'/'require' and 'default'), and its mainFields +// default is empty, so a package without an `exports` map would not resolve at all. 'module' and +// ['module', 'main'] match Rollup's plain nodeResolve(), which these bundles used. +const resolveForPlatform = (platform) => { + const base = { alias: aliasEntries }; + switch (platform) { + case 'node': + case 'browser': + return base; + case 'react_native': + return { + ...base, + conditionNames: ['react-native', 'module'], + mainFields: ['react-native', 'browser', 'module', 'main'], + aliasFields: [['react-native'], ['browser']], + }; + default: + return { ...base, conditionNames: ['module'], mainFields: ['module', 'main'] }; + } +}; + +const cjsBundleFor = (platform, opt = {}) => { + const { minify = true, ext = '.js' } = opt; const min = minify ? '.min' : ''; return { - plugins: [rnImportShimExternalPlugin, aliasPlugin, resolvePluginByPlatform[platform] || resolvePlugin, commonjs()], - external: externalDepsWithoutUuid, - input: `.build/index.${platform}.js`, + input: `./.build/index.${platform}.js`, output: { exports: 'named', format: 'cjs', + strict: true, file: `dist/index.${platform}${min}${ext}`, - interop: rnImportShimInterop, - plugins: minify ? [terser()] : undefined, sourcemap: true, + minify, }, - } -}; - -const esmBundleFor = (platform, opt) => { - const { minify, ext } = { - minify: true, - ext: '.js', - ...opt, + plugins: [rnImportShimExternalPlugin], + transform, + platform: rolldownPlatformFor(platform), + resolve: resolveForPlatform(platform), + external: externalDepsWithoutUuid, }; +}; +const esmBundleFor = (platform, opt = {}) => { + const { minify = true, ext = '.js' } = opt; const min = minify ? '.min' : ''; return { ...cjsBundleFor(platform), external: externalDeps, - output: [ - { - format: 'es', - file: `dist/index.${platform}.es${min}${ext}`, - plugins: minify ? [terser()] : undefined, - sourcemap: true, - }, - ], - } + output: { + format: 'es', + file: `dist/index.${platform}.es${min}${ext}`, + sourcemap: true, + minify, + }, + }; }; const cjsBundleForUAParser = (opt = {}) => { - const { minify, ext } = { - minify: true, - ext: '.js', - ...opt, - }; - + const { minify = true, ext = '.js' } = opt; const min = minify ? '.min' : ''; return { - plugins: [aliasPlugin, resolvePlugin, commonjs()], - external: externalDepsWithoutUuid, - input: `.build/odp/ua_parser/ua_parser.js`, + input: `./.build/odp/ua_parser/ua_parser.js`, output: { exports: 'named', format: 'cjs', + strict: true, file: `dist/ua_parser${min}${ext}`, - plugins: minify ? [terser()] : undefined, sourcemap: true, + minify, }, + transform, + platform: rolldownPlatformFor('neutral'), + resolve: resolveForPlatform('neutral'), + external: externalDepsWithoutUuid, }; }; const esmBundleForUAParser = (opt = {}) => { - const { minify, ext } = { - minify: true, - ext: '.js', - ...opt, - }; - + const { minify = true, ext = '.js' } = opt; const min = minify ? '.min' : ''; return { ...cjsBundleForUAParser(), external: externalDeps, - output: [ - { - format: 'es', - file: `dist/ua_parser.es${min}${ext}`, - plugins: minify ? [terser()] : undefined, - sourcemap: true, - }, - ], + output: { + format: 'es', + file: `dist/ua_parser.es${min}${ext}`, + sourcemap: true, + minify, + }, }; }; +const jsonSchemaBundle = { + input: './.build/utils/json_schema_validator/index.js', + output: { + exports: 'named', + format: 'cjs', + strict: true, + file: 'dist/optimizely.json_schema_validator.min.js', + sourcemap: true, + minify: true, + }, + transform, + platform: rolldownPlatformFor('neutral'), + resolve: resolveForPlatform('neutral'), + external: ['json-schema'], +}; + const umdBundle = { - plugins: [ - aliasPlugin, - resolvePluginBrowser, - commonjs(), - ], - input: '.build/index.browser.js', + input: './.build/index.browser.js', output: [ { name: 'optimizelySdk', format: 'umd', + strict: true, file: 'dist/optimizely.browser.umd.js', exports: 'named', }, { name: 'optimizelySdk', format: 'umd', + strict: true, file: 'dist/optimizely.browser.umd.min.js', exports: 'named', - plugins: [terser()], + minify: true, sourcemap: true, }, ], -}; - -// A separate bundle for json schema validator. -const jsonSchemaBundle = { - plugins: [aliasPlugin, resolvePlugin, commonjs()], - external: ['json-schema'], - input: '.build/utils/json_schema_validator/index.js', - output: { - exports: 'named', - format: 'cjs', - file: 'dist/optimizely.json_schema_validator.min.js', - plugins: [terser()], - sourcemap: true, - }, + transform, + platform: rolldownPlatformFor('browser'), + resolve: resolveForPlatform('browser'), }; const bundles = { @@ -300,18 +319,15 @@ const bundles = { // Collect all --config-* options and return the matching bundle configs // Builds all bundles if no --config-* option given -// --config-cjs will build all three cjs-* bundles -// --config-umd will build only the umd bundle +// --config-cjs will build all cjs-* bundles +// --config-umd will build only the umd bundle (both the plain and minified outputs) // --config-umd --config-json will build both umd and the json-schema bundles -export default args => { - const patterns = Object.keys(args) - .filter(arg => arg.startsWith('config-')) - .map(arg => arg.replace(/config-/, '')); +const patterns = process.argv + .filter(arg => arg.startsWith('--config-')) + .map(arg => arg.replace(/^--config-/, '')); - // default to matching all bundles - if (!patterns.length) patterns.push(/.*/); +if (!patterns.length) patterns.push(/.*/); - return Object.entries(bundles) - .filter(([name, config]) => patterns.some(pattern => name.match(pattern))) - .map(([name, config]) => config); -}; +export default Object.entries(bundles) + .filter(([name]) => patterns.some(pattern => name.match(pattern))) + .map(([, config]) => config); diff --git a/scripts/run-cjs-example.js b/scripts/run-cjs-example.js index fa213d54c..60d275549 100644 --- a/scripts/run-cjs-example.js +++ b/scripts/run-cjs-example.js @@ -53,16 +53,39 @@ function runQuiet(command, cwd) { } } +// The tarball `npm pack` creates for the current package version, e.g. +// @optimizely/optimizely-sdk@6.7.0 -> optimizely-optimizely-sdk-6.7.0.tgz. +// Only this exact file is used, so a leftover archive of another version is never tested (or deleted). +function findTarball() { + const { name, version } = require(path.join(rootDir, 'package.json')); + const fileName = `${name.replace(/^@/, '').replace(/\//g, '-')}-${version}.tgz`; + const tarballPath = path.join(rootDir, fileName); + if (!fs.existsSync(tarballPath)) { + console.error(`SDK tarball ${fileName} not found. Run \`npm pack\` first.`); + process.exit(1); + } + return tarballPath; +} + function main() { + const skipBuild = process.argv.includes('--skip-build'); + console.log('=== Building SDK and Running CommonJS Example ===\n'); - console.log('Installing SDK dependencies...'); - run('npm install', rootDir); + let tarballPath; + + if (skipBuild) { + console.log('Skipping build (--skip-build), using existing tarball...'); + tarballPath = findTarball(); + } else { + console.log('Installing SDK dependencies...'); + run('npm install', rootDir); - console.log('\nPacking SDK tarball...'); - const packOutput = runQuiet('npm pack', rootDir); - const tarballPath = path.join(rootDir, packOutput); - console.log(`Created: ${packOutput}`); + console.log('\nPacking SDK tarball...'); + const packOutput = runQuiet('npm pack', rootDir); + tarballPath = path.join(rootDir, packOutput); + console.log(`Created: ${packOutput}`); + } console.log('\nInstalling SDK tarball in cjs-example...'); run(`npm install --no-save --no-package-lock ${tarballPath}`, exampleDir); @@ -72,7 +95,7 @@ function main() { console.log('\nCleaning up tarball...'); fs.unlinkSync(tarballPath); - console.log(`Removed: ${packOutput}`); + console.log(`Removed: ${path.basename(tarballPath)}`); console.log('\n=== Example completed successfully! ===\n'); } diff --git a/tests/react-native-metro/run.mjs b/tests/react-native-metro/run.mjs index 42b277502..e011d697f 100644 --- a/tests/react-native-metro/run.mjs +++ b/tests/react-native-metro/run.mjs @@ -53,7 +53,7 @@ function installSdk() { if (tarball) { tarball = path.resolve(tarball); } else { - // npm pack runs the package's prepare script (the build), as npm publish does. + // npm pack runs the package's prepack script (the build), as npm publish does. const packDir = fs.mkdtempSync(path.join(os.tmpdir(), 'rn-metro-test-')); const name = run('npm', ['pack', '--silent', '--pack-destination', packDir], REPO_ROOT).trim().split('\n').pop(); tarball = path.join(packDir, name);