Skip to content

Comments

Move build tooling packages from devDependencies to dependencies#929

Open
justin808 wants to merge 1 commit intomainfrom
codex/issue-662-build-tools-deps-pr
Open

Move build tooling packages from devDependencies to dependencies#929
justin808 wants to merge 1 commit intomainfrom
codex/issue-662-build-tools-deps-pr

Conversation

@justin808
Copy link
Member

@justin808 justin808 commented Feb 23, 2026

Summary

  • move webpack/rspack build tooling packages from devDependencies to dependencies
  • keep lint/test/typecheck toolchain in devDependencies
  • retain peer dependency declarations and optional peer metadata as-is

Why

Issue #662 reports production install/build failures when package managers skip devDependencies. Moving these runtime bundler packages into dependencies ensures they are available in production installs and file-path based local installs.

Fixes #662


Note

Low Risk
Dependency classification-only change with no runtime code modifications; main risk is downstream install size/duplicate dependency expectations.

Overview
Moves core bundler/build tooling packages (Rspack/Webpack, loaders, and related plugins) from devDependencies into dependencies so production installs that omit dev deps still have the build toolchain available.

Keeps the lint/test/typecheck toolchain in devDependencies and leaves existing peerDependencies/peerDependenciesMeta declarations unchanged.

Written by Cursor Bugbot for commit 09a9f23. Configure here.

Summary by CodeRabbit

  • Chores
    • Build tooling and bundler packages have been reclassified as runtime dependencies, increasing the application's deployment footprint and installation requirements.

@coderabbitai
Copy link

coderabbitai bot commented Feb 23, 2026

Walkthrough

This PR reclassifies 16 build tooling packages from devDependencies to dependencies in package.json. These packages—including webpack, rspack, loaders, and plugins—are essential runtime dependencies that enable Shakapacker's bundling functionality and are already declared as peer dependencies.

Changes

Cohort / File(s) Summary
Build Tools Migration
package.json
Moves 16 runtime build packages (webpack, rspack, loaders, plugins) from devDependencies to dependencies. Packages moved: @rspack/cli, @rspack/core, @swc/core, babel-loader, compression-webpack-plugin, css-loader, esbuild-loader, mini-css-extract-plugin, rspack-manifest-plugin, sass-loader, swc-loader, webpack, webpack-assets-manifest, webpack-cli, webpack-subresource-integrity.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Poem

🐰 Hops of joy through the dependency tree,
Build tools now live where they ought to be,
No more production builds that say "nay,"
They're in dependencies to stay! 🛠️✨

🚥 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 describes the main change: moving build tooling packages from devDependencies to dependencies, which is the primary focus of the changeset.
Linked Issues check ✅ Passed The PR fully addresses issue #662's objective to move runtime build tools (webpack, rspack, loaders, plugins) from devDependencies to dependencies while keeping development-only tooling in devDependencies.
Out of Scope Changes check ✅ Passed All changes are directly scoped to moving build tooling packages between dependency sections; no unrelated modifications to code, exports, or package structure are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/issue-662-build-tools-deps-pr

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.

@claude
Copy link

claude bot commented Feb 23, 2026

Code Review

This PR moves build tooling from devDependencies to dependencies, but this approach has several significant problems that I'd recommend addressing before merging.

Core Issue: This Approach is Architecturally Incorrect for a Library

Shakapacker is a library published to npm. For libraries, the npm dependency sections have specific semantics:

  • dependencies: Packages your library's runtime code imports and needs to function (always installed transitively for consumers)
  • devDependencies: Packages only needed to develop/test the library itself (never installed for consumers)
  • peerDependencies: Packages the consumer must install themselves (consumer-provided, prevents duplicate installs)

The packages moved here (webpack, rspack, loaders, plugins) should remain as peer dependencies only. They're tools the consumer orchestrates — shakapacker doesn't import them at runtime, it just knows how to configure them.

Problem 1: Duplication Between dependencies and peerDependencies

Every moved package is already declared in peerDependencies. Having a package in both sections causes:

  • Package managers may install two copies (once from shakapacker's dependencies, once from the consumer's direct install)
  • Version conflicts when the consumer uses a different version than what shakapacker pinned
  • Consumers using rspack-only stacks will now also receive webpack and all its loaders as forced transitive dependencies (and vice versa)

This is a breaking change for existing consumers' install size and potential version conflicts.

Problem 2: Version Pinning Conflict

webpack is pinned to an exact version (5.93.0, no caret), while peerDependencies accepts ^5.76.0. A consumer using webpack 5.94.0 would get two different webpack copies installed, which is a known source of subtle bundler bugs.

