Repository navigation
Conversation
The Dockerfile builds the frontend in its own stage and the Rails image keeps the pristine build. bin/with_static_shell, which the entrypoint now runs (inside chamber, because ASSETS_HOST comes from there), makes the copy Rails serves with ASSETS_HOST substituted in, puts the hashed files in public/assets, and sets STATIC_SHELL_DIR. Rails can then serve the whole frontend without nginx or a CDN in front of it. The middleware that kept the unhashed data-mode entry files uncached, and the list it read, go with the build that needed them. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…12260) The nginx image is now the assets stage of the main Dockerfile, built from the same frontend stage as the Rails image so the two always carry the same build, and it replaces the data-mode assets image under the same name. CI builds it on every push (on main it layers on the last release's image, so the previous release's files stay available for the retention period), smoke-tests both images with and without ASSETS_HOST, and checks that Rails serves the hashed files. The release tags one image instead of two. The assets bucket workflow now uploads the framework build's assets/ (with ASSETS_HOST substituted in) instead of packs/, and, in its publish phase, marks the files under packs/ obsolete so that tabs open on an 8.x release can load them until the bucket's retention runs out. The bundle size and GraphQL document checks read the framework build, and CI keeps checking the generated routes in the TypeScript job. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…12260) The printable reports and the CMS layout preview loaded /packs/application-styles.js, which only the data-mode build makes. They now link the stylesheets the shell's index.html links, which StaticSpaShell reads. Without a shell (in development) they go unstyled, until the reports move into the SPA (#12322). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The deployment guide now says that Rails serves the frontend itself and nginx is optional, that intercode-assets is the new name of the framework-mode image (and what it was before 9.0.0), and that both containers use ASSETS_HOST to build what they serve. The staged rollout guide gets a note on what 9.0.0 changes for it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Temporary: delete this file before merging the branch. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…part of #12260) SessionsController, PasswordsController and RegistrationsController rendered the data-mode shell for the sign-in, sign-up and password pages, which loads packs/application.js. CI used to hide that by also building the data-mode bundle into the image; with that gone, sign-in broke. They now serve the static shell when there is one (render_spa_shell). The upload script tests drop the deleted packs script and cover UPLOAD_INDEX=false and marking packs/ obsolete, and the CI check of Rails serving assets waits for the container to make public/assets before it looks. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UKBUsy46smVMUGFsNFhy1B
Contributor
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #12260 (the cutover half of the plan). Draft, not to be merged until there is a safe window to release it: CI only builds images for pushes to
main, so merging this stopsmainfrom being releasable as 8.x. Merge it when the next release is v9.0.0. Needs themajorlabel (done).What changes
The Rails image carries the frontend.
Dockerfilehas afrontendstage (yarn build:framework) and the Rails image keeps the pristine build inbuild/framework/client.bin/entrypoint.shrunsbin/with_static_shell(insidechamber exec, sinceASSETS_HOSTcomes from there). It copies the build, substitutesASSETS_HOST(or same-origin for none), puts the hashed files inpublic/assetsand setsSTATIC_SHELL_DIR. Rails then serves the whole frontend itself, so nginx or a CDN in front is optional.Access-Control-Allow-Origin: *and the 180-day cache it already used for files inpublic. The middleware that kept the unhashed data-mode entry files uncached (Intercode::DisableCachingForSpecificAssets,config/nocache-files.json) is removed with the build that needed it.The assets image is
intercode-assets, built from the same stage.assetstarget of the mainDockerfile(nginx, same front server config as before;docker-assets-framework/is nowdocker-assets/).Dockerfile.assets,Dockerfile.assets-framework,nginx-assets.confandgenNginxNocache.jsare gone.intercode-assets:latest, so the previous release's files stay for 30 days. TheBUILD_FRAMEWORKgate is gone.intercodeandintercode-assets(one image, not two).Buckets.
upload-assets-to-bucket.yml(theASSETS_BUCKETbehindASSETS_HOST) now uploads the framework build'sassets/, withASSETS_HOSTsubstituted, instead ofpacks/. It needs a new repository variableASSETS_HOST(set it toassets.neilhosting.netbefore the release; the workflow fails early without it).packs/obsolete, so the bucket's lifecycle rule expires the 8.x files after the retention period. A tab left open on an 8.x release can load its chunks until then. (This is what makes "stale tabs" a non-issue for the Rails-served domains.)The Devise pages.
SessionsController,PasswordsControllerandRegistrationsControllerrendered the data-mode shell (layout: "application", which loads/packs/application.js) for sign-in, sign-up and password reset. They now callrender_spa_shell, which serves the static shell when there is one. CI's authentication system tests found this: withoutpacks/in the image, signing in broke.Print reports and the CMS layout preview take their stylesheet from the shell's
index.html(StaticSpaShell.stylesheet_hrefs) instead of/packs/application-styles.js. They go unstyled in development until the reports move into the SPA (#12322).Checks. The bundle size check and the GraphQL document check read the framework build. CI's system tests run once, against the static shell, as production does. CI builds both images and smoke-tests them (see below).
Docs. The deployment guide, the compose example and a note in the staged rollout guide.
What this deliberately does not do
The plan also had this PR delete
AppRouter.tsx,lazyRoute, the route generator andyarn routes:check, and makeyarn startrun the framework dev server. I left that out and it can follow in a separate PR (or go with #12261):packs/.Host(intercode.test), so convention subdomains wouldn't work, and the seeded OAuth redirect URIs point at the data-mode dev server (:3135). That deserves its own design, and keeping it out of this diff keeps the release-critical part small.Also still there for #12261:
cdn_spa_shell, the oldapplication_entry_script_tag,checkAppEntrypointHeadersMatch.ts(it already does nothing in framework mode), the dev-only GraphiQL entry.Tested
ASSETS_HOSTsubstituted into the shell andpublic/assets(no placeholder left), with and without a host; Rails served/assets/<hash>.csswith CORS and the long cache; the fulldeploycompose example (schema load, migrate, Rails, nginx) on those images: Rails serves the shell directly, crawlers get the Open Graph document, nginx proxies/client_configuration.RAILS_SERVE_STATIC_FILESand fetches an asset, and tests the Devise pages with and without a static shell. All of CI is green.ts:check(typegen couldn't run in my environment, so it used the existing generated types), the new Ruby tests,check-graphql-documentsand the bundle size check (348 KB against the 700 KB budget) on the framework build.Not tested
packs/marking. Thepacks/marking changes real objects in the production bucket on the first release.with_static_shellunderchamber execwith the realASSETS_HOST. That is what the canary is for.Canary (temporary
fly.canary.toml, delete before merging)A second Fly app running this branch's web process against production, for
w.interconlarp.org.intercode-chamberrole only trustsnew-england-interactive-literature:intercode:*(the app name is part of the OIDC subject), so the canary can't read its secrets untilnew-england-interactive-literature:intercode-canary:*is added to the trust policy'ssubcondition.ASSETS_HOST=assets.neilhosting.netfrom chamber, so its shell points at the assets bucket: upload this branch'sassets/there first (additive; it touches nothing underpacks/). Build with the same arguments as the Fly build (fly.canary.tomlhas them) so the hashed names match, then verify (below).fly apps create intercode-canary, thenfly deploy -c fly.canary.toml --remote-only.fly certs add w.interconlarp.org -a intercode-canary), lower the DNS TTL beforehand, and pointwat the canary. Roll back by pointing it back./assets/file the canary's shell names exists on the assets host, then watch Sentry, Rollbar and the logs.Rebase this branch on the released
mainbefore deploying the canary, so it never runs ahead of the production schema.🤖 Generated with Claude Code
https://claude.ai/code/session_01UKBUsy46smVMUGFsNFhy1B