Fix DataTables CSS and sync_poller import 404ing in production - #531
Merged
Conversation
Two asset paths were broken in production builds: 1. DataTables CSS. application.scss did `@import "datatables/...css"`, but Sass treats a `.css` extension as a passthrough: it does not inline the file, it emits a literal `@import url(datatables/dataTables.bootstrap5.css)` into the compiled stylesheet. That URL resolves to /assets/datatables/dataTables.bootstrap5.css, which is not in the precompile list, and production sets config.assets.compile = false -- so it 404s and DataTables renders unstyled. Serve both files from public/ via plain <link> tags instead, and delete the now-unused copies under app/assets/stylesheets/datatables/ so there is exactly one copy. Dropping the .css extension so Sass inlines it was tried and does not compile under sassc-rails (`Function rgb is missing argument $green`), because the vendored file uses rgb(var(--custom-prop)). The public/ copies are therefore raw upstream, with no unquote() Sass workaround. 2. sync_poller. assignment_controller.js and enrollments_controller.js imported it as "./sync_poller", which resolves relative to the digested module URL and yields /assets/controllers/sync_poller.js -- again never precompiled under that name. Import it as "controllers/sync_poller" so it goes through the `pin_all_from ... under: "controllers"` importmap pin and resolves to the digested asset. Verified: assets:precompile succeeds and the compiled application.css no longer contains a stray `@import url(...)`.
2 tasks
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.
Split out of #404 (admin dashboard UI), which had picked up these asset fixes incidentally. This PR carries only the asset-loading fixes so #404 can stay scoped to the admin nav.
Two things are broken in production builds
1. DataTables CSS never loads
application.scssimported the vendored stylesheets as:Sass treats a
.cssextension as a passthrough, not an inline. It does not paste the file in; it emits a literal@import url(...)into the compiled output. Confirmed by inspecting the precompiled stylesheet:That URL resolves relative to the stylesheet, i.e.
/assets/datatables/dataTables.bootstrap5.css. Nothing precompiles that path —app/assets/config/manifest.jsonly linksapplication.css, andconfig/initializers/assets.rbdoesn't add it. Production setsconfig.assets.compile = false, so there is no runtime fallback: it 404s and every DataTable renders unstyled.2.
sync_pollernever loadsassignment_controller.jsandenrollments_controller.jsimported it relatively:Under importmap the importing module is served digested (
/assets/controllers/assignment_controller-<digest>.js), so./sync_pollerresolves to/assets/controllers/sync_poller.js— undigested, and never precompiled under that name. Onlysync_poller-<digest>.jsexists on disk.The fixes
public/via plain<link>tags, and delete the now-unused copies underapp/assets/stylesheets/datatables/so exactly one copy remains.controllers/sync_poller, which goes through the existingpin_all_from "app/javascript/controllers", under: "controllers"pin and resolves to the digested asset.Why
public/and not a proper pipeline fixThe obvious fix — drop the
.cssextension so Sass actually inlines the file — does not compile undersassc-rails:libsass parses
rgb(var(--x))as a Sass function call. The oldapp/assetscopy worked around this by wrapping each such value inunquote("..."), but that is a Sass-only construct and would be invalid if the file were served directly. Thepublic/copies are therefore raw upstream, with nounquote()workaround — correct for plain-CSS serving.A comment in
application.html.erbrecords all of this so nobody "fixes" it back into the pipeline.Known trade-offs (follow-ups, not blockers)
<link>tags get no digest, so a future DataTables upgrade will serve stale bytes from browser cache until the max-age expires. The real fix is moving offsassc-rails(dartsass-sprocketshandlesrgb(var(--x))natively) — already noted as blocked on Bootstrap 5.3's deprecated@importusage in theGemfile.datatables.net-bs5(2.3.1) anddatatables.net-responsive-bs5(3.0.4) pins inconfig/importmap.rb. I could not verify the vendored copies match those exact versions — the CDN is blocked from my sandbox by network policy. Worth a manual check.Verification
rails assets:precompilesucceeds, and the compiledapplication.cssno longer contains any stray@import url(...)(0occurrences, was2).<link>targets exist underpublic/datatables/, andsync_poller-<digest>.jsis emitted.cucumber features/assignments.feature features/enrollments.feature features/navigation.feature: 5 passed, 5 failed — byte-identical to theorigin/mainbaseline (same 5 scenario IDs). No regression. All 5 are@javascriptscenarios that cannot pass in my sandbox:application.jsdoesimport "@rails/ujs", which is pinned tohttps://ga.jspm.io/..., and that CDN is blocked by network policy, so the ES module graph fails to resolve in headless Chrome and no Stimulus controller runs. These need a CI run to actually validate — that is the environment where the real behavioral fix should show up.rubocop: clean.