Problem 3: The Root Cause Isn't Fixed

Issue #662 describes failures when package managers skip devDependencies. But shakapacker itself should be in the consumer app's devDependencies — it's a build tool, not runtime code. If a deployment pipeline is skipping devDependencies, it should also skip shakapacker entirely. The real fix is either:

  1. Documentation clarifying shakapacker must be in consumer's devDependencies
  2. Better error messaging when build tools are missing at runtime
  3. Investigating the specific package manager (pnpm/Bun strict mode) that caused Build tools should be in dependencies, not devDependencies #662

Problem 4: Inconsistency — sass-loader Without sass

sass-loader is moved to dependencies, but sass itself remains only in peerDependencies. sass-loader is useless without sass, so this creates an inconsistency where a half-installed toolchain is forced on consumers.

Recommendation

Rather than this approach, I'd suggest:

  1. Keep these packages in devDependencies (for shakapacker's own test/dev use) and peerDependencies only (unchanged from today)
  2. Investigate the specific issue in Build tools should be in dependencies, not devDependencies #662 — provide a minimal reproduction and identify which package manager and configuration triggers the failure
  3. If the problem is pnpm's strict peer deps, the fix may be configuration on the consumer side or adding a note to the install docs

"prepublishOnly": "yarn build && yarn type-check"
},
"dependencies": {
"@rspack/cli": "^1.5.8",
Copy link

Choose a reason for hiding this comment

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

These packages are already declared in peerDependencies (lines 102–123). Having them in both dependencies and peerDependencies will cause package managers to install duplicate copies — one pinned by shakapacker's dependency resolution, and one from the consumer's own install. This is a common source of version conflicts (e.g., two webpack instances) and will silently inflate every consumer's node_modules.

"rspack-manifest-plugin": "^5.0.3",
"sass-loader": "^16.0.5",
"swc-loader": "^0.1.15",
"webpack": "5.93.0",
Copy link

Choose a reason for hiding this comment

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

This exact pin (5.93.0, no caret) conflicts with the peerDependencies range ^5.76.0. A consumer on webpack 5.94.0 will end up with two different webpack versions installed simultaneously — a well-known cause of bundler bugs (duplicate plugin instances, HMR breakage, etc.). If kept here at all, this should be "webpack": "^5.76.0" to match the peer dep range.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 23, 2026

Greptile Summary

Moves essential build tooling packages (webpack, rspack, loaders, and plugins) from devDependencies to dependencies to ensure production installs that skip dev dependencies have access to the bundler toolchain. This resolves production install/build failures reported in issue #662.

  • Correctly moves 12 build-critical packages: webpack, webpack-cli, @rspack/core, @rspack/cli, @swc/core, babel-loader, css-loader, sass-loader, swc-loader, esbuild-loader, mini-css-extract-plugin, compression-webpack-plugin, webpack-assets-manifest, webpack-subresource-integrity, rspack-manifest-plugin, and webpack-merge
  • Properly retains development-only tools in devDependencies: ESLint, Prettier, TypeScript, Jest, and type definitions
  • Leaves peerDependencies and peerDependenciesMeta declarations unchanged as intended
  • All moved packages remain marked as optional peers, maintaining backward compatibility

Confidence Score: 5/5

  • This PR is safe to merge with no execution risk
  • This is a pure dependency classification change with zero code modifications. The moved packages are essential build tools that must be available in production environments, and the change correctly addresses a real production install failure scenario. All peer dependency declarations remain unchanged, maintaining backward compatibility.
  • No files require special attention

Important Files Changed

Filename Overview
package.json Moved build tooling packages from devDependencies to dependencies to fix production install failures; correctly kept lint/test/typecheck tools in devDependencies

Last reviewed commit: 09a9f23

"mini-css-extract-plugin": "^2.9.4",
"path-complete-extname": "^1.0.0",
"rspack-manifest-plugin": "^5.0.3",
"sass-loader": "^16.0.5",
Copy link

Choose a reason for hiding this comment

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

sass-loader is now a hard dependency, but sass itself remains only in peerDependencies (optional). This is inconsistent — sass-loader is non-functional without sass. Consumers who don't use Sass now get sass-loader forced on them but don't get sass, so the loader serves no purpose in their install.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is ON, but it could not run because Privacy Mode (Legacy) is turned on. To enable Bugbot Autofix, switch your privacy mode in the Cursor dashboard.

"rspack-manifest-plugin": "^5.0.3",
"sass-loader": "^16.0.5",
"swc-loader": "^0.1.15",
"webpack": "5.93.0",
Copy link

Choose a reason for hiding this comment

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

Exact-pinned webpack version forces duplicates on consumers

High Severity

webpack is exact-pinned at "5.93.0" (no caret) in dependencies, while the peerDependencies declares "^5.76.0". When this was in devDependencies, the exact pin only affected local development. Now that it's a hard dependency, consumers using any other webpack 5.x version (e.g., 5.95.0) will get a duplicate webpack installation nested inside this package's node_modules. Two webpack instances cause instanceof check failures, broken singleton patterns, and plugin incompatibilities. Every other package in dependencies uses a caret range — this one likely needs ^5.93.0 or similar.

Fix in Cursor Fix in Web

"webpack-assets-manifest": "^5.0.6",
"webpack-cli": "^6.0.0",
"webpack-merge": "^5.8.0",
"webpack-subresource-integrity": "^5.1.0",
Copy link

Choose a reason for hiding this comment

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

Mutually exclusive optional packages now forced on all consumers

Medium Severity

Packages like @rspack/cli, @rspack/core, webpack, webpack-cli, babel-loader, swc-loader, and esbuild-loader are designed to be mutually exclusive choices (webpack vs rspack, babel vs swc vs esbuild). They were previously optional peer dependencies so consumers install only what they need. Moving all of them into hard dependencies forces every consumer to install both bundlers and all transpiler loaders, significantly bloating installs. The peerDependenciesMeta optional: true flags are now contradicted and rendered meaningless.

Fix in Cursor Fix in Web

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
package.json (1)

52-52: esbuild-loader is pinned two major versions behind its current release

"esbuild-loader": "^2.18.0" pins to the v2 line. The latest published version of esbuild-loader is 4.4.2. The peerDependencies already advertises support up to ^4.0.0. Keeping dependencies on ^2 means every consumer gets v2 regardless of what newer version they have installed, and they miss 2 major versions of improvements.

Consider bumping to "^4.0.0" (or at least "^3.0.0 || ^4.0.0") to stay aligned with the latest supported range.

🔧 Proposed fix
-    "esbuild-loader": "^2.18.0",
+    "esbuild-loader": "^4.0.0",

Similarly, babel-loader in dependencies is pinned to ^8.2.4. The latest version of babel-loader is 10.0.0. The peerDependencies already allows ^10.0.0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 52, Update package.json dependencies to allow current
major versions: replace the esbuild-loader entry ("esbuild-loader": "^2.18.0")
with a range that matches supported peers, e.g. "^4.0.0" (or "^3.0.0 || ^4.0.0")
so consumers can resolve modern v3/ v4 releases; likewise bump babel-loader from
"^8.2.4" to "^10.0.0" to match its peer support. Ensure only the dependency
version strings for "esbuild-loader" and "babel-loader" are updated in
package.json.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Line 59: The package.json dependency for "webpack" is pinned to an exact patch
("5.93.0") which forces consumers to install duplicate webpack instances; update
the "webpack" entry in package.json to use a caret range (e.g. change "webpack":
"5.93.0" to "webpack": "^5.93.0") so npm/yarn can resolve compatible versions
and avoid duplicate installs (ensure this aligns with the existing
peerDependencies range if needed).
- Around line 49-63: package.json lists specific dependency ranges narrower than
the package's peerDependencies which can cause duplicate installs and lock
consumers to older majors; update the dependency ranges for babel-loader,
esbuild-loader, compression-webpack-plugin, swc-loader, and
webpack-assets-manifest to either match the widest peerDependencies ranges (e.g.
"babel-loader": "^8.2.4 || ^9.0.0 || ^10.0.0", "esbuild-loader": "^2.0.0 ||
^3.0.0 || ^4.0.0", etc.) or bump each dependency to the latest major allowed by
its peerDependencies (e.g. set babel-loader to "^10.0.0") so npm dedupes
correctly and avoids installing a second copy.

---

Nitpick comments:
In `@package.json`:
- Line 52: Update package.json dependencies to allow current major versions:
replace the esbuild-loader entry ("esbuild-loader": "^2.18.0") with a range that
matches supported peers, e.g. "^4.0.0" (or "^3.0.0 || ^4.0.0") so consumers can
resolve modern v3/ v4 releases; likewise bump babel-loader from "^8.2.4" to
"^10.0.0" to match its peer support. Ensure only the dependency version strings
for "esbuild-loader" and "babel-loader" are updated in package.json.

Comment on lines +49 to +63
"babel-loader": "^8.2.4",
"compression-webpack-plugin": "^9.0.0",
"css-loader": "^7.1.2",
"esbuild-loader": "^2.18.0",
"js-yaml": "^4.1.0",
"mini-css-extract-plugin": "^2.9.4",
"path-complete-extname": "^1.0.0",
"rspack-manifest-plugin": "^5.0.3",
"sass-loader": "^16.0.5",
"swc-loader": "^0.1.15",
"webpack": "5.93.0",
"webpack-assets-manifest": "^5.0.6",
"webpack-cli": "^6.0.0",
"webpack-merge": "^5.8.0",
"webpack-subresource-integrity": "^5.1.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat package.json

Repository: shakacode/shakapacker

Length of output: 6578


🏁 Script executed:

tail -c 1 package.json | od -An -tx1

Repository: shakacode/shakapacker

Length of output: 107


🏁 Script executed:

tail -c 1 package.json | wc -c

Repository: shakacode/shakapacker

Length of output: 66


🏁 Script executed:

tail -c 2 package.json | xxd

Repository: shakacode/shakapacker

Length of output: 108


🏁 Script executed:

python3 << 'EOF'
with open('package.json', 'rb') as f:
    content = f.read()
    last_char = content[-1:]
    if last_char == b'\n':
        print("File ends with newline")
    else:
        print(f"File does NOT end with newline. Last byte: {last_char}")
EOF

Repository: shakacode/shakapacker

Length of output: 87


Several dependencies ranges are narrower than their peerDependencies counterparts, risking duplicate installs and forcing consumers to stale majors

When Shakapacker is a dependency of a consuming project, npm 7+ resolves Shakapacker's own dependencies separately. If the consumer has a version that satisfies the peerDependencies range but not the dependencies range, npm installs a second copy of the conflicting package inside Shakapacker's subtree. This results in:

  • Two copies of the same loader/plugin in the build (known to cause subtle runtime failures e.g. with webpack plugin registrations)
  • Consumers being silently locked to an older major despite their peerDependencies meta advertising broader support

Affected pairs (dependencies → peerDependencies):

Package dependencies peerDependencies
babel-loader ^8.2.4 ^8.2.4 || ^9.0.0 || ^10.0.0
esbuild-loader ^2.18.0 ^2.0.0 || ^3.0.0 || ^4.0.0
compression-webpack-plugin ^9.0.0 ^9.0.0 || ^10.0.0 || ^11.0.0
swc-loader ^0.1.15 ^0.1.15 || ^0.2.0
webpack-assets-manifest ^5.0.6 ^5.0.6 || ^6.0.0

The dependencies range should either:

  1. Match the widest range declared in peerDependencies (e.g. "^8.2.4 || ^9.0.0 || ^10.0.0"), so deduplication succeeds for any consumer-compatible version, or
  2. Be bumped to the latest major that peerDependencies supports (e.g. "^10.0.0" for babel-loader).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 49 - 63, package.json lists specific dependency
ranges narrower than the package's peerDependencies which can cause duplicate
installs and lock consumers to older majors; update the dependency ranges for
babel-loader, esbuild-loader, compression-webpack-plugin, swc-loader, and
webpack-assets-manifest to either match the widest peerDependencies ranges (e.g.
"babel-loader": "^8.2.4 || ^9.0.0 || ^10.0.0", "esbuild-loader": "^2.0.0 ||
^3.0.0 || ^4.0.0", etc.) or bump each dependency to the latest major allowed by
its peerDependencies (e.g. set babel-loader to "^10.0.0") so npm dedupes
correctly and avoids installing a second copy.

"rspack-manifest-plugin": "^5.0.3",
"sass-loader": "^16.0.5",
"swc-loader": "^0.1.15",
"webpack": "5.93.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

webpack is pinned to an exact version — use a caret range instead

"webpack": "5.93.0" (no ^) locks every consumer to exactly this patch. When a consuming project has a different webpack version (even a patch bump like 5.94.0), npm/yarn will install a second, nested copy of webpack. Two concurrent webpack instances in one build cause hard-to-debug loader resolution and plugin registration failures. The intent is clearly a range — peerDependencies already declares "^5.76.0".

🔧 Proposed fix
-    "webpack": "5.93.0",
+    "webpack": "^5.93.0",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"webpack": "5.93.0",
"webpack": "^5.93.0",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 59, The package.json dependency for "webpack" is pinned
to an exact patch ("5.93.0") which forces consumers to install duplicate webpack
instances; update the "webpack" entry in package.json to use a caret range (e.g.
change "webpack": "5.93.0" to "webpack": "^5.93.0") so npm/yarn can resolve
compatible versions and avoid duplicate installs (ensure this aligns with the
existing peerDependencies range if needed).

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.

Build tools should be in dependencies, not devDependencies

1 participant