إنتقل إلى المحتوى الرئيسي

08 — Engineering Best Practices for a React + React Native Library Monorepo (2025–2026)

Research date: 2026-08-15. Scope: how to build, test, document, secure and publish the Rasd Forms open-core library (React web + React Native + shared core) as a pnpm/Turborepo monorepo. Facts below were verified against primary sources (release blogs, official docs, GitHub issues, pricing pages) unless flagged "unverified" or "conflict".

Summary​

  1. Platform baseline is now firmly "New Architecture + React 19 + ESM": React Native 0.82 (Oct 2025) runs only on the New Architecture; 0.85 (Apr 2026) requires Node ≥20.19.4 and moves the Jest preset to @react-native/jest-preset; 0.87 (Aug 11 2026) makes the Strict TypeScript API default, removes deep imports (react-native/Libraries/*), requires Node ≥22.13 and ships Metro 0.87 [3][5][6]. Expo SDK 56 (May 21 2026) = RN 0.85 + React 19.2; SDK 54 was the last SDK with Legacy Architecture [3][7].
  2. Ship ESM-only from Metro-friendly, extension-less .js output. react-native-builder-bob's default template dropped dual CJS/ESM in 0.40.0 (Apr 2025); Metro honours exports by default since Metro 0.82 / RN 0.79; Node 20.19+/22.12+ can require() ESM. Dual publishing now mostly creates the "dual package hazard" (two copies of React context/state) [1][2][11][39].
  3. exports map with react-native condition first, types first-within-branch, default last, plus a private "source" condition for the monorepo. When a subpath matches exports, Metro no longer expands .native.js/.ios.js extensions, so platform splitting must be done by separate packages or by pointing react-native condition targets at native entry files [1][11][38].
  4. tsup is dead; tsdown (Rolldown) is its named successor; rslib (Rspack) is a strong 0.x alternative; keep bob for RN packages (Babel-based, Hermes-safe, codegen-aware) [9][10][30].
  5. TypeScript 6.0 (Mar 23 2026) flipped defaults (strict, module: esnext, target: es2025, types: []) and deprecates baseUrl, moduleResolution: node, target: es5; TS 7 (Go port) is in preview. Adopt isolatedDeclarations now so tsdown/rslib/oxc can emit .d.ts without the type-checker; TypeDoc will feature-freeze once TS 7 ships and API Extractor has historically choked on isolatedDeclarations [8][33][34].
  6. Publish with Changesets + npm Trusted Publishing (OIDC, GA July 31 2025): no long-lived tokens, npm ≥11.5.1, Node ≥22.14, id-token: write, one trusted publisher per package, provenance auto for public repos. Beware pnpm 11.0.8 broke OIDC publish (fix PR #11526) — pin pnpm or publish via npm publish/changeset publish [12][13][14][26].
  7. Supply chain is the #1 2025–26 risk: Shai-Hulud worms (Sept and Nov 2025; 500–796 packages incl. chalk/debug) and the Nx "s1ngularity" token theft (Aug 2025). pnpm 11 (Apr 2026) defaults minimumReleaseAge=1440 min, blockExoticSubdeps=true, strictDepBuilds, allowBuilds allow-list; pair with Socket/GHSA audit, SHA-pinned Actions and Node 24 runners (default from June 16 2026) [24][25][27][36].
  8. Testing stack: Vitest 4 (Oct 22 2025; browser mode stable, toMatchScreenshot), RTL for web, RNTL v14 (Jun 5 2026; React ≥19, RN ≥0.78, async render), Storybook 10 (ESM-only; @storybook/react-native v10 + @storybook/react-native-web-vite), Playwright for web E2E, Maestro for RN E2E (Expo's documented EAS Workflows tool; Detox 20 covers RN 0.77–0.84 but treats Expo as community-only) [15][16][17][18][19][20].
  9. Lint/format: ESLint 9 flat config + typescript-eslint v8 (projectService) remains necessary for eslint-plugin-react-hooks compiler rules and jsx-a11y; Biome 2.5 (Jun 2026, 500+ rules, plugin code-fixes) is a fast formatter/first-pass linter but not a full replacement yet [23].
  10. Docs: Docusaurus 3.10 (Apr 2026, last 3.x, future.v4 flag) is the safe multi-locale/RTL choice; Fumadocs if docs live in a Next.js app; Mintlify Starter is $0 (5 editors, custom domain) with Pro "custom" pricing per the live pricing page — third-party blogs quote historic $250–300/mo Pro (conflict) [21][37][41].

1. Platform baseline (what Rasd Forms must target)​

LayerCurrent (Aug 2026)Notes for a library
React19.2 (Oct 2025), patch 19.2.8 (Jul 21 2026) [40]Activity, useEffectEvent, owner stacks. No React 20 announced.
React Native0.87 (Aug 11 2026); 0.85 (Apr 7 2026); 0.83 (Dec 2025, React 19.2); 0.82 (Oct 8 2025, New Arch only) [3][4][5][6]0.87: Strict TS API default, deep imports removed (opt-out via customConditions: ["react-native","react-native-legacy-deep-imports"] until 0.88), Node ≥22.13, Metro 0.87, AGP 9, experimental SwiftPM. 0.85: Node ≥20.19.4, @react-native/jest-preset, StyleSheet.absoluteFillObject removed. 0.82: uncaught promise rejections now console.error (relevant to sync engines).
ExpoSDK 56 stable May 21 2026 (RN 0.85, React 19.2, TS 6 support, import.meta on, expo-sqlite ArrayBuffer/blob + session changesets); SDK 55 (Feb 2026, RN 0.83); SDK 54 (RN 0.81) last Legacy Arch [7]SDK 57 announced as minor-like, fixes Hermes V1 memory regression.
HermesV1 default from RN 0.84 (Feb 2026) [4]Avoid import.meta and top-level await in shipped code; bob docs: import.meta is a syntax error in bare Metro [1].
TypeScript6.0 (Mar 23 2026); 7.0 native preview "extremely close" [8]New defaults strict, module: esnext, target: es2025, types: [], noUncheckedSideEffectImports. Deprecated: baseUrl, moduleResolution node/classic, target es5, outFile, esModuleInterop:false.
NodeNode 22 LTS baseline: pnpm 11 ≥22, RN 0.87 ≥22.13, npm OIDC ≥22.14, RNTL 14 ^22.13 ‖ ≥24 [13][18][24]Set "engines": {"node": ">=22.13"} for tooling; runtime library code has no Node requirement.

Implication: a library launching in late 2026 can reasonably declare react ^19, react-native >=0.81 (0.79 = exports-aware Metro; 0.81/SDK 54 = last legacy) and Expo SDK ≥54, and test against 0.85/SDK 56 and 0.87.

2. Monorepo: pnpm 11 + Turborepo 2.x (vs Nx 23)​

  • pnpm 11.0 (Apr 28 2026): Node ≥22; security defaults (minimumReleaseAge: 1440, blockExoticSubdeps: true, strictDepBuilds: true, verifyDepsBeforeRun: install); allowBuilds map replaces onlyBuiltDependencies/neverBuiltDependencies; pnpm settings move from .npmrc to pnpm-workspace.yaml; native publish/dist-tag/deprecate (npm CLI fallback removed); new pnpm ci, pnpm sbom (CycloneDX/SPDX), pnpm peers check; store v11 uses SQLite; catalog: protocol for single-source versions [24][25].
  • Turborepo: 2.6 (Oct 2025), 2.7 (Dec 2025: Biome rule, Yarn catalogs, composable config), 2.8 (Jan 2026: git worktrees, agent skill, task descriptions), 2.9 (Mar 2026: up to 96% faster, deprecations for 3.0), 2.10 (Jun 24 2026: graceful shutdown, deferred input hashing, composable --affected/--filter) [31].
  • Nx: 22 (Oct 2025) recognises pnpm catalogs; 23 (Jun 2026) requires Node 22 [32][43]. Nx is heavier (plugins, inferred tasks, Nx Cloud) and was the victim of the Aug 2025 "s1ngularity" token-theft incident, which is a reminder that the build tool's own supply chain matters [27].

Verdict: pnpm workspaces + Turborepo (remote cache optional) is the lowest-ceremony choice for a ~10-package library repo; Nx only if you want generators/inferred targets and Nx Agents.

3. TypeScript configuration​

  • Base tsconfig for packages: "strict": true, "moduleResolution": "bundler" (bob explicitly warns against node16/nodenext because they break platform-specific resolution) [1], "module": "esnext", "target": "es2020" or higher for web (Hermes handles down-levelling via Babel in RN), "isolatedModules": true, "isolatedDeclarations": true, "verbatimModuleSyntax": true, "types": [] (TS 6 default) plus explicit "types": ["react","react-native"] where needed, "customConditions": ["react-native", "rasd-source"] for the monorepo source condition [1][8].
  • isolatedDeclarations forces explicit return types on exports; payoff is that tsdown/rslib/oxc-transform generate .d.ts in milliseconds without tsc [9][30][44]. Cost: API Extractor once errored on the flag ("Unknown compiler option 'isolatedDeclarations'", rushstack #4877, may be fixed in newer versions — verify before adopting) [34].
  • Turn on TS 6 now with "ignoreDeprecations": "6.0" only where needed; then trial @typescript/native-preview (TS 7) in CI as a non-blocking job [8].

4. Build tools​

ToolEngineStatus (Aug 2026)Fit for Rasd Forms
tsupesbuildREADME: "This project is not actively maintained anymore. Please consider using tsdown instead." [10]Do not start new packages on it.
tsdownRolldown (Rust)Active; npx tsdown-migrate; defaults: ESM, auto-clean, dts auto if types field, reads engines.node; unbundle: true for per-file output; workspace mode; auto exports generation; 3–10× faster than tsup per third-party benchmarks [9]Web/core/builder/storage-web packages.
rslibRspack0.x, ByteDance; ESM/CJS/UMD, isolated declarations, CSS Modules/Lightning CSS, Module Federation [30]Alternative if you need CSS pipelines or MF; watch for 1.0.
rollup + pluginsJSMature; more config; slower dtsOnly for exotic needs.
unbuildrollup/mkdistUnJS; "stub" mode nice for monoreposFine, but tsdown covers it.
react-native-builder-bob 0.40+Babel + tscDefault template ESM-only since 0.40.0 (Apr 4 2025); targets module, commonjs, typescript, codegen; supports source condition, .native.js etc. [1][2]Native packages (@rasd-forms/native, storage-sqlite).

Bob's ESM guidance to internalise [1]: named exports only (no default exports); do not use .mjs/.cjs/.mts/.cts with Metro; platform-specific extensions break Node ESM; extension-less specifiers plus .js output; do not rely on import.meta.

5. package.json exports, conditions, dual publish, tree-shaking​

Reference shape (per package):

{
"name": "@rasd-forms/react",
"type": "module",
"sideEffects": false,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"rasd-source": "./src/index.ts",
"types": "./dist/index.d.ts",
"react-native": "./dist/index.native.js",
"browser": "./dist/index.js",
"default": "./dist/index.js"
},
"./styles.css": "./dist/styles.css",
"./package.json": "./package.json"
},
"files": ["dist", "src", "!**/__tests__"],
"engines": { "node": ">=20.19" }
}

