- No massive breaking changes – each step should not affect large parts of the rest of the site
- Fork useful Apostrophe core modules – copy and trim rather than rewrite from scratch.
- Replace jQuery with vanilla JS – continue the “lean frontend” initiative to its conclusion.
- Adopt lighter alternatives where they provide clear benefits without disproportionate effort.
| Module | Purpose | Why Fork? | Estimated Effort |
|---|---|---|---|
apostrophe‑utils |
Logging, IDs, HTTP helpers, DOM utilities | Lightweight, already used everywhere; can be trimmed of jQuery dependencies. | Low |
apostrophe‑db |
MongoDB connection pooling, cursor helpers | Simple wrapper around native driver; easy to maintain. | Low |
apostrophe‑schemas |
Field type definitions, converters, validation | Complex but central to custom fields; fork and strip unused field types. | Medium |
apostrophe‑i18n |
Locale detection, cookie management | Already extended by apostrophe‑i18n‑content; fork and keep only needed logic. |
Low |
apostrophe‑assets |
Asset loading, pushAsset, when conditions |
Heavy; consider replacing with build‑time manifest, but fork as interim step. | High |
| File | jQuery Usage | Replacement Strategy |
|---|---|---|
widget‑editor.js (DeepL) |
$(), $.on, $.ajax |
Already uses apos.utils.post; replace remaining $ with document.querySelector. |
Widget player scripts (widget.js) |
Various $ calls |
Convert to vanilla JS using apos.utils where available. |
Admin UI scripts (user.js) |
jQuery required for Apostrophe admin | Keep jQuery for admin UI; focus on public frontend. |
- Replace
$()inajax‑utils.js– already uses vanilla DOM methods; verify no jQuery. - Audit
when: 'always'assets – change to'lean'or'user'. - Remove jQuery from widget players – one widget at a time.
- Copy
node_modules/apostrophe/lib/utils.jsand related utility files intolib/core/utils/. - Remove jQuery‑dependent functions (e.g.,
$‑based DOM helpers) or replace with vanilla equivalents. - Keep
log,generateId,get,post,emit,onReady,runPlayers. - Update module references to use local copy:
// In each module var utils = require('../core/utils'); // Instead of self.apos.utils
- Create a shim that delegates
self.apos.utilsto the forked version.
- Decouples from Apostrophe version.
- Allows us to improve utilities without waiting for upstream updates.
- Audit all
public/jsfiles for$orjQueryusage. - Replace each occurrence with vanilla JS or
apos.utilsequivalent.$(selector)→document.querySelector/document.querySelectorAll$.on→addEventListener$.ajax→apos.utils.get/post$.closest→apos.utils.closest
- Test each widget as anonymous user (no jQuery loaded).
- Remove jQuery from lean bundle – ensure
apostrophe‑assetsconfiglean: truealready excludes jQuery.
- Reduces public page weight by ~30 KB (jQuery removed).
- Aligns with modern JavaScript practices.
- Copy relevant files from Apostrophe’s
lib/modules/apostrophe‑dbandapostrophe‑schemas. - Trim schemas to only support field types we use (
string,boolean,select,color,multilingual‑string, etc.). - Replace any internal use of
self.apos.utilswith our forked utils. - Update module definitions to extend our forked base classes.
- Full control over database queries and schema evolution.
- Ability to add custom optimizations (e.g., projection hints, caching).
- Set up Vite or Webpack to bundle all
public/jsandpublic/cssassets. - Generate a manifest
public/dist/manifest.jsonmapping asset names to hashed filenames. - Create helper
assetUrl(name)used in templates. - Replace
self.pushAssetcalls with template logic that injects script/link tags based on manifest. - Keep
when: 'lean'/'user'differentiation via server‑side conditionals.
- Modern bundling (tree‑shaking, minification, code splitting).
- Eliminates runtime asset compilation overhead.
For each custom module (e.g., card‑widgets, galleries):
- Analyze dependencies on Apostrophe base classes.
- Create a lightweight alternative that implements only the methods we use.
- Run both implementations in parallel using a feature flag.
- Switch over after testing.
- Extends
apostrophe‑images‑widgets. - Uses
piecesModuleName,addFields,arrangeFields,filters. - Alternative: create a generic
Widgetclass that renders images with same template.
- Once all modules are migrated, remove
apostrophefrompackage.json. - Delete
node_modules/apostropheand any unused Apostrophe‑plugin packages. - Update
app.jsto bootstrap our own framework. - Run full regression suite.
- Parallel runs – keep old and new code side‑by‑side during transition.
- Feature flags – allow quick rollback.
- Comprehensive testing – use cdp‑cli for browser automation to detect visual regressions.
- Performance monitoring – track Lighthouse scores before/after each phase.
- Fork
apostrophe‑utils– createlib/core/utilswith trimmed utilities. - Audit and replace jQuery in one widget player (e.g.,
card‑widgets/public/js/widget.js). - Update
ajax‑utils.jsto ensure zero jQuery dependency. - Add CI step that fails if any
public/jsfile contains$(orjQuery.
This pragmatic approach allows us to incrementally replace Apostrophe components with lighter, forked versions while keeping the site live and stable. Each step delivers immediate value (reduced bundle size, better control) and builds toward a fully independent codebase.
We are not deciding “whether” to migrate—we are executing a systematic, low‑risk migration that aligns with the project’s long‑term sustainability.