Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
835adb5
Vibe code RSPack support into Shakapacker
craigmcnamara Aug 19, 2025
98f68d4
Ditch a flaky test for now
craigmcnamara Aug 19, 2025
84a0b7c
Remove hardcoded webpack call
craigmcnamara Aug 19, 2025
641c7e8
Remove unsupported options from rspack command
craigmcnamara Aug 19, 2025
0fb64ad
Fix JS exports
craigmcnamara Aug 19, 2025
ea51c96
Fix loader detection
craigmcnamara Aug 19, 2025
3f63dcc
Fix named exports
craigmcnamara Aug 19, 2025
0986fa7
Fix manifest support
craigmcnamara Aug 19, 2025
5c3287b
Update index.js
craigmcnamara Aug 19, 2025
bf5a4c6
Fix CSS loader
craigmcnamara Aug 19, 2025
e761a15
Fix asset loaders
craigmcnamara Aug 19, 2025
c94d3b0
Fix more asset handling
craigmcnamara Aug 19, 2025
5422036
Fix static asset handling
craigmcnamara Aug 19, 2025
8c4daf0
Update file.js
craigmcnamara Aug 19, 2025
7971fa8
Try to fix CSS extraction
craigmcnamara Aug 19, 2025
ff435ca
Consulted the docs
craigmcnamara Aug 19, 2025
1c8f9b6
Fix import
craigmcnamara Aug 19, 2025
3380051
Fix manifest
craigmcnamara Aug 19, 2025
14eb87f
Fix file mapping
craigmcnamara Aug 19, 2025
3cd30d4
More manifest hackery
craigmcnamara Aug 19, 2025
7847740
Try to keep in line with the webpacker approach.
craigmcnamara Aug 19, 2025
acd8b96
Go back to a scheme that works
craigmcnamara Aug 19, 2025
a2de666
Fix hashed asset lookup
craigmcnamara Aug 19, 2025
bacac74
Fix chunk lookup
craigmcnamara Aug 19, 2025
8f1d7e7
Update CHANGELOG.md
craigmcnamara Aug 19, 2025
9d45f7d
Don't flood warnings from dependencies
craigmcnamara Aug 19, 2025
5c3dceb
Address automated review issues.
craigmcnamara Aug 20, 2025
49437c5
Replace WebpackAssetsManifest with RspackManifestPlugin
justisb Aug 26, 2025
a1997bd
Fall back to pack name without ext
justisb Aug 26, 2025
8bc951b
Replace webpack import with rspack
justisb Aug 26, 2025
b0c233a
Fall back to entry path
justisb Aug 26, 2025
cbdb000
Try custom serialize/generate options
justisb Sep 3, 2025
e21fb58
Copy remaining changes from rspack/base.js
justisb Sep 3, 2025
b91e764
Move logic from serialize to generate
justisb Sep 4, 2025
0254b95
Remove find(name)
justisb Sep 5, 2025
cbd30e0
Always use original file path
justisb Sep 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
## [Unreleased]
Changes since the last non-beta release.


### Added