Rules verified from Metro docs, publint and bob [1][11][38]:

  • Metro checks conditions in order react-native, browser, then import/require (whichever the importing file used, never both), then default; enabled by default since Metro 0.82 (RN 0.79) with unstable_enablePackageExports still available as an escape hatch. The legacy root "react-native" field is superseded by the community condition [11].
  • Once a subpath matches exports, Metro uses the exact file — no sourceExts or .ios.js/.native.js expansion; adding exports to an existing package is a breaking change unless every prior deep import is re-listed [11].
  • publint: types first, default last, module before require, dual formats need separate .d.mts/.d.cts, prefer exports/imports browser conditions over the legacy browser field, set "sideEffects": false (or an array listing CSS/polyfill files) [38].
  • ESM-only is the 2026 default for new browser/React libraries (antfu, Feb 2025; Storybook 10 itself went ESM-only). Node 20.19+/22.12+ require(esm) removes the last CJS argument for Node consumers [39][15]. If a CJS build is unavoidable (e.g., an old Jest config), keep React-context/state singletons in a single module both builds import (bob's dual-package-hazard mitigation) [1].
  • Keep src in the tarball so the source condition and source maps work for consumers debugging Hermes stack traces.

6. peerDependencies, React 19, New Architecture, React Compiler​

  • Declare react, react-dom, react-native, and Expo modules (expo, expo-sqlite, react-native-mmkv/op-sqlite, react-native-svg, gesture-handler/reanimated for the builder) as peerDependencies with peerDependenciesMeta.optional = true for platform-only ones; pnpm 11 pnpm peers check and pnpm.peerDependencyRules help in the workspace [24].
  • Ranges: react ^19, react-dom ^19, react-native >=0.81 <1, expo >=54 (optional). Test matrix should include RN 0.81 (last legacy), 0.85 (SDK 56), 0.87 (Strict TS API — no react-native/Libraries/* imports allowed) [5][6].
  • React Compiler 1.0 (Oct 7 2025): the compiler must run on original source, so app pipelines cannot compile node_modules — libraries should precompile with babel-plugin-react-compiler (target: '17' | '18' | '19'), and add react-compiler-runtime as a dependency only if targeting <19; test with and without compilation [28][29]. Since Rasd Forms targets React 19, target: '19' and no runtime dependency; keep manual useMemo out of hot paths and mark opt-outs with "use no memo".

7. Versioning, releases and publishing​

  • Semver + Changesets (.changeset/*.md, changeset version, changeset publish, changesets/action@v1 opening the "Version Packages" PR). Fixed-versioning group for @rasd-forms/* runtime packages so react/native/core stay in lock-step; independent for tooling packages.
  • npm Trusted Publishing (OIDC) GA July 31 2025 [12][13][14]: configure per package on npmjs.com (repo + workflow filename; only one trusted publisher per package, cloud runners only); workflow needs permissions: id-token: write; npm ≥11.5.1 and Node ≥22.14; provenance is attached automatically for public repos (Phil Nash reports needing --provenance or publishConfig.provenance: true in some cases and repository.url must exactly match git+https://github.com/org/repo.git); package must be published once before a trusted publisher can be added (community-reported). Then set the package to "Require 2FA and disallow tokens".
  • pnpm caveat: pnpm 11.0.8 broke OIDC publish (404), tracked in pnpm/pnpm#11513 with fix PR #11526; until verified, run changeset publish (which shells to npm) with npm upgraded, or pin a known-good pnpm [26].
  • Conventional Commits (commitlint + husky/lefthook) mainly to auto-generate changeset summaries; Changesets remains the source of truth for versions.
  • Add LICENSE (e.g., Apache-2.0 for the open core; separate commercial LICENSE-COMMERCIAL for pro packages) and SPDX headers // SPDX-License-Identifier: Apache-2.0 enforced by an ESLint header rule or Biome plugin; run pnpm sbom and license-checker-rseidelsohn in release CI [24].

8. API docs and docs sites​

  • TypeDoc 0.28.x (typedoc-plugin-markdown for MDX output into the docs site). Risk: TypeDoc relies on TS-internal APIs; the maintainer plans a feature freeze once TS 7 ships and TS 7 support has no timeline [33]. API Extractor gives .api.md reports (great for enforcing public-API review in PRs) but had isolatedDeclarations issues [34]. Practical: TypeDoc for docs, api-extractor run --local in CI as an API-report guard, verify against your tsconfig first.
  • Docs site comparison [21][37][41]:
OptionStackProsConsCost
Docusaurus 3.10React/MDX, Rspacki18n + RTL out of the box, versioned docs, Algolia DocSearch v4/AskAI, huge ecosystem; 3.10 = last 3.x, future.v4 flagSlower dev server than Astro; opinionatedFree
FumadocsNext.jsBest if docs live in a Next.js app; OpenAPI pages; very customisableMore React/Next knowledge; i18n DIYFree
StarlightAstroFastest static output, built-in i18nNot React-native-friendly for live component demos (islands only)Free
MintlifyHostedPolished, AI assistant on paid tiersVendor lock-in; pricing page shows Starter $0 (5 editors, custom domain), Pro "custom", Enterprise; third-party posts cite historic $250–300/mo Pro (conflict — verify)$0+

For an Arabic-RTL humanitarian audience with live React demos, Docusaurus (or Fumadocs) beats Starlight/Mintlify.

9. Lint and format​

  • ESLint 9 flat config (eslint.config.js at root, per-package overrides), typescript-eslint v8 with parserOptions.projectService: true (no per-package project arrays needed in monorepos), eslint-plugin-react-hooks (v6+ ships React-Compiler-powered rules), eslint-plugin-jsx-a11y, eslint-plugin-react-native-a11y, eslint-plugin-import-x, eslint-plugin-perfectionist.
  • Biome 2.5 (Jun 5 2026): 500+ rules, cross-file linting, plugin code fixes, built-in type inference for some type-aware rules [23]. Third-party comparisons put its floating-promise coverage at ~75% of typescript-eslint and note gaps vs. framework plugins (unverified numbers). Use Biome as formatter + import organiser (Turborepo 2.7 even ships a Biome rule) and keep ESLint for React/a11y/type-aware rules; do not run two formatters.

10. Testing strategy​

LayerWebReact Native
Unit/componentVitest 4 (Oct 22 2025; browser mode stable via @vitest/browser-playwright, toMatchScreenshot, Playwright traces) + @testing-library/react + vitest-axe [17]Jest with @react-native/jest-preset (RN 0.85+) + RNTL v14 (Jun 5 2026: React ≥19, RN ≥0.78, Node ^22.13‖≥24; render/fireEvent are async, host-only queries; use v13 if React 18 must be supported) [6][18]. Vitest for RN is not the supported path — keep Jest for native packages.
StoriesStorybook 10 (ESM-only; Node 20.16+/22.19+/24+; Vitest 4 addon; sb.mock) [15]@storybook/react-native v10 on-device + @storybook/react-native-web-vite (10.4.x, Aug 2026) sharing the same stories; keep all storybook majors aligned [16]
Visual regressionChromatic (Free 5,000 snapshots/mo, Starter $179/mo 35k, Pro $399/mo 85k, OSS plan on request; TurboSnap on all plans) or self-hosted Loki / Vitest toMatchScreenshot [22][17]Storybook RN-web on Chromatic; device screenshots via Maestro
E2EPlaywright (@axe-core/playwright for a11y, offline via context.setOffline(true), PWA install/service-worker checks)Maestro (YAML flows; Expo EAS Workflows has a first-class maestro job; free CLI, paid cloud) [20]. Detox 20 supports RN 0.77–0.84 with New Arch but Expo support is community-only [19].
a11yaxe (web), RNTL accessible-name queries + react-native-a11y lint
i18n/RTLPlaywright projects with locale: 'ar' and I18nManager.forceRTL in Storybook decorators; snapshot ar/en/fr; ICU message lint
Offline/low-endPlaywright throttling + fake-indexeddb in Vitest; Android emulator with 1 GB RAM profile in Maestro on CI

11. Supply chain, security, CI​

  • Threat model (2025–26): Shai-Hulud (Sept 8 2025: chalk, debug, 500+ packages; token-stealing, self-propagating via stolen npm tokens; 2.0 in Nov 2025 with 796 packages and preinstall payloads) and Nx s1ngularity (Aug 2025, stolen publish token) [27]. Countermeasures now default in pnpm 11: minimumReleaseAge (1 day; the docs suggest 10080 = 1 week for stricter shops), minimumReleaseAgeExclude for your own scope, allowBuilds allow-list instead of dangerouslyAllowAllBuilds, blockExoticSubdeps, trustPolicy: no-downgrade [24][25].
  • CI hygiene: pin every Action to a full SHA and let Renovate bump them; permissions: contents: read by default; OIDC-only publish; GitHub runners default to Node 24 from June 16 2026 (Node 20 removed fall 2026) so use actions/checkout@v5, actions/setup-node@v5, pnpm/action-setup@v4 [36]; run zizmor (Actions linter), pnpm audit (GHSA-based in pnpm 11), Socket (or OpenSSF Scorecard) on PRs; Dependabot security alerts on, Renovate for updates (grouped, minimumReleaseAge mirror, lockfile maintenance, automerge patch after checks).
  • Repo files: SECURITY.md (private vulnerability reporting via GitHub Security Advisories), CODEOWNERS, signed commits/tags, .github/workflows/release.yml gated on environment: npm with required reviewers.
  • CI matrix: ubuntu (Node 22, 24) for lint/type/test/build/publint/attw/size-limit; Node 20.19 smoke for consumers still on RN 0.85 tooling; macOS runner only for the Expo example build/Maestro iOS; Android emulator job on ubuntu (reactivecircus/android-emulator-runner) for Maestro; TS 7 preview job allowed to fail.
  • Bundle/perf budgets: size-limit (@size-limit/preset-small-lib, andresz1/size-limit-action PR comments) with per-entry gz budgets (e.g., @rasd-forms/core ≤ 25 kB, @rasd-forms/react ≤ 60 kB, builder lazy-chunked); publint + @arethetypeswrong/cli on npm pack output; Lighthouse CI on the Vite example (PWA installable, TTI on "Moto G4" throttling) [35][38].

Comparison tables​

Monorepo/task runners

pnpm ws + Turborepo 2.10Nx 23
Node≥22 (pnpm 11)≥22
Configturbo.json(c), composable per packagenx.json, project.json/inferred
Remote cacheVercel or self-hostedNx Cloud
Catalogspnpm catalogs (Turbo 2.7 lockfile parser)pnpm catalogs (Nx 22+)
Fitsmall/medium library reposlarge polyglot orgs

RN E2E

MaestroDetox 20
SetupCLI only, YAML flowsnative integration, per-RN-version support (0.77–0.84)
Expodocumented in EAS Workflowscommunity-only
Sync modelblack-box + waitsgrey-box synchronisation
CostCLI free; cloud paidfree

Implications & recommendations for Rasd Forms​

  1. Repo layout (pnpm 11 workspaces + Turborepo 2.10):
    rasd-forms/
    pnpm-workspace.yaml # catalog: react, react-native, expo, zod, typescript...
    turbo.jsonc
    packages/
    core/ @rasd-forms/core (JSON schema types, validation, logic/skip engine, i18n runtime; framework-free; tsdown)
    react/ @rasd-forms/react (web renderer, hooks; tsdown; conditions: browser/default)
    native/ @rasd-forms/native (RN renderer; bob; peers react-native, expo?)
    builder/ @rasd-forms/builder (drag-and-drop builder, web; tsdown; lazy chunks)
    storage-web/ @rasd-forms/storage-idb (IndexedDB adapter)
    storage-native/ @rasd-forms/storage-sqlite (expo-sqlite / op-sqlite adapters; bob)
    sync/ @rasd-forms/sync (queue, conflict rules, transport)
    themes/ @rasd-forms/theme-{default,unrwa-like,...}
    license/ @rasd-forms/license (offline-verifiable token check)
    eslint-config/, tsconfig/, tsdown-config/ (internal, private)
    apps/
    docs/ (Docusaurus 3.10, ar/en, RTL) example-vite/ example-next/ example-expo/ storybook-web/
    .changeset/ .github/workflows/ SECURITY.md CODEOWNERS
  2. Module format: ESM-only, "type": "module", extension-less .js output, named exports only, sideEffects: false except CSS/theme files; add a "rasd-source" condition for in-repo dev, resolved via TS customConditions, Metro unstable_conditionNames/react-native-monorepo-config, and Vitest resolve.conditions.
  3. Platform split by package, not by extension: @rasd-forms/react (web) and @rasd-forms/native share @rasd-forms/core; a small @rasd-forms/ui facade may map react-native condition → native entry and default → web entry, but keep separate entry files because Metro will not expand .native.js inside exports.
  4. TypeScript: TS 6.0 with strict, isolatedDeclarations, verbatimModuleSyntax, moduleResolution: bundler; run TS 7 preview as an advisory CI job; no react-native/Libraries/* deep imports (breaks on RN 0.87).
  5. Build: tsdown for web/core (unbundle: true for tree-shaking-friendly per-file output, dts: { isolatedDeclarations: true }), bob for native packages (module + typescript targets, esm: true), React Compiler precompiled with target: '19'; verify each tarball with publint and attw --pack.
  6. Peers: react ^19, react-dom ^19 (web pkgs), react-native >=0.81 (native), optional expo >=54, expo-sqlite, @op-engineering/op-sqlite; test matrix RN 0.81 / 0.85 / 0.87 and Expo SDK 54 / 56.
  7. Release: Changesets fixed group; OIDC trusted publishing per package (public repo, id-token: write, npm ≥11.5.1, Node 24 runner), provenance on, tokens disallowed, publishConfig.access: public; commercial packages published to the same public scope with a license-token runtime check (per doc 06) rather than a private registry, unless the pro builder must remain source-closed (then GitHub Packages/private npm with granular tokens, no OIDC provenance).
  8. Testing: Vitest 4 (jsdom for logic, browser mode for components) + RTL + vitest-axe; Jest + RNTL 14 for native; Storybook 10 with RN-web-vite for a single story set; Chromatic Free/OSS for visual diffs (upgrade only if >5k snapshots/mo); Playwright projects for en/ar (RTL) and offline mode; Maestro flows on the Expo example on EAS Workflows or CI emulators; explicit low-end Android profile.
  9. Lint/format: Biome (format + organise imports) and ESLint 9 flat (typescript-eslint v8 projectService, react-hooks v6, jsx-a11y, react-native-a11y, license-header rule); commitlint conventional commits; lefthook pre-commit running biome check + eslint --cache on staged files.
  10. Security posture: pnpm 11 defaults kept (minimumReleaseAge 1 day, allowBuilds allow-list), Renovate with minimumReleaseAge ≥3 days and grouped RN/Expo bumps, Socket + pnpm audit, SHA-pinned Actions, zizmor, OpenSSF Scorecard badge, pnpm sbom attached to GitHub Releases, SECURITY.md with 90-day disclosure policy — this is a credibility signal for UN/NGO procurement.
  11. Docs: Docusaurus 3.10 with i18n (en, ar RTL, fr), versioned docs per minor, TypeDoc→markdown API pages, live examples via @docusaurus/theme-live-codeblock, and a "Compatibility matrix" page (RN/Expo/React/Node) regenerated from the CI matrix.
  12. Budgets: size-limit gz budgets per entry with PR comments; Lighthouse CI PWA checks; Hermes bytecode size of the Expo example tracked; performance tests for 500-question forms on Android emulator (rendering + IndexedDB/SQLite write throughput).
  13. Error-reporting hooks: expose an onError/reportError hook in @rasd-forms/core (no built-in Sentry dependency), tag errors with schema/version, and rely on RN 0.82+ behaviour that unhandled promise rejections surface as console.error — sync code must catch and route through the hook.

Sources​

  1. react-native-builder-bob — ESM support docs (GitHub docs/pages/esm.md): https://github.com/callstack/react-native-builder-bob/blob/main/docs/pages/esm.md (accessed 2026-08-15)
  2. react-native-builder-bob 0.40.0 release (ESM-only default template): https://github.com/callstack/react-native-builder-bob/releases/tag/react-native-builder-bob@0.40.0 (accessed 2026-08-15)
  3. React Native 0.82 — A New Era (Oct 8 2025): https://reactnative.dev/blog/2025/10/08/react-native-0.82 (accessed 2026-08-15)
  4. React Native blog index (0.80–0.87 dates): https://reactnative.dev/blog (accessed 2026-08-15)
  5. React Native 0.87 — Strict TypeScript API, Metro 0.87, SwiftPM, AGP 9 (Aug 11 2026): https://reactnative.dev/blog/2026/08/11/react-native-0.87 (accessed 2026-08-15)
  6. React Native 0.85 — Animation backend, @react-native/jest-preset, Node ≥20.19.4 (Apr 7 2026): https://reactnative.dev/blog/2026/04/07/react-native-0.85 (accessed 2026-08-15)
  7. Expo SDK 56 changelog (May 21 2026): https://expo.dev/changelog/sdk-56 (accessed 2026-08-15)
  8. Announcing TypeScript 6.0 (Mar 23 2026): https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/ (accessed 2026-08-15)
  9. tsdown — Migrate from tsup: https://tsdown.dev/guide/migrate-from-tsup (accessed 2026-08-15)
  10. tsup repository README (maintenance notice): https://github.com/egoist/tsup (accessed 2026-08-15)
  11. Metro — Package Exports docs: https://metrobundler.dev/docs/package-exports/ (accessed 2026-08-15)
  12. GitHub Changelog — npm trusted publishing with OIDC is generally available (Jul 31 2025): https://github.blog/changelog/2025-07-31-npm-trusted-publishing-with-oidc-is-generally-available/ (accessed 2026-08-15)
  13. npm Docs — Trusted publishing for npm packages: https://docs.npmjs.com/trusted-publishers/ (accessed 2026-08-15)
  14. Phil Nash — Things you need to do for npm trusted publishing to work (Jan 28 2026): https://philna.sh/blog/2026/01/28/trusted-publishing-npm/ (accessed 2026-08-15)
  15. Storybook 10 announcement (ESM-only): https://storybook.js.org/blog/storybook-10/ (accessed 2026-08-15)
  16. storybookjs/react-native README (v10): https://github.com/storybookjs/react-native (accessed 2026-08-15)
  17. Vitest 4.0 is out (Oct 22 2025): https://vitest.dev/blog/vitest-4 (accessed 2026-08-15)
  18. React Native Testing Library releases (v14.0.0 Jun 5 2026): https://github.com/callstack/react-native-testing-library/releases (accessed 2026-08-15)
  19. Detox — Environment setup (RN 0.77–0.84, Expo community-only): https://wix.github.io/Detox/docs/introduction/environment-setup/ (accessed 2026-08-15)
  20. Expo — E2E tests with Maestro on EAS Workflows: https://docs.expo.dev/eas/workflows/examples/e2e-tests/ (accessed 2026-08-15)
  21. Mintlify pricing: https://mintlify.com/pricing (accessed 2026-08-15)
  22. Chromatic pricing: https://www.chromatic.com/pricing (accessed 2026-08-15)
  23. Biome v2.5 — 500 lint rules, plugin code fix, cross-file linting (Jun 5 2026): https://biomejs.dev/blog/biome-v2-5/ (accessed 2026-08-15)
  24. pnpm 11.0 release notes (Apr 28 2026): https://pnpm.io/blog/releases/11.0 (accessed 2026-08-15)
  25. pnpm — Mitigating supply chain attacks: https://pnpm.io/supply-chain-security (accessed 2026-08-15)
  26. pnpm issue #11513 — OIDC publish fails on pnpm 11: https://github.com/pnpm/pnpm/issues/11513 (accessed 2026-08-15)
  27. Unit 42 — "Shai-Hulud" worm compromises npm ecosystem: https://unit42.paloaltonetworks.com/npm-supply-chain-attack/ (accessed 2026-08-15)
  28. React — Compiling Libraries (React Compiler): https://react.dev/reference/react-compiler/compiling-libraries (accessed 2026-08-15)
  29. React Compiler v1.0 (Oct 7 2025): https://react.dev/blog/2025/10/07/react-compiler-1 (accessed 2026-08-15)
  30. Rslib — Introducing Rslib: https://rslib.rs/blog/introducing-rslib (accessed 2026-08-15)
  31. Turborepo blog (2.5–2.10 release notes): https://turborepo.dev/blog (accessed 2026-08-15)
  32. Nx 23 release: https://nx.dev/blog/nx-23-release (accessed 2026-08-15)
  33. TypeDoc issue #3098 — TypeScript 7 (TS-Go) support: https://github.com/TypeStrong/typedoc/issues/3098 (accessed 2026-08-15)
  34. rushstack issue #4877 — API Extractor "Unknown compiler option 'isolatedDeclarations'": https://github.com/microsoft/rushstack/issues/4877 (accessed 2026-08-15)
  35. size-limit: https://github.com/ai/size-limit and https://github.com/andresz1/size-limit-action (accessed 2026-08-15)
  36. GitHub Changelog — Deprecation of Node 20 on GitHub Actions runners (Sept 19 2025; Node 24 default June 16 2026): https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ (accessed 2026-08-15)
  37. Docusaurus blog (3.9 Sept 25 2025; 3.10 Apr 7 2026): https://docusaurus.io/blog (accessed 2026-08-15)
  38. publint rules: https://publint.dev/rules (accessed 2026-08-15)
  39. Anthony Fu — Move on to ESM-only (Feb 5 2025): https://antfu.me/posts/move-on-to-esm-only (accessed 2026-08-15)
  40. React 19.2 (Oct 1 2025) and 19.2.8 release (Jul 21 2026): https://react.dev/blog/2025/10/01/react-19-2 ; https://github.com/react/react/releases/tag/v19.2.8 (accessed 2026-08-15)
  41. Fumadocs — Comparisons: https://www.fumadocs.dev/docs/comparisons (accessed 2026-08-15)
  42. changesets/action issue #515 — separate publish workflow for OIDC: https://github.com/changesets/action/issues/515 (accessed 2026-08-15)
  43. Nx 22 release (pnpm catalogs): https://nx.dev/blog/nx-22-release (accessed 2026-08-15)
  44. tsdown — Declaration files (dts) options: https://tsdown.dev/options/dts (accessed 2026-08-15)