diff --git a/README.md b/README.md index 5ead90e..82942ea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # JavaScript Bundling for Rails -Use [Bun](https://bun.sh), [esbuild](https://esbuild.github.io), [rollup.js](https://rollupjs.org), or [Webpack](https://webpack.js.org) to bundle your JavaScript, then deliver it via the asset pipeline in Rails. This gem provides installers to get you going with the bundler of your choice in a new Rails application, and a convention to use `app/assets/builds` to hold your bundled output as artifacts that are not checked into source control (the installer adds this directory to `.gitignore` by default). +Use [Bun](https://bun.sh), [esbuild](https://esbuild.github.io), [rollup.js](https://rollupjs.org), [Rspack](https://rspack.dev), or [Webpack](https://webpack.js.org) to bundle your JavaScript, then deliver it via the asset pipeline in Rails. This gem provides installers to get you going with the bundler of your choice in a new Rails application, and a convention to use `app/assets/builds` to hold your bundled output as artifacts that are not checked into source control (the installer adds this directory to `.gitignore` by default). You develop using this approach by running the bundler in watch mode in a terminal with `yarn build --watch` (and your Rails server in another, if you're not using something like [puma-dev](https://github.com/puma/puma-dev)). You can also use `./bin/dev`, which will start both the Rails server and the JS build watcher (along with a CSS build watcher, if you're also using `cssbundling-rails`). @@ -12,14 +12,14 @@ This also happens in testing where the bundler attaches to the `test:prepare` ta That's it! -You can configure your bundler options in the `build` script in `package.json` or via the installer-generated `bun.config.js` for Bun, `rollup.config.js` for rollup.js or `webpack.config.json` for Webpack (esbuild does not have a default configuration format, and we don't intend to use esbuild as an API in order to hack around it). +You can configure your bundler options in the `build` script in `package.json` or via the installer-generated `bun.config.js` for Bun, `rollup.config.js` for rollup.js. `rspack.config.json` for Rspack, or `webpack.config.json` for Webpack(esbuild does not have a default configuration format, and we don't intend to use esbuild as an API in order to hack around it). If you're already using [`webpacker`](https://github.com/rails/webpacker) and you're wondering if you should migrate to `jsbundling-rails`, have a look at [the high-level comparison](./docs/comparison_with_webpacker.md). If you're looking to migrate from webpacker, see the [migration guide](https://github.com/rails/jsbundling-rails/blob/main/docs/switch_from_webpacker.md). If you want to use webpack features like [code splitting](https://webpack.js.org/guides/code-splitting/) and [hot module reloading](https://webpack.js.org/concepts/hot-module-replacement/), consider using the official fork of `webpacker`, [`shakapacker`](https://github.com/shakacode/shakapacker). ## Installation -If you are installing esbuild, rollup, or webpack, you must already have node installed on your system. You will also need npx version 7.1.0 or later. +If you are installing esbuild, rollup, rspack, or webpack, you must already have node installed on your system. You will also need npx version 7.1.0 or later. If you are using Bun, then you must have the Bun runtime already installed on your system. @@ -31,10 +31,10 @@ To get started run: ``` ``` -./bin/rails javascript:install:[bun|esbuild|rollup|webpack] +./bin/rails javascript:install:[bun|esbuild|rollup|rspack|webpack] ``` -Or, in Rails 7+, you can preconfigure your new application to use a specific bundler with `rails new myapp -j [bun|esbuild|rollup|webpack]`. +Or, in Rails 7+, you can preconfigure your new application to use a specific bundler with `rails new myapp -j [bun|esbuild|rollup|rspack|webpack]`. ## FAQ diff --git a/jsbundling-rails.gemspec b/jsbundling-rails.gemspec index ec42935..fdf1821 100644 --- a/jsbundling-rails.gemspec +++ b/jsbundling-rails.gemspec @@ -6,7 +6,7 @@ Gem::Specification.new do |spec| spec.authors = [ "David Heinemeier Hansson" ] spec.email = "david@loudthinking.com" spec.homepage = "https://github.com/rails/jsbundling-rails" - spec.summary = "Bundle and transpile JavaScript in Rails with bun, esbuild, rollup.js, or Webpack." + spec.summary = "Bundle and transpile JavaScript in Rails with bun, esbuild, rollup.js, Webpack, or Rspack." spec.license = "MIT" spec.files = Dir.glob("lib/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } diff --git a/lib/install/rspack/install.rb b/lib/install/rspack/install.rb new file mode 100644 index 0000000..f1cb504 --- /dev/null +++ b/lib/install/rspack/install.rb @@ -0,0 +1,20 @@ +apply "#{__dir__}/../install.rb" +apply "#{__dir__}/../install_procfile.rb" + +say "Install Rspack with config" +copy_file "#{__dir__}/rspack.config.js", "rspack.config.js" +run "yarn add --dev @rspack/core @rspack/cli" + +say "Add build script" +build_script = "rspack --config rspack.config.js" + +case `npx -v`.to_f +when 7.1...8.0 + run %(npm set-script build "#{build_script}") + run %(yarn build) +when (8.0..) + run %(npm pkg set scripts.build="#{build_script}") + run %(yarn build) +else + say %(Add "scripts": { "build": "#{build_script}" } to your package.json), :green +end diff --git a/lib/install/rspack/rspack.config.js b/lib/install/rspack/rspack.config.js new file mode 100644 index 0000000..a0c65b1 --- /dev/null +++ b/lib/install/rspack/rspack.config.js @@ -0,0 +1,21 @@ +const path = require("path") +const rspack = require('@rspack/core'); + +module.exports = { + mode: "production", + devtool: "source-map", + entry: { + application: "./app/javascript/application.js" + }, + output: { + filename: "[name].js", + sourceMapFilename: "[file].map", + chunkFormat: "module", + path: path.resolve(__dirname, "app/assets/builds"), + }, + plugins: [ + new rspack.optimize.LimitChunkCountPlugin({ + maxChunks: 1 + }) + ] +} diff --git a/lib/tasks/jsbundling/install.rake b/lib/tasks/jsbundling/install.rake index 9f10a4c..fc13800 100644 --- a/lib/tasks/jsbundling/install.rake +++ b/lib/tasks/jsbundling/install.rake @@ -19,5 +19,10 @@ namespace :javascript do task :webpack do system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../../install/webpack/install.rb", __dir__)}" end + + desc "Install Rspack" + task :rspack do + system "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{File.expand_path("../../install/rspack/install.rb", __dir__)}" + end end end diff --git a/test/rspack_installer_test.rb b/test/rspack_installer_test.rb new file mode 100644 index 0000000..a061f93 --- /dev/null +++ b/test/rspack_installer_test.rb @@ -0,0 +1,31 @@ +require "test_helper" +require_relative "shared_installer_tests" + +class RspackInstallerTest < ActiveSupport::TestCase + include RailsAppHelpers + include SharedInstallerTests + + test "rspack installer" do + with_new_rails_app do + out, _err = run_installer + + File.read("Procfile.dev").tap do |procfile| + assert_match "js: yarn build --watch", procfile + end + + assert_match "STUBBED gem install foreman", out + + assert File.exist?("rspack.config.js") + + assert_match %r{STUBBED yarn add.* @rspack}, out + assert_match %r{STUBBED npm (?:set-script build |pkg set scripts.build=)rspack --config rspack.config.js}, out + assert_match "STUBBED yarn build", out + end + end + + private + def run_installer + stub_bins("gem", "yarn", "npm") + run_command("bin/rails", "javascript:install:rspack") + end +end