Skip to content

Remove Grunt: consolidate build on webpack + npm scripts#594

Merged
Brutus5000 merged 1 commit into
developfrom
chore/remove-grunt
May 26, 2026
Merged

Remove Grunt: consolidate build on webpack + npm scripts#594
Brutus5000 merged 1 commit into
developfrom
chore/remove-grunt

Conversation

@Brutus5000

@Brutus5000 Brutus5000 commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Webpack handles JS and SCSS now (via sass-loader + mini-css-extract-plugin + webpack-remove-empty-scripts). Output reorganized under dist/{js,styles}/ with a single combined manifest at dist/manifest.json.
  • webpackAsset middleware exposes webpackAssetJS(entry) and a new webpackAssetCSS(entry); the default layout and newshub.pug now resolve their stylesheet through the manifest, replacing the ?version=Date.now() cache-busting hack with proper content hashes.
  • Dev runner is now yarn devwebpack --watch + nodemon started in parallel via concurrently. Prod build is yarn build. Dockerfile-dev CMD and the prod Dockerfile build step updated accordingly.
  • Drops Gruntfile.js, the grunt/ folder, and 8 grunt-* devDeps. Net diff: +202 / -1457.

Why

Reduces the build pipeline from two parallel runners (Grunt + webpack) down to one, removes EOL-tier tooling, and unifies file-watching. Identified as the highest-impact "quick cleanup" item in the stack assessment.

