rspack_rails 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3eb3563c7877029531bd93b2ed9036ce92b8a89c4008600ea251dfad3b641ff
4
- data.tar.gz: 5d210e018044764c5e2f3f94cd06e3cb296d16e1da97d010b9e18907c1416644
3
+ metadata.gz: b7f84e6f9280bcf6d3fbd54f2a3a267a817e7c333d4c89a70c8e171b477f3e85
4
+ data.tar.gz: '09e2d5eb77331777f33a1b58478ba1bac7774ffe83308b0f97236653fb80f534'
5
5
  SHA512:
6
- metadata.gz: 5dc66b20aadec8d3695d98448c80eb39e31a0d2c55d693002c6d318ac25c95a96ff81b8ac4829d0e60a6e09af7959ceca287f1f5c440a09af333069b6ffa0458
7
- data.tar.gz: fc965e7fd0ddd80f60d120b77cf135ce9e4da264b87e66e298767c5e14e367cf9bbfda64130abc6d03d2f0368528196826e5425f8dcae8ddbe36714e9c534da8
6
+ metadata.gz: 79928a7186a0b752296a5d82cf5e570ce87730a24ce2c1c515c4490be4585fe512790b68b4bdef81f9a76c608a73a615d4db75d7891889092f1a8a56a7a76e66
7
+ data.tar.gz: 11660d1b0a381e43a789b8b5b2b92593784755cbfda2d00f32f1646b784dd39d959329fa2845febf900e4e6af38e4879c816832ecb5f2c944e1f8d6241ffbe47
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.0] - 2026-11-13
4
+
5
+ - CSS imported from JavaScript is extracted to `app/assets/builds/<entry>.bundle.css` and hot-reloaded under `rspack serve`; `*.module.css` are CSS modules
6
+ - **Changed:** `rspack_stylesheet_tag "application"` now links `application.bundle.css` (was `application.css`)
7
+ - TypeScript: `.ts` files and `*_controller.ts` Stimulus controllers compile with the built-in SWC loader
8
+ - `rspack:install:typescript` adds `tsconfig.json`, `typescript` and a `typecheck` script
9
+ - Dev server writes bundles to disk so `app/assets/builds` stays current
10
+ - `rspack:doctor` warns when `application.bundle.css` is built but not linked
11
+ - Existing apps: re-run `bin/rails rspack:install` (and `rspack:install:stimulus`) and accept the new `rspack.config.mjs` / `autoload.js`
12
+
3
13
  ## [0.1.0] - 2026-11-13
4
14
 
5
15
  - `rspack:doctor`: checks Node.js against rspack's `engines`, packages, config, entry, build output, layout, Procfile.dev, Stimulus and the dev server
data/README.md CHANGED
@@ -57,17 +57,44 @@ end
57
57
  bin/rails rspack:install:stimulus
58
58
  ```
59
59
 
60
- This installs `@hotwired/stimulus` and adds `app/javascript/controllers/autoload.js`, imported from `application.js`. Every `*_controller.js` under `app/javascript/controllers` is registered automatically, with the usual naming (`admin/user_card_controller.js` becomes `admin--user-card`). There is no manifest to keep up to date.
60
+ This installs `@hotwired/stimulus` and adds `app/javascript/controllers/autoload.js`, imported from `application.js`. Every `*_controller.js` (or `.ts`) under `app/javascript/controllers` is registered automatically, with the usual naming (`admin/user_card_controller.js` becomes `admin--user-card`). There is no manifest to keep up to date.
61
61
 
62
62
  Under `rspack serve`, editing a controller or adding a new one hot-swaps it in the open page without a reload, so form input and other page state survive.
63
63
 
64
64
  If `application.js` imported `./controllers` (the stimulus-rails index), the installer switches it to `./controllers/autoload`. stimulus-rails may still rewrite `controllers/index.js` when you run `bin/rails generate stimulus`, but nothing imports that file any more.
65
65
 
66
+ ### CSS
67
+
68
+ Import CSS from your JavaScript and rspack extracts it to `app/assets/builds/<entry>.bundle.css`:
69
+
70
+ ```js
71
+ // app/javascript/application.js
72
+ import "./styles/application.css"
73
+ ```
74
+
75
+ ```erb
76
+ <%= rspack_stylesheet_tag "application" %>
77
+ ```
78
+
79
+ `*.module.css` files are compiled as CSS modules. Under `rspack serve`, CSS changes are applied without a page reload.
80
+
81
+ The `.bundle` suffix keeps the output from clashing with `app/assets/stylesheets/application.css`. Rails 8's default `stylesheet_link_tag :app` links every CSS file under `app/assets`, so it also links the bundle. That is harmless: the dev server keeps `app/assets/builds` up to date and its own link comes later in the cascade. A rule you delete keeps applying until the next reload.
82
+
83
+ ### TypeScript
84
+
85
+ `.ts` files compile out of the box with Rspack's built-in SWC loader, including Stimulus controllers (`*_controller.ts`). SWC strips types without checking them. For type checking:
86
+
87
+ ```bash
88
+ bin/rails rspack:install:typescript # tsconfig.json, typescript, "typecheck" script
89
+ npm run typecheck
90
+ ```
91
+
66
92
  ### Tasks
67
93
 
68
94
  | Task | What it does |
69
95
  |---|---|
70
96
  | `bin/rails rspack:install:stimulus` | Sets up Stimulus with controller autoloading |
97
+ | `bin/rails rspack:install:typescript` | Adds tsconfig.json, typescript and a `typecheck` script |
71
98
  | `bin/rails rspack:doctor` | Checks Node.js, packages, config, layout, Procfile and dev server |
72
99
  | `bin/rails rspack:build` | Installs JS dependencies, then runs `build` |
73
100
  | `bin/rails rspack:clobber` | Removes rspack output from `app/assets/builds` |
@@ -22,14 +22,41 @@ export default defineConfig({
22
22
  path: path.resolve(root, "app/assets/builds"),
23
23
  filename: "[name].js",
24
24
  // ".digested" tells Propshaft the file is already fingerprinted.
25
- chunkFilename: "[name]-[contenthash].digested.js",
25
+ chunkFilename: "[name]-[contenthash].digested.js",
26
+ // CSS imported from JavaScript. ".bundle" avoids clashing with
27
+ // app/assets/stylesheets/application.css in Propshaft.
28
+ cssFilename: "[name].bundle.css",
29
+ cssChunkFilename: "[name]-[contenthash].digested.css",
26
30
  // Under `rspack serve`, chunks and hot updates load from the dev server.
27
31
  publicPath: isDevServer ? `http://${host}:${port}/` : "/assets/",