- Support for subresource integrity. [PR 570](https://github.com/shakacode/shakapacker/pull/570) by [panagiotisplytas](https://github.com/panagiotisplytas)
* Rspack support as an alternative bundler to webpack. Configure `bundler: 'rspack'` in `shakapacker.yml` to use Rspack's faster Rust-based bundling with webpack-compatible API, built-in SWC loader, and CSS extraction. Automatic bundler detection in `bin/shakapacker` with fallback support for webpack configurations.
* Support for subresource integrity. [PR 570](https://github.com/shakacode/shakapacker/pull/570) by [panagiotisplytas](https://github.com/panagiotisplytas)

### Fixed

- Install the latest major version of peer dependencies [PR 576](https://github.com/shakacode/shakapacker/pull/576) by [G-Rath](https://github.com/g-rath).
- Remove duplicate word in comment from generated `shakapacker.yml` config [PR 572](https://github.com/shakacode/shakapacker/pull/572) by [G-Rath](https://github.com/g-rath).
* Install the latest major version of peer dependencies [PR 576](https://github.com/shakacode/shakapacker/pull/576) by [G-Rath](https://github.com/g-rath).
* Remove duplicate word in comment from generated `shakapacker.yml` config [PR 572](https://github.com/shakacode/shakapacker/pull/572) by [G-Rath](https://github.com/g-rath).

## [v8.3.0] - April 25, 2025
### Added
Expand Down
190 changes: 190 additions & 0 deletions docs/rspack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Rspack Integration

Shakapacker supports [Rspack](https://rspack.rs) as an alternative bundler to Webpack. Rspack is a fast Rust-based web bundler with webpack-compatible API that can significantly speed up your build times.

## Installation

First, install the required Rspack dependencies:

```bash
npm install @rspack/core @rspack/cli -D
# or
yarn add @rspack/core @rspack/cli -D
# or
pnpm add @rspack/core @rspack/cli -D
# or
bun add @rspack/core @rspack/cli -D
```

Note: These packages are already listed as optional peer dependencies in Shakapacker, so you may see warnings if they're not installed.

## Configuration

To enable Rspack, update your `config/shakapacker.yml`:

```yaml
default: &default
# ... other config options
bundler: 'rspack' # Change from 'webpack' to 'rspack'
```

## Configuration

Rspack uses its own configuration directory to keep things organized. Create your Rspack configuration file at `config/rspack/rspack.config.js`:

```javascript
const { generateRspackConfig } = require('shakapacker/rspack')

module.exports = generateRspackConfig()
```

### Custom Configuration

If you need to customize your Rspack configuration:

```javascript
const { generateRspackConfig } = require('shakapacker/rspack')

const rspackConfig = generateRspackConfig({
plugins: [
new SomeRspackCompatiblePlugin()
],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
}
})

module.exports = rspackConfig
```

### Migration from Webpack Config

If you have an existing `config/webpack/webpack.config.js`, you can migrate it to `config/rspack/rspack.config.js`:

**Old (webpack.config.js):**
```javascript
const { generateWebpackConfig } = require('shakapacker')
module.exports = generateWebpackConfig()
```

**New (rspack.config.js):**
```javascript
const { generateRspackConfig } = require('shakapacker/rspack')
module.exports = generateRspackConfig()
```

> **Note:** Shakapacker will show a deprecation warning if you use `config/webpack/webpack.config.js` with `bundler: 'rspack'`. Please migrate to `config/rspack/rspack.config.js`.

## Key Differences from Webpack

### Built-in Loaders

Rspack has built-in loaders that are faster than their webpack counterparts:

- **JavaScript/TypeScript**: Uses `builtin:swc-loader` instead of `babel-loader`
- **CSS Extraction**: Uses `rspack.CssExtractRspackPlugin` instead of `mini-css-extract-plugin`
- **Asset Handling**: Uses built-in asset modules instead of `file-loader`/`url-loader`

### Plugin Compatibility

Most webpack plugins work with Rspack, but some have Rspack-specific alternatives:

| Webpack Plugin | Rspack Alternative | Status |
|---|---|---|
| `mini-css-extract-plugin` | `rspack.CssExtractRspackPlugin` | Built-in |
| `copy-webpack-plugin` | `rspack.CopyRspackPlugin` | Built-in |
| `terser-webpack-plugin` | `rspack.SwcJsMinimizerRspackPlugin` | Built-in |

### Minification

Rspack uses SWC for minification by default, which is significantly faster than Terser:

```javascript
optimization: {
minimize: true,
minimizer: [
new rspack.SwcJsMinimizerRspackPlugin(),
new rspack.SwcCssMinimizerRspackPlugin()
]
}
```

## Limitations

- **CoffeeScript**: Not supported with Rspack
- **Some Webpack Plugins**: May not be compatible; check Rspack documentation

## Commands

All existing Shakapacker commands work the same way and automatically use Rspack when configured:

```bash
# Build (automatically uses rspack when bundler: 'rspack')
./bin/shakapacker

# Development server (automatically uses rspack when bundler: 'rspack')
./bin/shakapacker-dev-server

# Watch mode
./bin/shakapacker --watch
```

The same dev server configuration in `shakapacker.yml` applies to both webpack and rspack.

## Performance Benefits

Rspack typically provides:

- **2-10x faster** cold builds
- **5-20x faster** incremental builds
- **Faster HMR** (Hot Module Replacement)
- **Lower memory usage**

## Migration Checklist

1. **Install Rspack dependencies:**
```bash
npm install @rspack/core @rspack/cli -D
```

2. **Update configuration:**
```yaml
# config/shakapacker.yml
default: &default
bundler: 'rspack'
```

3. **Create Rspack config:**
```javascript
// config/rspack/rspack.config.js
const { generateRspackConfig } = require('shakapacker/rspack')
module.exports = generateRspackConfig()
```

4. **Remove CoffeeScript files** (if any) - not supported by Rspack

5. **Test your application** - same commands work automatically

## Troubleshooting

### Configuration Issues

If you encounter configuration issues:

1. Check that all plugins are Rspack-compatible
2. Verify custom loaders work with Rspack
3. Review the [Rspack migration guide](https://rspack.rs/guide/migration/webpack)

### Performance Issues

If builds are unexpectedly slow:

1. Ensure you're using built-in Rspack loaders
2. Check for webpack-specific plugins that should be replaced
3. Review your asset optimization settings

## Further Reading

- [Rspack Official Documentation](https://rspack.rs)
- [Rspack Migration Guide](https://rspack.rs/guide/migration/webpack)
- [Rspack Plugins](https://rspack.rs/plugins/webpack/)
16 changes: 14 additions & 2 deletions lib/install/bin/shakapacker
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,22 @@ ENV["RAILS_ENV"] ||= "development"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)

require "bundler/setup"
require "pathname"
require "shakapacker"
require "shakapacker/webpack_runner"

APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Shakapacker::WebpackRunner.run(ARGV)
config = Shakapacker::Configuration.new(
root_path: Pathname.new(APP_ROOT),
config_path: Pathname.new(File.join(APP_ROOT, "config/shakapacker.yml")),
env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
)

if config.rspack?
require "shakapacker/rspack_runner"
Shakapacker::RspackRunner.run(ARGV)
else
require "shakapacker/webpack_runner"
Shakapacker::WebpackRunner.run(ARGV)
end
end
13 changes: 13 additions & 0 deletions lib/install/bin/shakapacker-rspack
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env ruby

ENV["RAILS_ENV"] ||= "development"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)

require "bundler/setup"
require "shakapacker"
require "shakapacker/rspack_runner"

APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Shakapacker::RspackRunner.run(ARGV)
end
6 changes: 6 additions & 0 deletions lib/install/config/rspack/rspack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// See the shakacode/shakapacker README and docs directory for advice on customizing your rspackConfig.
const { generateRspackConfig } = require('shakapacker/rspack')

const rspackConfig = generateRspackConfig()

module.exports = rspackConfig
3 changes: 3 additions & 0 deletions lib/install/config/shakapacker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ default: &default
# Select loader to use, available options are 'babel' (default), 'swc' or 'esbuild'
webpack_loader: 'babel'

# Select bundler to use, available options are 'webpack' (default) or 'rspack'
bundler: 'webpack'

# Raises an error if there is a mismatch in the shakapacker gem and npm package being used
ensure_consistent_versioning: true

Expand Down
6 changes: 6 additions & 0 deletions lib/install/config/webpack/rspack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// See the shakacode/shakapacker README and docs directory for advice on customizing your rspackConfig.
const { generateRspackConfig } = require('shakapacker/rspack')

const rspackConfig = generateRspackConfig()

module.exports = rspackConfig
12 changes: 12 additions & 0 deletions lib/shakapacker/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ def compiler_strategy
fetch(:compiler_strategy)
end

def bundler
fetch(:bundler) || "webpack"
end

def rspack?
bundler == "rspack"
end

def webpack?
bundler == "webpack"
end

def fetch(key)
data.fetch(key, defaults[key])
end
Expand Down
24 changes: 17 additions & 7 deletions lib/shakapacker/dev_server_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,20 @@ def execute_cmd
env["NODE_OPTIONS"] = "#{env["NODE_OPTIONS"]} --inspect-brk --trace-warnings"
end

cmd += ["--config", @webpack_config]
cmd += ["--progress", "--color"] if @pretty

# Default behavior of webpack-dev-server is @hot = true
cmd += ["--hot", "only"] if @hot == "only"
cmd += ["--no-hot"] if !@hot
# Add bundler-specific flags and config
bundler = get_bundler_type
if bundler == "webpack"
cmd += ["--config", @webpack_config]
cmd += ["--progress", "--color"] if @pretty
# Default behavior of webpack-dev-server is @hot = true
cmd += ["--hot", "only"] if @hot == "only"
cmd += ["--no-hot"] if !@hot
elsif bundler == "rspack"
# Only add config for rspack if it's not a rspack-specific command
cmd += ["--config", @webpack_config]
# Rspack supports --hot but not --no-hot or --progress/--color
cmd += ["--hot"] if @hot && @hot != false
end

cmd += @argv

Expand All @@ -90,7 +98,9 @@ def execute_cmd
end

def build_cmd
package_json.manager.native_exec_command("webpack", ["serve"])
bundler = get_bundler_type
command = bundler == "rspack" ? "rspack" : "webpack"
package_json.manager.native_exec_command(command, ["serve"])
end
end
end
3 changes: 3 additions & 0 deletions lib/shakapacker/manifest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ def lookup_pack_with_chunks(name, pack_type = {})
manifest_pack_name = manifest_name(name, manifest_pack_type)
find("entrypoints")[manifest_pack_name]["assets"][manifest_pack_type]
rescue NoMethodError
path = find(name)
return [path] if path.present?

nil
end

Expand Down
Loading