Test plan

  • yarn build produces dist/js/*.[hash].js, dist/styles/styles.[hash].css, and a manifest with both *.js and styles.css keys
  • yarn lint clean
  • yarn test — 71/71 (integration tests boot AppKernel and hit / + /newshub, exercising the new CSS manifest path end-to-end)
  • Manual: yarn dev — edit a .sass file, confirm CSS rebuilds; edit a backend file, confirm nodemon restarts
  • Manual: build & run the prod Docker image, confirm site loads with styles
  • Verify CI/deployment scripts don't reference grunt anywhere outside this repo (faf-stack, deploy configs)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Migrated from Grunt to webpack-based build tooling with npm-based build and development scripts.
    • CSS stylesheets are now managed through webpack manifest system instead of Grunt configuration files.
    • Updated Docker build and development containers to execute yarn build and yarn dev respectively.
    • Asset serving refactored to use centralized webpack manifest for both JavaScript and CSS file references.

Review Change Stack

Webpack now handles both JS and SCSS via sass-loader + mini-css-extract-
plugin (with webpack-remove-empty-scripts to drop the empty styles JS
chunk). Output is reorganized under dist/{js,styles}/ with a single
combined manifest at dist/manifest.json; AppContainer loads it and
webpackAsset middleware exposes both webpackAssetJS and webpackAssetCSS
helpers. The default and newshub pug templates now link CSS via the
manifest, dropping the ?version=Date.now() cache-busting hack in favor
of content hashes.

The dev runner becomes `yarn dev` (webpack --watch + nodemon under
concurrently); prod build becomes `yarn build`. Dockerfile-dev CMD and
the prod Dockerfile build step are updated accordingly. Removes 8
grunt-* devDeps, Gruntfile.js, and the grunt/ folder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 26, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR migrates the build system from Grunt to webpack with native npm scripts. Webpack now extracts SASS stylesheets as hashed CSS files, the backend loads a unified manifest instead of JS-specific manifests, and asset middleware provides separate helpers for JS and CSS entry points. Development uses nodemon and concurrent npm scripts instead of Grunt tasks.

Changes

Build System Migration

Layer / File(s) Summary
Webpack CSS and SASS extraction
webpack.config.js
New mini-css-extract-plugin and webpack-remove-empty-scripts dependencies. Added *.s[ac]ss rule with sass-loader to compile public/styles/site.sass. New styles entry point emits hashed CSS to dist/styles/. Output reconfigured to path: dist, publicPath: /dist/, and JS filenames to js/[name].[contenthash].js. Manifest plugin uses default options.
NPM scripts and build dependencies
package.json, .gitignore
Removed all grunt-* packages; added concurrently, nodemon, webpack-remove-empty-scripts. Added npm scripts: build (webpack), dev:webpack (webpack watch), dev:server (nodemon), dev (concurrent), start (node backend). Cleaned up .gitignore to stop ignoring .grunt directory.
Development environment tooling
nodemon.json, Dockerfile, Dockerfile-dev
New nodemon.json watches src/backend, ignores dist/sessions/node_modules, applies 500ms delay. Dockerfile builder runs yarn build instead of webpack/Grunt commands. Dockerfile-dev runs yarn dev under dumb-init instead of grunt concurrent.
Backend webpack manifest and asset middleware
src/backend/dependency-injection/AppContainer.js, src/backend/AppKernel.js, src/backend/middleware/webpackAsset.js
AppContainer loads unified dist/manifest.json (not dist/js/manifest.json) as webpackManifest. AppKernel passes webpackManifest instead of webpackManifestJS. webpackAsset middleware refactored: accepts webpackManifest, centralizes asset lookup, webpackAssetJS(entry) now resolves ${entry}.js, new webpackAssetCSS(entry) helper resolves ${entry}.css.
Template stylesheet links
src/backend/templates/layouts/default.pug, src/backend/templates/views/newshub.pug
Replaced hardcoded site.min.css?version=Date.now() with webpackAssetCSS('styles') to load webpack-managed stylesheet.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 Grunt has retired, webpack takes the stage,
SASS flows as CSS in this modern age,
Nodemon watches, concurrently runs true,
From Dockerfile to template, it's all something new!
🎉✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing Grunt and consolidating the build process on webpack and npm scripts, which is exactly what the changeset demonstrates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/remove-grunt

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@src/backend/dependency-injection/AppContainer.js`:
- Around line 12-13: The module currently does eager one-time loading of
dist/manifest.json into the webpackManifest constant at import time causing
startup failures when the manifest is missing and stale assets after rebuilds;
change this to a lazy loader function (e.g., getWebpackManifest or loadManifest)
used by the middleware that currently references webpackManifest so the manifest
is read on demand (and in development optionally cached/invalidated between
requests), and handle/read errors gracefully so startup doesn't crash when
manifest is not yet written.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c50ccd26-10f3-4a79-a006-3f4628dd9419

📥 Commits

Reviewing files that changed from the base of the PR and between 464f094 and 43d0b9c.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (17)
  • .gitignore
  • Dockerfile
  • Dockerfile-dev
  • Gruntfile.js
  • grunt/concurrent.js
  • grunt/nodemon.js
  • grunt/run.js
  • grunt/sass.js
  • grunt/watch.js
  • nodemon.json
  • package.json
  • src/backend/AppKernel.js
  • src/backend/dependency-injection/AppContainer.js
  • src/backend/middleware/webpackAsset.js
  • src/backend/templates/layouts/default.pug
  • src/backend/templates/views/newshub.pug
  • webpack.config.js
💤 Files with no reviewable changes (7)
  • grunt/run.js
  • grunt/watch.js
  • grunt/sass.js
  • grunt/concurrent.js
  • grunt/nodemon.js
  • Gruntfile.js
  • .gitignore

Comment on lines +12 to +13
const webpackManifest = JSON.parse(
fs.readFileSync('dist/manifest.json', 'utf8')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid eager, one-time manifest loading.

Line 12 loads dist/manifest.json at module import and Line 23 reuses that static object forever. With yarn dev (webpack watch + nodemon in parallel), this can crash startup if the manifest is not written yet, and it can serve stale hashed assets after rebuilds.

Suggested direction
+const path = require('path')
 const fs = require('fs')
-const webpackManifest = JSON.parse(
-    fs.readFileSync('dist/manifest.json', 'utf8')
-)
+const loadWebpackManifest = () =>
+    JSON.parse(
+        fs.readFileSync(path.resolve(process.cwd(), 'dist/manifest.json'), 'utf8')
+    )

 module.exports.appContainer = function (appConfig) {
     const container = new ContainerBuilder()

-    container.setParameter('webpackManifest', webpackManifest)
+    container.setParameter('webpackManifest', loadWebpackManifest)

Then have the middleware call the loader (at least in development) instead of capturing a frozen manifest snapshot.

Also applies to: 23-23

🤖 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 `@src/backend/dependency-injection/AppContainer.js` around lines 12 - 13, The
module currently does eager one-time loading of dist/manifest.json into the
webpackManifest constant at import time causing startup failures when the
manifest is missing and stale assets after rebuilds; change this to a lazy
loader function (e.g., getWebpackManifest or loadManifest) used by the
middleware that currently references webpackManifest so the manifest is read on
demand (and in development optionally cached/invalidated between requests), and
handle/read errors gracefully so startup doesn't crash when manifest is not yet
written.

@Brutus5000 Brutus5000 merged commit eace251 into develop May 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant