Skip to content

Extracted shared vite config helper for public UMD apps#28976

Merged
9larsons merged 8 commits into
mainfrom
public-app-vite-shared-config
Jun 29, 2026
Merged

Extracted shared vite config helper for public UMD apps#28976
9larsons merged 8 commits into
mainfrom
public-app-vite-shared-config

Conversation

@9larsons

@9larsons 9larsons commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Extracts a shared publicAppViteConfig factory at apps/_shared/vite-public-app.mjs, then migrates all 6 public UMD apps onto it. Pure refactor: bundle output byte-identical to current main (verified post-rebase against #28974). Total vite-config code shrinks from ~360 → ~150 lines.

Now rebased onto main after #28973 and #28974 merged. The 4 apps #28974 set sourcemap: false for pass that through as a top-level helper arg (sourcemap: false).

How the helper carves up "common" vs "per-app"

Helper covers what every app shares — logLevel, clearScreen, outDir, the lib block (entry, formats, name, fileName from packageName), build.{emptyOutDir,reportCompressedSize,minify}, optional i18n locale glob, baseline test block.

Per-app divergence flows through an overrides slot that's deep-merged via Vite's mergeConfig (appends plugin arrays, deep-merges objects, override-wins primitives). First-class knobs cover the dimensions that legitimately vary:

  • framework: 'react' | 'preact'
  • svgr: boolean
  • libFormat: 'umd' | 'iife'
  • libName (e.g. 'GhostAdminToolbar' for admin-toolbar's IIFE global)
  • sourcemap (false for 5 of 6 post-Removed sourcemap generation for four public apps #28974), cssCodeSplit
  • i18nNamespace (4 of 6 apps wire a locale glob)

Plugin imports are dynamic (await import(...) inside the factory) so apps can opt out of deps they don't use — admin-toolbar uses Preact and never installs @vitejs/plugin-react.

Per-app config shrink

App Before After Real divergence in overrides
admin-toolbar 30 10 (just args — Preact, IIFE, no svgr)
announcement-bar 38 13 test.setupFiles
portal 62 33 cssInjectedByJsPlugin, REACT_APP_VERSION, manualChunks, coverage
sodo-search 56 33 dedupe, assetFileNames=main.css, setupFiles
signup-form 78 35 VITESEGFAULT, preview, optimizeDeps, CI threads
comments-ui 96 48 strip-fingerprint, React-17 dedupe/alias, tiptap inline test deps
total 360 172

Verification

  • Byte-identical bundles to current main (post-Removed sourcemap generation for four public apps #28974) for all 6 apps — verified via sha256sum over emitted umd/* after rebuilding both states.
  • All unit test suites green (pre-rebase, unchanged in scope): admin-toolbar 20/20, announcement-bar 1/1, portal 582/583, sodo-search 11/11, comments-ui 251/251. signup-form has no unit suite (only test:acceptance).
  • Lint clean across all 6.
  • App version bumps included in the final commit: all 6 apps patch-bumped (vite.config changes trigger the bump CI check).

Notes

  • Helper at apps/_shared/ (underscore-prefix = not a published workspace package).
  • Helper is .mjs + JSDoc (not .ts) to avoid an import-edge case with the 4 .mjs callers and 2 .mts callers.
  • Plugin arrays in overrides get appended after base plugins (reactPlugin(), svgrPlugin()); confirmed no order-sensitive output drift via byte-diff (portal's cssInjectedByJsPlugin operates at the render hook, not transform — order doesn't matter).
  • comments-ui dropped its unused multi-format fileName function (formats only contains 'umd'; helper default produces the same comments-ui.min.js).

Test plan

  • CI: app-version-bump check passes
  • CI: all unit + acceptance test suites green
  • Smoke-test the dev gateway flows in pnpm dev (portal sign-in, comments-ui post, sodo-search query)

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 28e59e91-13e2-4736-8f5f-290512a6a09e

📥 Commits

Reviewing files that changed from the base of the PR and between ff5dc21 and 8772484.

📒 Files selected for processing (13)
  • apps/_shared/vite-public-app.mjs
  • apps/admin-toolbar/package.json
  • apps/admin-toolbar/vite.config.mjs
  • apps/announcement-bar/package.json
  • apps/announcement-bar/vite.config.mjs
  • apps/comments-ui/package.json
  • apps/comments-ui/vite.config.mts
  • apps/portal/package.json
  • apps/portal/vite.config.mjs
  • apps/signup-form/package.json
  • apps/signup-form/vite.config.mts
  • apps/sodo-search/package.json
  • apps/sodo-search/vite.config.mjs

Walkthrough

A new shared Vite configuration factory publicAppViteConfig(opts) is added to apps/_shared/vite-public-app.mjs. It builds a base Vite config covering log level, plugin installation (React/Preact and SVGR via dynamic imports), UMD/IIFE build output, minification, sourcemaps, CSS splitting, i18n locale glob wiring via commonjsOptions, and jsdom test defaults, then deep-merges caller-supplied overrides. Six public app Vite configs (admin-toolbar, announcement-bar, comments-ui, portal, signup-form, sodo-search) are rewritten to delegate to this factory, removing duplicated inline configuration. Each migrated app's package.json version is incremented.

Possibly related PRs

  • TryGhost/Ghost#27873: Modifies comments-ui CommonJS locale glob bundling, which is now centralized in the new publicAppViteConfig factory.
  • TryGhost/Ghost#28973: Edits the same public app vite.config files (portal, announcement-bar, sodo-search, admin-toolbar) by removing dead server/preview config and changing entry points.
  • TryGhost/Ghost#28974: Disables source maps for announcement-bar, comments-ui, signup-form, and sodo-search — behavior preserved through the sourcemap option in this refactor.

Suggested reviewers

  • acburdine
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: extracting a shared Vite config helper for public UMD apps.
Description check ✅ Passed The description is detailed and clearly matches the refactor to a shared publicAppViteConfig helper across the public apps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch public-app-vite-shared-config

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Base automatically changed from public-app-vite-config to main June 29, 2026 21:13
@nx-cloud

nx-cloud Bot commented Jun 29, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit 8772484

Command Status Duration Result
nx run-many --target=build --projects=tag:publi... ✅ Succeeded 1s View ↗
nx run-many -t test:unit -p @tryghost/admin-too... ✅ Succeeded 1m 7s View ↗
nx run @tryghost/comments-ui:test:acceptance ✅ Succeeded 48s View ↗
nx run-many -t lint -p ghost-monorepo,@tryghost... ✅ Succeeded 24s View ↗
nx run @tryghost/signup-form:test:acceptance ✅ Succeeded 11s View ↗
nx run @tryghost/admin:build ✅ Succeeded 5s View ↗
nx run ghost:build:assets ✅ Succeeded 2s View ↗
nx run ghost:build:tsc ✅ Succeeded 6s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-06-29 21:46:42 UTC

9larsons added 8 commits June 29, 2026 16:38
no ref

Each of the 6 public UMD apps (portal, comments-ui, sodo-search,
announcement-bar, signup-form, admin-toolbar) hand-rolled ~90% of the
same vite config: outDir, lib block, optional i18n locale glob,
baseline plugins, test config. Drift had crept in across them
(plugin order, define entries, test setup keys, NODE_ENV resolution).

`publicAppViteConfig` lives at apps/_shared/vite-public-app.mjs and
takes the dimensions that legitimately vary per app
(framework='react'|'preact', svgr, libFormat, sourcemap, cssCodeSplit,
i18nNamespace, libName) plus an `overrides` slot that flows through
Vite's `mergeConfig` for anything app-specific (extra plugins,
resolve.dedupe, rollupOptions.output, preview block).

Plugin imports are dynamic so apps can opt out of dependencies they
don't use (admin-toolbar runs Preact and never installs
@vitejs/plugin-react).

Followup commits migrate each of the 6 apps onto this helper,
byte-diff gated against the bundle output on origin/main.
no ref

Replaced the hand-rolled 30-line vite.config.mjs with a 10-line call
to publicAppViteConfig. Behavior is unchanged: IIFE format, Preact
runtime, no SVGR, sourcemap off.

Verified: emitted umd/admin-toolbar.min.js is byte-identical to the
PR1 baseline.
no ref

Replaced the 38-line vite.config.mjs with a 13-line call to
publicAppViteConfig. All defaults (React, SVGR, UMD, sourcemap on,
cssCodeSplit on) apply; only `test.setupFiles` passes through
overrides.

Verified: emitted umd/announcement-bar.min.js + .map byte-identical
to baseline.
no ref

Replaced the 56-line vite.config.mjs with a 33-line call to
publicAppViteConfig. Per-app divergence flows through overrides:

- `cssCodeSplit: false` (sodo-search emits a single CSS file)
- `i18nNamespace: 'search'` wires the locale glob
- `resolve.dedupe: ['@tryghost/debug']`
- `build.rollupOptions.output.assetFileNames` keeps the CSS sibling
  named umd/main.css (theme templates reference it by that name; see
  ghost/core defaults.json → sodoSearch.styles)
- `test.setupFiles` for the per-app jsdom setup

Verified: emitted umd/sodo-search.min.js + main.css + map are
byte-identical to baseline.
no ref

Replaced the 62-line vite.config.mjs with a 33-line call. Per-app
divergence in overrides:

- `i18nNamespace: 'portal'`
- `cssCodeSplit: false` (portal emits a single CSS file)
- `plugins: [cssInjectedByJsPlugin()]` — inlines CSS into the JS
  bundle (appended after react+svgr; plugin operates at the render
  hook, not transform, so order doesn't change output)
- `define.REACT_APP_VERSION` from npm_package_version
- `resolve.dedupe: ['@tryghost/debug']`
- `build.rollupOptions.output.manualChunks: false`
- `test.setupFiles` + `test.coverage.reporter`

Verified: emitted umd/portal.min.js + map byte-identical to
baseline.
no ref

Replaced the 78-line vite.config.mts with a 35-line call. Per-app
divergence in overrides:

- `i18nNamespace: 'signup-form'`
- `define.VITEST_SEGFAULT_RETRY` (vitest segfault retry env var)
- `preview` block (still consumed by the dev:test script)
- `optimizeDeps.include` ('@tryghost/i18n', '@tryghost/debug')
- `resolve.dedupe: ['@tryghost/debug']`
- `build.rollupOptions.output: {}` (empty, preserved for parity)
- `test` extras: `include`, env-driven `testTimeout`, CI thread caps

Verified: emitted umd/signup-form.min.js + map byte-identical to
baseline.
no ref

Last of the 6 public apps onto publicAppViteConfig. The 96-line
vite.config.mts shrinks to 48 lines. Per-app divergence in overrides:

- `plugins: [stripFingerprintingPlugin()]` — Safari 26+ / DDG
  tracker mitigation for ProseMirror/tiptap
- `define.VITEST_SEGFAULT_RETRY`
- `preview` block (dev:test still uses `vite preview --port 7175`,
  takes the override on port but inherits host/allowedHosts)
- `server` block (port 5368)
- `resolve.dedupe + alias` for React-17 hoist-avoidance (load-bearing)
- `i18nNamespace: 'comments'`
- `build.rollupOptions.output: {}` (empty, preserved)
- `test.setupFiles` + `test.include` + `test.server.deps.inline`
  (the tiptap/headlessui inline rule that keeps Vite's alias applying
  to their React imports)
- `test.testTimeout` from env + CI thread caps

The unused multi-format `fileName` function dropped — formats only
contains 'umd', the helper's default fileName produces the same
`comments-ui.min.js` output.

Verified: emitted umd/comments-ui.min.js + map byte-identical to
baseline.
no ref

The helper-based vite.config in each of the 6 public apps triggers
the app-version-bump CI check. MAJOR.MINOR unchanged across all six,
so ghost/core/core/shared/config/defaults.json does not need updates.

- admin-toolbar:    0.1.10 → 0.1.11
- announcement-bar: 1.1.27 → 1.1.28
- comments-ui:      1.5.21 → 1.5.22
- portal:           2.69.14 → 2.69.15
- signup-form:      0.3.33 → 0.3.34
- sodo-search:      1.8.30 → 1.8.31
@9larsons 9larsons force-pushed the public-app-vite-shared-config branch from e8e7f4e to 8772484 Compare June 29, 2026 21:42
@9larsons 9larsons enabled auto-merge (squash) June 29, 2026 21:48
@9larsons 9larsons merged commit b0c7e8c into main Jun 29, 2026
41 checks passed
@9larsons 9larsons deleted the public-app-vite-shared-config branch June 29, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant