diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc1377d7a..e8b0069a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -196,7 +196,6 @@ jobs: - name: Build core env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - EXOJS_FULL_BUNDLE: '1' run: pnpm build - name: Build extension packages diff --git a/README.md b/README.md index ecdb00281..ceec38644 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ npm run dev npm install @codexo/exojs ``` -ExoJS ships as ESM — use `import` syntax with a modern bundler or runtime. A prebuilt IIFE bundle (`dist/exo.iife.js`, global `Exo`) is included for CDN and script-tag usage. +ExoJS ships as ESM — use `import` syntax with a modern bundler or runtime. Prebuilt IIFE bundles are included for CDN and script-tag usage: `dist/exo.iife.js` (the core) and `dist/exo.full.iife.js` (core plus every extension except React), both on the global `Exo`. Optional packages install independently — add only what your project needs: ```bash diff --git a/package.json b/package.json index caf32fc8c..2e1ac96f5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,10 @@ "dist/exo.iife.js.map", "dist/exo.iife.min.js", "dist/exo.iife.min.js.map", + "dist/exo.full.iife.js", + "dist/exo.full.iife.js.map", + "dist/exo.full.iife.min.js", + "dist/exo.full.iife.min.js.map", "README.md", "CHANGELOG.md", "LICENSE" @@ -208,6 +212,11 @@ "limit": "340 KB", "gzip": true }, + { + "path": "dist/exo.full.iife.min.js", + "limit": "550 KB", + "gzip": true + }, { "path": "dist/exo.debug.esm.js", "limit": "5 KB", diff --git a/scripts/build.ts b/scripts/build.ts index 11f2792e6..116ef01fd 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -1,7 +1,7 @@ /** * Builds the core package: `exo.esm.js`, `exo.debug.esm.js`, the preserveModules * `dist/esm` tree (with declarations), `exo.iife.js`, and (production only) - * `exo.iife.min.js`. + * `exo.iife.min.js`, `exo.full.iife.js` and `exo.full.iife.min.js`. * * Bundling runs on Rolldown; declarations are a separate `tsc * --emitDeclarationOnly` pass over `dist/esm`, since Rolldown has no @@ -11,11 +11,14 @@ * inner dev loop this mode serves, and `pnpm typecheck` already covers type * correctness. * - * `EXOJS_FULL_BUNDLE=1` additionally builds the opt-in all-in-one IIFE bundle - * (core + every extension package), transpiling TypeScript source across - * multiple rootDirs (src/ and each extension package's src/) - Rolldown's - * built-in transpiler has no single-Program rootDir constraint, so this needs - * no separate esbuild-based path the way the previous Rollup pipeline did. + * The production build also emits the all-in-one IIFE bundle (`exo.full.iife.js` + * and its minified twin: core + every extension package except react, whose + * peer cannot ship in a script-tag bundle), transpiling TypeScript source + * across multiple rootDirs (src/ and each extension package's src/) - + * Rolldown's built-in transpiler has no single-Program rootDir constraint, so + * this needs no separate esbuild-based path the way the previous Rollup + * pipeline did. The dev build and watch mode skip it: it is the slowest job of + * the set and nothing in the inner loop reads it. */ import { spawnSync } from 'node:child_process'; import { dirname, relative as relativePath, resolve as resolvePath } from 'node:path'; @@ -227,7 +230,7 @@ if (watchMode) { } else { const jobs = buildMode === 'production' - ? [bundled(true), debugBundled(true), modules(), iife(false), iife(true)] + ? [bundled(true), debugBundled(true), modules(), iife(false), iife(true), fullBundle(false), fullBundle(true)] : [bundled(true), debugBundled(true), modules(), iife(false)]; for (const job of jobs) { @@ -235,11 +238,4 @@ if (watchMode) { } await emitDeclarations(); writeSourceStamp(resolvePath(rootDir, 'src'), resolvePath(rootDir, 'dist')); - - if (process.env.EXOJS_FULL_BUNDLE === '1') { - const fullBundleJobs = buildMode === 'production' ? [fullBundle(false), fullBundle(true)] : [fullBundle(false)]; - for (const job of fullBundleJobs) { - await runJob(job); - } - } } diff --git a/scripts/release/full-zip.ts b/scripts/release/full-zip.ts index a59310484..6ad889070 100644 --- a/scripts/release/full-zip.ts +++ b/scripts/release/full-zip.ts @@ -3,8 +3,9 @@ * * A self-contained, offline-servable snapshot of a coordinated release: * - * npm/ the four official tarballs (Core, Particles, Tilemap, Tiled) - * vendor/ each package's ESM tree (exojs, exojs-particles, exojs-tilemap, exojs-tiled) + * npm/ every lockstep tarball (Core + extensions) + * vendor/ every lockstep package's ESM tree, plus Core's single-file + * bundles (exo.esm.js, the IIFE pair, the full IIFE pair) * examples/ src/** (TS), js/** (transpiled), assets/**, examples.json * site/ the built static site (itself servable; references ./vendor + ./examples) * README.md CHANGELOG.md LICENSE release-manifest.json checksums.sha256 @@ -18,6 +19,7 @@ import { basename, dirname, join, relative, resolve } from 'node:path'; import { ModuleKind, ScriptTarget, transpileModule } from 'typescript'; import type { CommandRunner } from './command-runner.ts'; +import { LOCKSTEP_PACKAGES } from './lockstep-packages.ts'; import { type ReleaseManifest, renderChecksums, serializeManifest, sha256File } from './manifest.ts'; export interface AssembleOptions { @@ -32,15 +34,30 @@ export interface AssembleOptions { manifest: ReleaseManifest; } -const VENDOR_PACKAGES = [ - { name: 'exojs', vendorDir: 'exojs' }, - { name: 'exojs-particles', vendorDir: 'exojs-particles' }, - { name: 'exojs-tilemap', vendorDir: 'exojs-tilemap' }, - { name: 'exojs-tiled', vendorDir: 'exojs-tiled' }, - { name: 'exojs-physics', vendorDir: 'exojs-physics' }, - { name: 'exojs-audio-fx', vendorDir: 'exojs-audio-fx' }, +/** + * Core's single-file bundles, shipped under `vendor/exojs/` beside the ESM + * tree so the archive serves a script tag as well as an import map. The list + * mirrors the bundle entries of the root `package.json#files`; the test suite + * pins the two together. + */ +export const CORE_BUNDLE_FILES = [ + 'exo.esm.js', + 'exo.esm.js.map', + 'exo.debug.esm.js', + 'exo.debug.esm.js.map', + 'exo.iife.js', + 'exo.iife.js.map', + 'exo.iife.min.js', + 'exo.iife.min.js.map', + 'exo.full.iife.js', + 'exo.full.iife.js.map', + 'exo.full.iife.min.js', + 'exo.full.iife.min.js.map', ] as const; +/** `vendor/