28
32
  },
33
+ resolve: {
34
+ extensions: ["...", ".ts"],
35
+ },
36
+ module: {
37
+ rules: [
38
+ {
39
+ // Transpile TypeScript with Rspack's built-in SWC (no type checking).
40
+ test: /\.ts$/,
41
+ exclude: /node_modules/,
42
+ loader: "builtin:swc-loader",
43
+ options: { jsc: { parser: { syntax: "typescript" } } },
44
+ type: "javascript/auto",
45
+ },
46
+ {
47
+ // Native CSS; *.module.css files become CSS modules.
48
+ test: /\.css$/,
49
+ type: "css/auto",
50
+ },
51
+ ],
52
+ },
29
53
  devServer: {
30
54
  host,
31
55
  port,
32
56
  hot: true,
57
+ // Keep app/assets/builds current while the dev server runs, so Propshaft
58
+ // (and `stylesheet_link_tag :app`) never serve a stale bundle.
59
+ devMiddleware: { writeToDisk: true },
33
60
  allowedHosts: "all",
34
61
  headers: { "Access-Control-Allow-Origin": "*" },
35
62
  client: {
@@ -1,16 +1,16 @@
1
- // Registers every app/javascript/controllers/**/*_controller.js with Stimulus.
1
+ // Registers every app/javascript/controllers/**/*_controller.{js,ts} with Stimulus.
2
2
  // Managed by rspack_rails: new controllers need no manual import, and edited
3
3
  // controllers are hot-swapped under `rspack serve` without a page reload.
4
4
  import { application } from "./application"
5
5
 
6
6
  const controllers = () =>
7
- import.meta.webpackContext("./", { recursive: true, regExp: /_controller\.js$/ })
7
+ import.meta.webpackContext("./", { recursive: true, regExp: /_controller\.[jt]s$/ })
8
8
 
9
9
  // "./users/profile_controller.js" -> "users--profile"
10
10
  const identifierFor = (key) =>
11
11
  key
12
12
  .replace(/^\.\//, "")
13
- .replace(/_controller\.js$/, "")
13
+ .replace(/_controller\.[jt]s$/, "")
14
14
  .replace(/\//g, "--")
15
15
  .replace(/_/g, "-")
16
16
 
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "types": ["@rspack/core/module"],
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "isolatedModules": true,
11
+ "skipLibCheck": true
12
+ },
13
+ "include": ["app/javascript/**/*.ts"]
14
+ }
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Rails application template run by `bin/rails rspack:install:typescript`.
4
+ require "json"
5
+
6
+ pm = RspackRails::PackageManager.detect(Rails.root)
7
+
8
+ say "Adding tsconfig.json"
9
+ copy_file "#{__dir__}/typescript/tsconfig.json", "tsconfig.json"
10
+
11
+ say "Adding typecheck script"
12
+ package = JSON.parse(File.read("package.json"))
13
+ (package["scripts"] ||= {})["typecheck"] = "tsc --noEmit"
14
+ File.write("package.json", "#{JSON.pretty_generate(package)}\n")
15
+
16
+ say "Installing typescript"
17
+ run pm.add_dev_command("typescript")
18
+
19
+ say "TypeScript ready. Rspack compiles .ts files; run `#{pm.run_command("typecheck")}` to type-check.", :green
@@ -9,6 +9,7 @@ module RspackRails
9
9
  # Inspects a Rails app's rspack setup and reports what is missing.
10
10
  class Doctor
11
11
  Check = Struct.new(:status, :name, :detail, :hint)
12
+ LAYOUT = "app/views/layouts/application.html.erb"
12
13
  SYMBOLS = { ok: "✓", warn: "!", error: "✗" }.freeze
13
14
 
14
15
  def initialize(root, config: RspackRails.config, dev_server: RspackRails.dev_server, node_version: nil)
@@ -21,7 +22,7 @@ module RspackRails
21
22
  def checks
22
23
  @checks ||= [
23
24
  node_check, package_check(:cli), package_check(:core), package_check(:"dev-server"),
24
- config_check, scripts_check, entry_check, build_check, layout_check, procfile_check,
25
+ config_check, scripts_check, entry_check, build_check, layout_check, stylesheet_check, procfile_check,
25
26
  stimulus_check, dev_server_check
26
27
  ].compact
27
28
  end
@@ -105,7 +106,7 @@ module RspackRails
105
106
  end
106
107
 
107
108
  def layout_check
108
- layout = read("app/views/layouts/application.html.erb")
109
+ layout = read(LAYOUT)
109
110
  return Check.new(:warn, "Layout", "app/views/layouts/application.html.erb not found") unless layout
110
111
 
111
112
  if layout.include?("javascript_importmap_tags")
@@ -118,6 +119,16 @@ module RspackRails
118
119
  %(Add <%= rspack_javascript_tag "application" %> to get the dev server and HMR))
119
120
  end
120
121
 
122
+ def stylesheet_check
123
+ return unless exist?("app/assets/builds/application.bundle.css")
124
+
125
+ linked = read(LAYOUT)&.include?("rspack_stylesheet_tag")
126
+ return Check.new(:ok, "Stylesheet", "uses rspack_stylesheet_tag") if linked
127
+
128
+ Check.new(:warn, "Stylesheet", "application.bundle.css is built but not linked",
129
+ %(Add <%= rspack_stylesheet_tag "application" %> to your layout))
130
+ end
131
+
121
132
  def procfile_check
122
133
  procfile = read("Procfile.dev")
123
134
  if procfile&.match?(/^js: .*\bdev$/)
@@ -12,11 +12,16 @@ module RspackRails
12
12
  "\n")
