Add golden-output gate for the serverWebpackConfig generator template - #4790
Conversation
Generator template output was validated only by hand-maintained string fixtures that nothing checked against the real templates, so the two drifted silently. PR #2489 is the worked example: it updated the template and one fixture and left a second fixture on the old implementation, and every spec stayed green. Pin the real rendered output. A new spec runs BaseGenerator#copy_webpack_config into a temp destination across seven variants (webpack/rspack x base/pro/rsc, plus a Shakapacker < 9 variant) and diffs each produced serverWebpackConfig.js against a checked-in golden file. Failures print a readable unified diff and the one-line regeneration command, which regenerates and then re-asserts so a green run is itself round-trip proof. Pin the drift risk on the simulation fixtures without forcing them to match byte-for-byte, since they deliberately represent older installs. Each structural anchor the Pro and RSC gsub_file transforms match on is asserted present in both the golden file and the fixture the transform is exercised against. Anchors are derived from the transforms themselves; the six that are literals inside generator methods carry an extra assertion that the duplicated copy still appears verbatim in pro_setup.rb / rsc_setup.rb. Fix the self-consistency defect reported on PR #4788: base_server_webpack_content and the legacy pre-getLoaderPath fixture both referenced serverBundleOutputPath without declaring it, so the simulated config could never have run in Node. A new test requires every output.path identifier to be declared before use. The root .gitignore carries a bare `generated` rule that would have left the golden files uncommitted and the gate dead on arrival in CI. Add a single directory negation, matching the existing root-level negation precedent. Fixes #4787 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
WalkthroughAdds golden-output coverage for ChangesGenerator golden coverage
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
Greptile SummaryThis PR adds a checked-in golden-output gate for generated server webpack configuration.
Confidence Score: 4/5The PR appears safe to merge, with two non-blocking gaps in the new gate’s structural validation and regeneration cleanup. The generated outputs and current matrix are pinned, but the scope check can accept non-nested anchors and regeneration can retain obsolete variant directories. Files Needing Attention: react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
V["Variant flags and Shakapacker version"] --> B["BaseGenerator#copy_webpack_config"]
B --> T["Temporary generated config"]
T --> C{"Matches checked-in golden?"}
G["Checked-in golden variant"] --> C
C -->|No| F["Spec failure with diff"]
C -->|Yes| A["Validate transform anchors"]
S["Simulation fixtures"] --> A
A --> P["Guard standalone Pro/RSC rewrite assumptions"]
Reviews (1): Last reviewed commit: "Add golden-output gate for the serverWeb..." | Re-trigger Greptile |
|
+ci-run-hosted |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e39c601086
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Hosted CI RequestedTriggered 9 workflow(s) for View progress in the Actions tab. |
ReviewReviewed the diff ( OverviewAdds a golden-output regression gate for Verification performed
Code quality
Minor / non-blocking
Security / performanceNo concerns — this is test-only generator-output tooling with no runtime or production code paths touched. Bugs foundNone. I could not find a correctness issue in the anchor-pinning logic, the gitignore fix, or the fixture self-consistency checks after independently cross-referencing them against the actual generator source. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb (1)
268-421: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoffNamed RSpec subjects convention not followed.
None of the examples in this file use
subject(:name); values likeactual/expected/content/identifiersare computed as inline locals in everyitblock (e.g. Lines 271-281, 404-419). Repo guideline calls for named subjects (subject(:method_result)) rather than inline locals.As per coding guidelines: "Ruby code must satisfy RuboCop, use a maximum line length of 120 characters, and use named RSpec subjects such as
subject(:method_result)."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb` around lines 268 - 421, Replace repeated inline local computations in the generator golden output specs with named RSpec subjects, such as subjects for generated output, expected golden content, fixture content, and scanned identifiers. Define each subject at the narrowest applicable describe/context scope and update the examples under the golden-output, structural-anchor, and simulation-fixture self-consistency sections to use them while preserving existing assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb`:
- Around line 268-421: Replace repeated inline local computations in the
generator golden output specs with named RSpec subjects, such as subjects for
generated output, expected golden content, fixture content, and scanned
identifiers. Define each subject at the narrowest applicable describe/context
scope and update the examples under the golden-output, structural-anchor, and
simulation-fixture self-consistency sections to use them while preserving
existing assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 491239c2-0dc4-40a6-8884-d8691f434128
⛔ Files ignored due to path filters (8)
react_on_rails/spec/react_on_rails/fixtures/generated/README.mdis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/rspack_base/config/rspack/serverWebpackConfig.jsis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/rspack_pro/config/rspack/serverWebpackConfig.jsis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/rspack_rsc/config/rspack/serverWebpackConfig.jsis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/webpack_base/config/webpack/serverWebpackConfig.jsis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/webpack_base_shakapacker8/config/webpack/serverWebpackConfig.jsis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/webpack_pro/config/webpack/serverWebpackConfig.jsis excluded by!**/generated/**react_on_rails/spec/react_on_rails/fixtures/generated/webpack_rsc/config/webpack/serverWebpackConfig.jsis excluded by!**/generated/**
📒 Files selected for processing (3)
.gitignorereact_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rbreact_on_rails/spec/react_on_rails/support/generator_spec_helper.rb
Addresses two P2 review threads on #4790. The rule-scope check compared byte offsets: rules.forEach before the Array.isArray(rule.use) guard before the css-module block. That is a proxy, and a weak one. A template refactor that CLOSES the forEach or the guard before the css-module block leaves all three tokens in the same relative order, so the check still passed while the Pro transform inserted extractLoader(rule, ...) at a point where `rule` was out of scope. The hole matters most for the simulation fixtures, which are deliberately allowed to drift from current output: a fixture could keep satisfying token order while no longer representing a structure the transform can operate on, which is the exact drift class #4787 exists to close. Replace it by running the real ProSetup transforms (add_extract_loader_to_server_config plus add_babel_ssr_caller_to_server_config) over the target and asserting the insertion point falls inside brace-matched rules.forEach and Array.isArray(rule.use) blocks. The brace scanner skips comments and string literals, which is required rather than cosmetic: the Shakapacker < 9 variant contains a template literal with ${serverBundleOutputPath} that a naive brace counter mis-matches. Verified on a restructured input with the tokens in unchanged order: the old offset check passes (1114 < 1144 < 1516) while the new check fails, reporting the insertion at 1918 against a loop spanning 1305..1434. Separately, regenerate! overwrites the current matrix but never removes directories for variants deleted or renamed in VARIANTS, and the examples enumerate only the current matrix, so a stale golden directory stayed committed and read as authoritative while nothing tested it. Assert that the on-disk golden file set exactly equals the paths derived from VARIANTS. This asserts rather than auto-deleting, so it fails loudly instead of silently removing a file someone added on purpose, and it also catches a changed bundler destination mapping. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb (1)
185-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
BABEL_CALLER_INSERTION/BABEL_CALLER_MARKERare duplicated generator literals that the byte-identical pinning example does not cover.
inline_anchorsonly selects entries with:source_file, and these two constants live outside the anchor arrays. IfProSetup#add_babel_ssr_caller_to_server_configchanges the inserted text, the pinning example stays green and the scope test fails with the misleading "could not locate the inserted extractLoader call". Consider adding them to the pinned set (or asserting both strings appear inpro_setup.rb) so drift points at the real cause.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb` around lines 185 - 189, Update the golden-output pinning coverage around BABEL_CALLER_INSERTION and BABEL_CALLER_MARKER so these generator literals are included in the pinned set or explicitly validated against ProSetup#add_babel_ssr_caller_to_server_config. Ensure changes to either inserted string fail at the actual drift location rather than only producing the downstream scope-test error.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb`:
- Around line 185-189: Update the golden-output pinning coverage around
BABEL_CALLER_INSERTION and BABEL_CALLER_MARKER so these generator literals are
included in the pinned set or explicitly validated against
ProSetup#add_babel_ssr_caller_to_server_config. Ensure changes to either
inserted string fail at the actual drift location rather than only producing the
downstream scope-test error.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: bf604e06-2090-4d75-aa43-48ec29b30000
📒 Files selected for processing (1)
react_on_rails/spec/react_on_rails/generators/generator_golden_output_spec.rb
ReviewI checked out the diff and cross-referenced the new spec logic against the actual generator source ( What this doesAdds a golden-output gate ( Verification performed
Code quality
Risk / gaps (mostly already called out by the author)
Overall this is a well-scoped, carefully verified addition to test infrastructure with no production code changes. I didn't find any functional bugs in the new spec logic. |
Batch handoff — ROR A 07-25 18:34, generator coverage + golden-outputThread Final state:
Immediate maintainer attentionNone. No blockers, no open questions. FYI / decisions madea1 (#4788) — seven new assertions covering the two rspack SSR fixes from #2489, each proven non-vacuous by removing the corresponding template line and watching it go red. Stale
a2 (#4790) — golden-output gate over 7 variants (webpack/rspack x base/pro/rsc, plus Shakapacker-8), diffed byte-for-byte against checked-in expected files, with
QA Evidence: not required. Spec-and-generator-template only, no runtime, server, or browser surface. Evidence is the generator specs plus hosted CI's generator shards. Confirmed the coverage actually executes in CI rather than only locally: Follow-ups filed (both out of scope, neither a regression from this batch):
Review surface: 21 threads across both PRs, all resolved, 0 unresolved at merge. Operational notes worth keeping:
Confidence: high. Every number above is output that was run and read. Remaining UNKNOWNs, all recorded in the PR bodies: no real rspack/webpack build executes the generated configs; the brace scanner is a pragmatic lexer rather than a JS parser; and only |
…t-policy * origin/main: (33 commits) Fix ci-required base ref for PR merge-ref checkouts (#4819) Honor response charset and reject non-2xx HTTP-served SSR bundles (#4817) [Pro] Redact RSC render-error metadata on the fetched (client-navigation) payload path (#4821) Forward-port the 17.0.1 changelog section to main (#4814) Handle selector metacharacters in renderComponent DOM IDs (#4808) [Pro] Prevent caching RSC renders with errors (#4804) Agents: trust Copilot review identities (#4807) Agents: bind fleet closeout to generated pack (#4805) Docs: ADR 0002 — Skills-in-package over MCP for agent-native DX (#4735) Scope GitHub release commands to the origin repository (#4803) Forward-port OSS npm license metadata fix (#4794) Add golden-output gate for the serverWebpackConfig generator template (#4790) Cover the rspack CSS SSR generator fixes and de-duplicate the loader path (#4788) Configure agent workflow repo policy (#4785) Forward-port gh include mixed framing from #4684 (#4784) Release: enforce one-change forward-port closeout (#4783) Forward-port multi-URL rolling-deploy seeding to main (#4782) Docs: clarify React 18 streaming without RSC (#4780) Docs: forward-port v17 upgrade and generator gate guidance (#4781) Record the final React on Rails 17.0.0 changelog (#4742) ... # Conflicts: # AGENTS.md # internal/contributor-info/release-train-runbook.md
Fixes #4787
Problem
Generator template output was validated only by hand-maintained string fixtures in
generator_spec_helper.rbthat nothing checked against the real templates. The Pro and RSC standalone upgrades do not renderserverWebpackConfig.js.tt— theygsub_filean existing base-install config, and their patterns were exercised only against those simplified fixtures. So the template could move and every spec would stay green while real user upgrades silently stopped matching.#2489 is the worked example: it updated the template and
base_server_webpack_content, and leftpro_server_webpack_contenton the old implementation. Nothing went red.What this adds
1. Golden-output gate.
spec/react_on_rails/generators/generator_golden_output_spec.rbruns the realBaseGenerator#copy_webpack_configinto amktmpdir— not a bare ERB render, so it exercises the same path a user's install takes, including the documentation-comment config and the bundler-specific destination directory. Seven variants:webpack_base--no-rspackwebpack_pro--prowebpack_rsc--rscRSCWebpackPluginrspack_base--rspackconfig/rspack/destination mappingrspack_pro--rspack --proconfig/rspack/+ Prorspack_rsc--rspack --rscRSCRspackPlugin+ import pathwebpack_base_shakapacker8--no-rspackShakapacker version detection is stubbed per variant so the golden files do not depend on whichever Shakapacker happens to be installed locally.
2. Structural anchor pinning. Per #4787's preferred option, the simulation fixtures are not forced to match golden output byte-for-byte — they intentionally represent older installs (a1 just added
legacy_base_server_webpack_content_pre_get_loader_pathfor exactly that reason). Instead, each anchor the transforms actually match on is asserted present in both the golden file and the fixture the transform is exercised against.Anchors were derived by reading the transforms, not the issue text:
ProSetup::BUNDLER_REQUIRE_PATTERNgetLoaderPathhelper / declarationProSetup::GET_LOADER_PATH_JS/GET_LOADER_PATH_DECLARATIONextractLoaderhelperProSetup::EXTRACT_LOADER_JSlibraryTargetProSetup#update_server_webpack_config_for_protarget = 'node'blockProSetup#update_server_webpack_config_for_procssLoader.options.modulesblockProSetup#add_babel_ssr_caller_to_server_configmodule.exportsshapeProSetup#update_server_config_exportsconfigureServersignatureRscSetup#update_server_webpack_config_for_rscLimitChunkCountPluginunshiftRscSetup#update_server_webpack_config_for_rscSix of these are literals inside generator methods and cannot be referenced as constants, so they are duplicated in the spec. That duplication is itself pinned: a test asserts each copy still appears verbatim in
pro_setup.rb/rsc_setup.rb, so editing the pattern in the generator without editing the spec is red. Without it this PR would have reintroduced the exact drift class #4787 exists to catch.Also pinned: which
add_extract_loader_to_server_configbranch each simulation fixture exercises (exact-helper / reuse-existing-declaration / emit-both), so a fixture cannot quietly stop covering its branch.3.
serverBundleOutputPathfix. Reported on #4788's review and named in #4787:base_server_webpack_contentreferencedserverBundleOutputPathwithout ever declaring it, so the simulated config could never have run in Node. Fixed in that fixture and in the legacy pre-getLoaderPathfixture, and guarded by a new test requiring everyoutput.pathidentifier to be declared before use.Review feedback addressed (both P2 threads)
Blocker 1 — the ordering assertion did not prove nesting
Raised independently by
greptile-appsandchatgpt-codex-connectoratgenerator_golden_output_spec.rb:368.The original rule-scope check compared byte offsets:
rules.forEachbefore theArray.isArray(rule.use)guard before the css-module block. That is only a proxy. A template refactor that closes the forEach or the guard before the css-module block leaves all three tokens in the same relative order, so the check still passes while the Pro transform insertsextractLoader(rule, …)whereruleis out of scope — producing an invalid generated config with the gate still green.The golden diff only partly covers this: any restructuring changes the golden bytes, so a human has to look. But the same anchor assertion pins the simulation fixtures, which are deliberately allowed to drift. A regenerated golden plus a fixture that still satisfies token ordering means the Pro/RSC transform specs keep passing against a fixture that no longer represents a structure the transform can operate on. That is precisely the drift class this PR exists to close.
Fix: run the real
ProSetuptransforms (add_extract_loader_to_server_configthenadd_babel_ssr_caller_to_server_config) over the target, then assert the insertion point falls inside brace-matchedrules.forEachandArray.isArray(rule.use)blocks.Evidence — restructured input with tokens in unchanged relative order, nesting removed:
Same input, old check green, new check red. Green on the real templates and fixtures:
34 examples, 0 failures.Blocker 2 — regeneration left obsolete variants behind
Thread at
generator_golden_output_spec.rb:109.regenerate!overwrote the current matrix but never removed directories for variants deleted or renamed inVARIANTS, and the examples enumerated only the current matrix — so a stale golden directory stayed committed and read as authoritative while nothing tested it.Fix: assert the on-disk golden file set exactly equals the paths derived from
VARIANTS.Evidence — planted a stale
webpack_legacy_removed/directory:Regeneration rewrote the live matrix and left the orphan in place — confirming the defect — and only the new assertion caught it. After removing it:
34 examples, 0 failures.It asserts rather than auto-deleting, so it fails loudly instead of silently removing a file someone added on purpose. It also catches a changed bundler destination mapping, since the expected paths are derived from it.
Evidence: the gate actually gates
Deliberate one-line edit to
serverWebpackConfig.js.tt(minimize: false→minimize: true), a temporary local experiment only:Red —
32 examples, 7 failuresat the time (all seven golden variants), with the readable diff:Green after revert. The template edit was never staged or committed:
The template does not appear in this PR's file list.
Evidence: the regeneration command round-trips
Run against the staged baseline, so an empty diff means regeneration reproduced the committed bytes exactly. The command regenerates and then re-asserts, so a green run is itself the round-trip proof.
Why the root
.gitignoreneeds one line.gitignore:87is a baregeneratedrule. It excluded the entire golden-fixture directory, which would have left every golden file uncommitted and the new gate dead on arrival in CI — the spec would fail on a fresh clone with "No golden file for variant".The fix is one directory negation, matching existing root-level precedent in the same file (
!react_on_rails/spec/dummy/log/.keep,!react_on_rails_pro/spec/dummy/log/.keep,!/.tool-versions):It must negate the directory: git cannot re-include a file whose parent directory is excluded, so a per-file negation would silently fail. After the change
git check-ignoreexits 1 and the files are tracked. No files under any/generated/path were previously tracked, so nothing else in the repo is affected.Validation
cd react_on_rails && BUNDLE_GEMFILE=../Gemfile bundle exec rubocop244 files inspected, no offenses detectedcd react_on_rails && bundle exec rspec spec/react_on_rails/generators(serial)1329 examples, 0 failuresin 28m47s34 examples, 0 failuresAll 7 golden files end with a trailing newline as committed, verified per file, so the
trailing-newlineshook has nothing to rewrite.Two operational warnings for whoever touches this next
The generator suite must run serially, and it is slow for a non-obvious reason. ~29 minutes wall clock at only a couple of minutes of CPU — it is I/O-bound on real
npmandbundlesubprocesses spawned by the dependency-manager specs, not CPU-bound. Do not parallelize to "speed it up": several generator specs sharespec/react_on_rails/dummy-for-generatorsas their destination, and a parallel run corrupts state and produces false greens (found by the sibling lane on #4786).trailing-newlinesin.lefthook.ymlruns withstage_fixed: true. A golden file that does not end in a newline is silently rewritten at commit time; the committed bytes then differ from generator output and the spec goes red for a reason that looks nothing like the cause. This warning is also in the fixture README next to the regeneration command, where someone adding a variant will actually see it.Codex Decision Log
Non-blocking decisions, none of which change the requested scope:
Kept the directory name
generated/rather than renaming it..prettierignoreandeslint.config.tsboth ignore**/*generated*, and that exemption is what keeps the golden files byte-exact — prettier would otherwise reformat them and break the gate on every commit. Verified with a control test rather than trusting an ambiguous "All matched files use Prettier code style!" on a possibly-empty match set: identical deliberately-malformed JS gets[warn] Code style issues foundoutsidegenerated/and passes silently inside it. Renaming would have required editing.prettierignoreandeslint.config.ts— strictly more non-owned files than the single.gitignoreline.Chose transform-application over plain brace matching for Blocker 1. Both were on the table. Applying the real
ProSetuptransform is stronger because the transform is what actually inserts the code — brace matching alone would still be reasoning about the template's shape rather than about where the generator puts things. Brace matching is retained, but as the means of judging the landing site of a real transform rather than as a standalone structural claim.The brace scanner skips comments and string literals, which is required rather than cosmetic. The Shakapacker < 9 variant contains a template literal with
${serverBundleOutputPath}; a naive brace counter mis-matches on it and would report a confidently wrong block range. Line comments, block comments, and single/double/backtick strings are all skipped.Blocker 2 asserts rather than auto-deleting. Clearing the directory before regenerating would also fix the stale-variant problem, but it silently deletes whatever is there. Failing loudly is the right default for a gate whose purpose is to make drift visible.
Added RSC variants beyond the "Pro on and off" matrix in the issue. RSC is the only case where webpack vs rspack changes the file contents (plugin class name and import path); without it,
webpack_baseandrspack_baseare byte-identical files. Two explicit tests document this: non-RSC webpack/rspack output is asserted identical, and RSC output is asserted to differ only in the plugin name and import path.Stubbed Shakapacker version detection instead of reading the installed gem. The template branches on
shakapacker_version_9_or_higher?; reading the real version would make golden files depend on the developer's local gem. Both arms are covered by the matrix instead.Ran the generator via
copy_webpack_configrather than the full install generator. The full generator shells out tobundleand package managers;copy_webpack_configis the actual production code path that writes this file and keeps the spec fast without losing fidelity.Did not derive the simulation fixtures from the golden files (option 1 in the issue). They deliberately model older installs; deriving them would erase the legacy-upgrade coverage a1 just added.
Confidence note: High that the gate works as specified. Every claim here is backed by output I ran and observed: the deliberate-edit red/green, the byte-verified regeneration round-trip, both blocker fixes demonstrated failing before and passing after, and the full generator suite green at
1329 examples, 0 failures. High that the.gitignorenegation is correct and minimal, verified bygit check-ignorebefore and after.UNKNOWNs:
pro_setup.rb(for example switching%r{}to/.../delimiters) — that would go red and need a matching spec edit, which is the intended cost, but it is a maintenance edge worth knowing about.serverWebpackConfig.jsis pinned. The other managed webpack templates (clientWebpackConfig.js,commonWebpackConfig.js,ServerClientOrBoth.js,rscWebpackConfig.js) have the same drift exposure and are not covered here; extending the matrix to them is a natural follow-up but was out of scope for Generator: add golden-output test for serverWebpackConfig templates to stop fixture drift #4787.mergeimport flagged bygithub-code-qualityis a pre-existing template wart faithfully reproduced by the golden files, tracked separately as Generated serverWebpackConfig.js imports 'merge' from shakapacker but never uses it #4791. The golden files are intentionally unchanged for it.Summary by CodeRabbit