Added ghost-cdn-url meta tag and fixed ././ build output#26555
Added ghost-cdn-url meta tag and fixed ././ build output#26555
Conversation
WalkthroughThe pull request introduces a CDN URL propagation mechanism and adjusts Ember admin asset loading. In the admin index file, a meta tag reads a CDN URL on load, finds Ghost admin metadata, decodes its JSON content, sets the cdnUrl property, re-encodes the data, and updates the meta tag. Additionally, the Vite Ember assets plugin is modified to read the admin index.html from the Ember build output directory instead of the Ghost admin built path, with a new constant introduced for the Ember distribution directory. 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
The ghost-cdn-url meta tag and bridge script enable deploy-time CDN URL injection via a single sed command. The bridge script propagates the CDN URL into Ember's config meta tag before Ember boots — no-op when empty. Also fixed vite-ember-assets plugin reading from the combined output directory (built/admin/) instead of the Ember dist, which caused ././ path prefixes to accumulate on repeated builds. Now reads from ghost/admin/dist/ directly and produces clean ./assets/ paths.
306170c to
e5a2df9
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/admin/index.html (1)
17-30: Guard decode/parse to avoid hard failure on malformed meta content.If the env meta tag is ever malformed (e.g., partial rewrite),
decodeURIComponent/JSON.parsewill throw and can stop the script. A small guard keeps the boot resilient.🔧 Suggested defensive guard
(function() { var c = document.querySelector('meta[name="ghost-cdn-url"]'); if (c && c.content) { var m = document.querySelector('meta[name="ghost-admin/config/environment"]'); if (m) { - var d = JSON.parse(decodeURIComponent(m.content)); - d.cdnUrl = c.content; - m.content = encodeURIComponent(JSON.stringify(d)); + try { + var d = JSON.parse(decodeURIComponent(m.content)); + d.cdnUrl = c.content; + m.content = encodeURIComponent(JSON.stringify(d)); + } catch (e) { + // no-op: keep original content if malformed + } } } })();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/admin/index.html` around lines 17 - 30, Guard the decode/parse of the env meta content to avoid hard failures: in the inline IIFE that queries meta elements (variables c and m) and reads m.content, validate m.content is present and wrap the decodeURIComponent + JSON.parse steps in a try/catch (or conditional check) so malformed or empty content is skipped; only set d.cdnUrl and update m.content if parsing succeeds, and log or silently ignore parse errors to keep the boot resilient.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@apps/admin/index.html`:
- Around line 17-30: Guard the decode/parse of the env meta content to avoid
hard failures: in the inline IIFE that queries meta elements (variables c and m)
and reads m.content, validate m.content is present and wrap the
decodeURIComponent + JSON.parse steps in a try/catch (or conditional check) so
malformed or empty content is skipped; only set d.cdnUrl and update m.content if
parsing succeeds, and log or silently ignore parse errors to keep the boot
resilient.
| <meta name="ghost-cdn-url" content=""> | ||
| <script> | ||
| (function() { | ||
| var c = document.querySelector('meta[name="ghost-cdn-url"]'); |
There was a problem hiding this comment.
Where are we setting the ghost-cdn-url meta tag?
There was a problem hiding this comment.
So it works, but its kind of backwards for now.
We build with GHOST_CDN_URL which puts the value in ember's meta config (URL encoded). ghost-cdn-url is empty by default, so the bridge leaves the ember meta config alone.
If we set ghost-cdn-url by doing the string replacement, this overrides the existing build value.
The string replacement takes place during deploy depending on the environment we're deploying to: https://github.com/TryGhost/Ghost-Moya/pull/135
A different approach might be to move the GHOST_CDN_URL handling to this new meta tag and overwrite it with the replacement. Then ghost-cdn-url becomes the source-of-truth.
Summary
<meta name="ghost-cdn-url">tag and bridge script toapps/admin/index.htmlthat propagates a CDN URL into Ember's config meta tag at runtimevite-ember-assetsplugin reading from the combined output directory instead of the Ember dist, which caused././assets/path prefixes to accumulate on repeated buildsBackground
Ghost(Pro) currently bakes absolute CDN URLs into the admin build at CI time via
GHOST_CDN_URL, then string-replaces them per environment at deploy time. The newcd.ymlflow (Ghost-Moya #135, merged) replaces this with a simpler approach: build once with relative paths, then rewrite onlyindex.htmlat deploy time withsed. A meta tag provides the CDN URL to Ember's runtime config, and static asset refs are rewritten to point at the CDN.This PR adds the meta tag infrastructure. It's a no-op until a relative-path artifact is deployed through
cd.yml.Details
ghost-cdn-url meta tag: The bridge script reads the meta tag's
contentattribute and, if non-empty, injects the value into Ember's URL-encoded config meta tag ascdnUrl. Whencontent=""(self-hosted, local dev, current CI), the script does nothing. The tag only becomes active after a deploy-timesedpopulates it with a CDN URL.././ fix: The
vite-ember-assetsplugin was reading Ember asset paths fromghost/core/core/built/admin/index.html— the combined output directory that gets overwritten by the plugin's owncloseBundlehook. On each build, paths that already had./got another./prepended. Now reads fromghost/admin/dist/index.html(the Ember build's own output), producing clean./assets/paths. This is necessary for thesedreplacement to work with a single consistent pattern.