13
13
  end
14
14
 
15
+ # Links the CSS that rspack extracts from an entry's imports
16
+ # (app/assets/builds/<entry>.bundle.css).
15
17
  def rspack_stylesheet_tag(*entries, **options)
16
- return stylesheet_link_tag(*entries, **options) unless RspackRails.dev_server.running?
18
+ unless RspackRails.dev_server.running?
19
+ return stylesheet_link_tag(*entries.map { |entry| "#{entry}.bundle" }, **options)
20
+ end
17
21
 
18
- safe_join(entries.map { |entry| stylesheet_link_tag(RspackRails.dev_server.url("#{entry}.css"), **options) },
19
- "\n")
22
+ safe_join(entries.map do |entry|
23
+ stylesheet_link_tag(RspackRails.dev_server.url("#{entry}.bundle.css"), **options)
24
+ end, "\n")
20
25
  end
21
26
  end
22
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RspackRails
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -15,6 +15,13 @@ namespace :rspack do
15
15
  system(RbConfig.ruby, "./bin/rails", "app:template", "LOCATION=#{template}") ||
16
16
  raise(RspackRails::Error, "rspack:install:stimulus failed")
17
17
  end
18
+
19
+ desc "Set up TypeScript type checking (tsconfig.json, typescript, typecheck script)"
20
+ task :typescript do
21
+ template = File.expand_path("../install/typescript.rb", __dir__)
22
+ system(RbConfig.ruby, "./bin/rails", "app:template", "LOCATION=#{template}") ||
23
+ raise(RspackRails::Error, "rspack:install:typescript failed")
24
+ end
18
25
  end
19
26
 
20
27
  desc "Check the rspack setup of this app"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspack_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tungnt
@@ -51,6 +51,8 @@ files:
51
51
  - lib/install/stimulus/application.js
52
52
  - lib/install/stimulus/autoload.js
53
53
  - lib/install/stimulus/hello_controller.js
54
+ - lib/install/typescript.rb
55
+ - lib/install/typescript/tsconfig.json
54
56
  - lib/rspack_rails.rb
55
57
  - lib/rspack_rails/configuration.rb
56
58
  - lib/rspack_rails/dev_server.rb