ruact 0.0.1 → 0.0.3
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 +4 -4
- data/.codecov.yml +31 -0
- data/.github/workflows/ci.yml +160 -94
- data/.github/workflows/server-functions-bench.yml +54 -0
- data/.rubocop.yml +19 -1
- data/.rubocop_todo.yml +175 -0
- data/CHANGELOG.md +86 -5
- data/README.md +2 -0
- data/RELEASING.md +9 -3
- data/bench/server_functions_dispatch_bench.rb +309 -0
- data/bench/server_functions_dispatch_bench.results.md +121 -0
- data/docs/internal/README.md +9 -0
- data/docs/internal/decisions/server-functions-api.md +1680 -0
- data/lib/generators/ruact/install/install_generator.rb +43 -0
- data/lib/generators/ruact/install/templates/application.jsx.tt +1 -1
- data/lib/generators/ruact/install/templates/initializer.rb.tt +1 -1
- data/lib/ruact/client_manifest.rb +125 -12
- data/lib/ruact/configuration.rb +264 -23
- data/lib/ruact/controller.rb +459 -32
- data/lib/ruact/doctor.rb +34 -2
- data/lib/ruact/erb_preprocessor.rb +6 -6
- data/lib/ruact/errors.rb +89 -0
- data/lib/ruact/flight/serializer.rb +2 -2
- data/lib/ruact/html_converter.rb +131 -31
- data/lib/ruact/query.rb +107 -0
- data/lib/ruact/railtie.rb +220 -3
- data/lib/ruact/render_context.rb +30 -0
- data/lib/ruact/render_pipeline.rb +201 -59
- data/lib/ruact/routing.rb +81 -0
- data/lib/ruact/serializable.rb +11 -11
- data/lib/ruact/server.rb +341 -0
- data/lib/ruact/server_action.rb +131 -0
- data/lib/ruact/server_functions/backtrace_cleaner.rb +32 -0
- data/lib/ruact/server_functions/bucket_two_payload.rb +109 -0
- data/lib/ruact/server_functions/codegen.rb +330 -0
- data/lib/ruact/server_functions/codegen_v2.rb +176 -0
- data/lib/ruact/server_functions/endpoint_controller.rb +237 -0
- data/lib/ruact/server_functions/error_payload.rb +93 -0
- data/lib/ruact/server_functions/error_rendering.rb +188 -0
- data/lib/ruact/server_functions/error_suggestion.rb +38 -0
- data/lib/ruact/server_functions/name_bridge.rb +113 -0
- data/lib/ruact/server_functions/query_context.rb +62 -0
- data/lib/ruact/server_functions/query_dispatch.rb +248 -0
- data/lib/ruact/server_functions/registry.rb +148 -0
- data/lib/ruact/server_functions/registry_entry.rb +26 -0
- data/lib/ruact/server_functions/route_source.rb +201 -0
- data/lib/ruact/server_functions/snapshot.rb +195 -0
- data/lib/ruact/server_functions/snapshot_writer.rb +65 -0
- data/lib/ruact/server_functions/standalone_context.rb +103 -0
- data/lib/ruact/server_functions/standalone_dispatcher.rb +178 -0
- data/lib/ruact/server_functions.rb +75 -0
- data/lib/ruact/version.rb +1 -1
- data/lib/ruact/view_helper.rb +17 -9
- data/lib/ruact.rb +85 -6
- data/lib/rubocop/cop/ruact/no_shared_state.rb +1 -1
- data/lib/tasks/benchmark.rake +15 -11
- data/lib/tasks/ruact.rake +81 -0
- data/spec/benchmarks/render_pipeline_benchmark_spec.rb +1 -1
- data/spec/fixtures/flight/README.md +55 -7
- data/spec/fixtures/flight/bigint.txt +1 -0
- data/spec/fixtures/flight/infinity.txt +1 -0
- data/spec/fixtures/flight/nan.txt +1 -0
- data/spec/fixtures/flight/negative_infinity.txt +1 -0
- data/spec/fixtures/flight/undefined.txt +1 -0
- data/spec/fixtures/story_7_9_views/controller_request_spec_support/demo/show.html.erb +3 -0
- data/spec/ruact/client_manifest_spec.rb +108 -0
- data/spec/ruact/configuration_spec.rb +501 -0
- data/spec/ruact/controller_request_spec.rb +204 -0
- data/spec/ruact/controller_spec.rb +427 -39
- data/spec/ruact/doctor_spec.rb +118 -0
- data/spec/ruact/erb_preprocessor_hook_spec.rb +3 -3
- data/spec/ruact/erb_preprocessor_spec.rb +7 -7
- data/spec/ruact/errors_spec.rb +95 -0
- data/spec/ruact/flight/renderer_spec.rb +14 -3
- data/spec/ruact/flight/serializer_spec.rb +129 -88
- data/spec/ruact/html_converter_spec.rb +183 -5
- data/spec/ruact/install_generator_spec.rb +93 -0
- data/spec/ruact/query_request_spec.rb +446 -0
- data/spec/ruact/query_spec.rb +105 -0
- data/spec/ruact/railtie_spec.rb +2 -3
- data/spec/ruact/render_context_spec.rb +58 -0
- data/spec/ruact/render_pipeline_concurrency_spec.rb +78 -0
- data/spec/ruact/render_pipeline_spec.rb +784 -330
- data/spec/ruact/serializable_spec.rb +8 -8
- data/spec/ruact/server_bucket_request_spec.rb +352 -0
- data/spec/ruact/server_function_name_spec.rb +53 -0
- data/spec/ruact/server_functions/backtrace_cleaner_spec.rb +63 -0
- data/spec/ruact/server_functions/bucket_two_payload_spec.rb +200 -0
- data/spec/ruact/server_functions/codegen_spec.rb +429 -0
- data/spec/ruact/server_functions/csrf_request_spec.rb +380 -0
- data/spec/ruact/server_functions/dispatch_request_spec.rb +819 -0
- data/spec/ruact/server_functions/error_payload_spec.rb +222 -0
- data/spec/ruact/server_functions/error_suggestion_spec.rb +79 -0
- data/spec/ruact/server_functions/name_bridge_spec.rb +188 -0
- data/spec/ruact/server_functions/query_context_spec.rb +72 -0
- data/spec/ruact/server_functions/railtie_integration_spec.rb +345 -0
- data/spec/ruact/server_functions/rake_spec.rb +86 -0
- data/spec/ruact/server_functions/registry_spec.rb +199 -0
- data/spec/ruact/server_functions/route_source_spec.rb +202 -0
- data/spec/ruact/server_functions/snapshot_spec.rb +256 -0
- data/spec/ruact/server_functions/snapshot_writer_spec.rb +71 -0
- data/spec/ruact/server_functions/standalone_action_spec.rb +224 -0
- data/spec/ruact/server_functions/standalone_context_spec.rb +142 -0
- data/spec/ruact/server_functions/standalone_dispatcher_spec.rb +273 -0
- data/spec/ruact/server_rescue_request_spec.rb +416 -0
- data/spec/ruact/server_spec.rb +180 -0
- data/spec/ruact/server_upload_request_spec.rb +311 -0
- data/spec/ruact/view_helper_spec.rb +23 -17
- data/spec/spec_helper.rb +52 -1
- data/spec/support/fixtures/pixel.png +0 -0
- data/spec/support/flight_wire_parser.rb +135 -0
- data/spec/support/flight_wire_parser_spec.rb +93 -0
- data/spec/support/matchers/flight_fixture_matcher.rb +356 -0
- data/spec/support/matchers/flight_fixture_matcher_spec.rb +250 -0
- data/spec/support/rails_stub.rb +75 -5
- data/vendor/javascript/ruact-server-functions-runtime/index.d.ts +139 -0
- data/vendor/javascript/ruact-server-functions-runtime/index.js +438 -0
- data/vendor/javascript/ruact-server-functions-runtime/index.test.mjs +827 -0
- data/vendor/javascript/ruact-server-functions-runtime/package.json +22 -0
- data/vendor/javascript/vite-plugin-ruact/index.js +3 -2
- data/vendor/javascript/vite-plugin-ruact/package-lock.json +1429 -0
- data/vendor/javascript/vite-plugin-ruact/package.json +15 -0
- data/vendor/javascript/vite-plugin-ruact/server-functions-codegen.mjs +761 -0
- data/vendor/javascript/vite-plugin-ruact/server-functions-codegen.test.mjs +866 -0
- data/vendor/javascript/vite-plugin-ruact/vitest.config.mjs +15 -0
- metadata +87 -6
- data/Users/luiz/workspace/rails-rsc/gem/vendor/javascript/vite-plugin-ruact/index.js +0 -163
- data/lib/ruact/component_registry.rb +0 -31
- data/lib/tasks/rsc.rake +0 -9
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Story 8.0a — minimal vitest harness for the bundled Vite plugin.
|
|
2
|
+
//
|
|
3
|
+
// Story 6.9 (vite-plugin TS modularization) will absorb this into its larger
|
|
4
|
+
// src/ + dist/ layout. Until then, run tests against the in-tree `.mjs` source
|
|
5
|
+
// directly.
|
|
6
|
+
|
|
7
|
+
import { defineConfig } from "vitest/config";
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
test: {
|
|
11
|
+
environment: "node",
|
|
12
|
+
include: ["**/*.test.mjs", "../ruact-server-functions-runtime/*.test.mjs"],
|
|
13
|
+
globals: false,
|
|
14
|
+
},
|
|
15
|
+
});
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruact
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Luiz Garcia
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-06-10 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: nokogiri
|
|
@@ -23,27 +24,33 @@ dependencies:
|
|
|
23
24
|
- - "~>"
|
|
24
25
|
- !ruby/object:Gem::Version
|
|
25
26
|
version: '1.15'
|
|
27
|
+
description:
|
|
26
28
|
email:
|
|
27
29
|
- luizcg@gmail.com
|
|
28
30
|
executables: []
|
|
29
31
|
extensions: []
|
|
30
32
|
extra_rdoc_files: []
|
|
31
33
|
files:
|
|
34
|
+
- ".codecov.yml"
|
|
32
35
|
- ".github/workflows/ci.yml"
|
|
36
|
+
- ".github/workflows/server-functions-bench.yml"
|
|
33
37
|
- ".rubocop.yml"
|
|
34
|
-
- "
|
|
38
|
+
- ".rubocop_todo.yml"
|
|
35
39
|
- CHANGELOG.md
|
|
36
40
|
- README.md
|
|
37
41
|
- RELEASING.md
|
|
38
42
|
- Rakefile
|
|
39
43
|
- SECURITY.md
|
|
44
|
+
- bench/server_functions_dispatch_bench.rb
|
|
45
|
+
- bench/server_functions_dispatch_bench.results.md
|
|
46
|
+
- docs/internal/README.md
|
|
47
|
+
- docs/internal/decisions/server-functions-api.md
|
|
40
48
|
- lib/generators/ruact/install/install_generator.rb
|
|
41
49
|
- lib/generators/ruact/install/templates/application.jsx.tt
|
|
42
50
|
- lib/generators/ruact/install/templates/initializer.rb.tt
|
|
43
51
|
- lib/generators/ruact/install/templates/vite.config.js.tt
|
|
44
52
|
- lib/ruact.rb
|
|
45
53
|
- lib/ruact/client_manifest.rb
|
|
46
|
-
- lib/ruact/component_registry.rb
|
|
47
54
|
- lib/ruact/configuration.rb
|
|
48
55
|
- lib/ruact/controller.rb
|
|
49
56
|
- lib/ruact/doctor.rb
|
|
@@ -57,9 +64,33 @@ files:
|
|
|
57
64
|
- lib/ruact/flight/row_emitter.rb
|
|
58
65
|
- lib/ruact/flight/serializer.rb
|
|
59
66
|
- lib/ruact/html_converter.rb
|
|
67
|
+
- lib/ruact/query.rb
|
|
60
68
|
- lib/ruact/railtie.rb
|
|
69
|
+
- lib/ruact/render_context.rb
|
|
61
70
|
- lib/ruact/render_pipeline.rb
|
|
71
|
+
- lib/ruact/routing.rb
|
|
62
72
|
- lib/ruact/serializable.rb
|
|
73
|
+
- lib/ruact/server.rb
|
|
74
|
+
- lib/ruact/server_action.rb
|
|
75
|
+
- lib/ruact/server_functions.rb
|
|
76
|
+
- lib/ruact/server_functions/backtrace_cleaner.rb
|
|
77
|
+
- lib/ruact/server_functions/bucket_two_payload.rb
|
|
78
|
+
- lib/ruact/server_functions/codegen.rb
|
|
79
|
+
- lib/ruact/server_functions/codegen_v2.rb
|
|
80
|
+
- lib/ruact/server_functions/endpoint_controller.rb
|
|
81
|
+
- lib/ruact/server_functions/error_payload.rb
|
|
82
|
+
- lib/ruact/server_functions/error_rendering.rb
|
|
83
|
+
- lib/ruact/server_functions/error_suggestion.rb
|
|
84
|
+
- lib/ruact/server_functions/name_bridge.rb
|
|
85
|
+
- lib/ruact/server_functions/query_context.rb
|
|
86
|
+
- lib/ruact/server_functions/query_dispatch.rb
|
|
87
|
+
- lib/ruact/server_functions/registry.rb
|
|
88
|
+
- lib/ruact/server_functions/registry_entry.rb
|
|
89
|
+
- lib/ruact/server_functions/route_source.rb
|
|
90
|
+
- lib/ruact/server_functions/snapshot.rb
|
|
91
|
+
- lib/ruact/server_functions/snapshot_writer.rb
|
|
92
|
+
- lib/ruact/server_functions/standalone_context.rb
|
|
93
|
+
- lib/ruact/server_functions/standalone_dispatcher.rb
|
|
63
94
|
- lib/ruact/version.rb
|
|
64
95
|
- lib/ruact/view_helper.rb
|
|
65
96
|
- lib/rubocop/cop/ruact.rb
|
|
@@ -67,18 +98,22 @@ files:
|
|
|
67
98
|
- lib/rubocop/cop/ruact/no_io_in_flight.rb
|
|
68
99
|
- lib/rubocop/cop/ruact/no_shared_state.rb
|
|
69
100
|
- lib/tasks/benchmark.rake
|
|
70
|
-
- lib/tasks/
|
|
101
|
+
- lib/tasks/ruact.rake
|
|
71
102
|
- sig/ruact.rbs
|
|
72
103
|
- spec/benchmarks/baseline.json
|
|
73
104
|
- spec/benchmarks/render_pipeline_benchmark_spec.rb
|
|
74
105
|
- spec/fixtures/flight/README.md
|
|
75
106
|
- spec/fixtures/flight/array.txt
|
|
76
107
|
- spec/fixtures/flight/as_json_object.txt
|
|
108
|
+
- spec/fixtures/flight/bigint.txt
|
|
77
109
|
- spec/fixtures/flight/boolean_false.txt
|
|
78
110
|
- spec/fixtures/flight/boolean_true.txt
|
|
79
111
|
- spec/fixtures/flight/client_component_with_props.txt
|
|
80
112
|
- spec/fixtures/flight/client_reference.txt
|
|
81
113
|
- spec/fixtures/flight/hash.txt
|
|
114
|
+
- spec/fixtures/flight/infinity.txt
|
|
115
|
+
- spec/fixtures/flight/nan.txt
|
|
116
|
+
- spec/fixtures/flight/negative_infinity.txt
|
|
82
117
|
- spec/fixtures/flight/nil.txt
|
|
83
118
|
- spec/fixtures/flight/number_float.txt
|
|
84
119
|
- spec/fixtures/flight/number_integer.txt
|
|
@@ -87,7 +122,11 @@ files:
|
|
|
87
122
|
- spec/fixtures/flight/serializable_object.txt
|
|
88
123
|
- spec/fixtures/flight/string_basic.txt
|
|
89
124
|
- spec/fixtures/flight/string_dollar_escape.txt
|
|
125
|
+
- spec/fixtures/flight/undefined.txt
|
|
126
|
+
- spec/fixtures/story_7_9_views/controller_request_spec_support/demo/show.html.erb
|
|
90
127
|
- spec/ruact/client_manifest_spec.rb
|
|
128
|
+
- spec/ruact/configuration_spec.rb
|
|
129
|
+
- spec/ruact/controller_request_spec.rb
|
|
91
130
|
- spec/ruact/controller_spec.rb
|
|
92
131
|
- spec/ruact/doctor_spec.rb
|
|
93
132
|
- spec/ruact/erb_preprocessor_hook_spec.rb
|
|
@@ -97,14 +136,54 @@ files:
|
|
|
97
136
|
- spec/ruact/flight/serializer_spec.rb
|
|
98
137
|
- spec/ruact/html_converter_spec.rb
|
|
99
138
|
- spec/ruact/install_generator_spec.rb
|
|
139
|
+
- spec/ruact/query_request_spec.rb
|
|
140
|
+
- spec/ruact/query_spec.rb
|
|
100
141
|
- spec/ruact/railtie_spec.rb
|
|
142
|
+
- spec/ruact/render_context_spec.rb
|
|
143
|
+
- spec/ruact/render_pipeline_concurrency_spec.rb
|
|
101
144
|
- spec/ruact/render_pipeline_spec.rb
|
|
102
145
|
- spec/ruact/serializable_spec.rb
|
|
146
|
+
- spec/ruact/server_bucket_request_spec.rb
|
|
147
|
+
- spec/ruact/server_function_name_spec.rb
|
|
148
|
+
- spec/ruact/server_functions/backtrace_cleaner_spec.rb
|
|
149
|
+
- spec/ruact/server_functions/bucket_two_payload_spec.rb
|
|
150
|
+
- spec/ruact/server_functions/codegen_spec.rb
|
|
151
|
+
- spec/ruact/server_functions/csrf_request_spec.rb
|
|
152
|
+
- spec/ruact/server_functions/dispatch_request_spec.rb
|
|
153
|
+
- spec/ruact/server_functions/error_payload_spec.rb
|
|
154
|
+
- spec/ruact/server_functions/error_suggestion_spec.rb
|
|
155
|
+
- spec/ruact/server_functions/name_bridge_spec.rb
|
|
156
|
+
- spec/ruact/server_functions/query_context_spec.rb
|
|
157
|
+
- spec/ruact/server_functions/railtie_integration_spec.rb
|
|
158
|
+
- spec/ruact/server_functions/rake_spec.rb
|
|
159
|
+
- spec/ruact/server_functions/registry_spec.rb
|
|
160
|
+
- spec/ruact/server_functions/route_source_spec.rb
|
|
161
|
+
- spec/ruact/server_functions/snapshot_spec.rb
|
|
162
|
+
- spec/ruact/server_functions/snapshot_writer_spec.rb
|
|
163
|
+
- spec/ruact/server_functions/standalone_action_spec.rb
|
|
164
|
+
- spec/ruact/server_functions/standalone_context_spec.rb
|
|
165
|
+
- spec/ruact/server_functions/standalone_dispatcher_spec.rb
|
|
166
|
+
- spec/ruact/server_rescue_request_spec.rb
|
|
167
|
+
- spec/ruact/server_spec.rb
|
|
168
|
+
- spec/ruact/server_upload_request_spec.rb
|
|
103
169
|
- spec/ruact/view_helper_spec.rb
|
|
104
170
|
- spec/spec_helper.rb
|
|
171
|
+
- spec/support/fixtures/pixel.png
|
|
172
|
+
- spec/support/flight_wire_parser.rb
|
|
173
|
+
- spec/support/flight_wire_parser_spec.rb
|
|
105
174
|
- spec/support/matchers/flight_fixture_matcher.rb
|
|
175
|
+
- spec/support/matchers/flight_fixture_matcher_spec.rb
|
|
106
176
|
- spec/support/rails_stub.rb
|
|
177
|
+
- vendor/javascript/ruact-server-functions-runtime/index.d.ts
|
|
178
|
+
- vendor/javascript/ruact-server-functions-runtime/index.js
|
|
179
|
+
- vendor/javascript/ruact-server-functions-runtime/index.test.mjs
|
|
180
|
+
- vendor/javascript/ruact-server-functions-runtime/package.json
|
|
107
181
|
- vendor/javascript/vite-plugin-ruact/index.js
|
|
182
|
+
- vendor/javascript/vite-plugin-ruact/package-lock.json
|
|
183
|
+
- vendor/javascript/vite-plugin-ruact/package.json
|
|
184
|
+
- vendor/javascript/vite-plugin-ruact/server-functions-codegen.mjs
|
|
185
|
+
- vendor/javascript/vite-plugin-ruact/server-functions-codegen.test.mjs
|
|
186
|
+
- vendor/javascript/vite-plugin-ruact/vitest.config.mjs
|
|
108
187
|
homepage: https://luizcg.github.io/ruact/
|
|
109
188
|
licenses:
|
|
110
189
|
- MIT
|
|
@@ -115,6 +194,7 @@ metadata:
|
|
|
115
194
|
changelog_uri: https://github.com/luizcg/ruact/blob/main/CHANGELOG.md
|
|
116
195
|
bug_tracker_uri: https://github.com/luizcg/ruact/issues
|
|
117
196
|
rubygems_mfa_required: 'true'
|
|
197
|
+
post_install_message:
|
|
118
198
|
rdoc_options: []
|
|
119
199
|
require_paths:
|
|
120
200
|
- lib
|
|
@@ -129,7 +209,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
129
209
|
- !ruby/object:Gem::Version
|
|
130
210
|
version: '0'
|
|
131
211
|
requirements: []
|
|
132
|
-
rubygems_version: 3.
|
|
212
|
+
rubygems_version: 3.5.22
|
|
213
|
+
signing_key:
|
|
133
214
|
specification_version: 4
|
|
134
215
|
summary: React Server Components for Rails — render React components from ERB using
|
|
135
216
|
the Flight wire format.
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* vite-plugin-ruact
|
|
6
|
-
*
|
|
7
|
-
* Scans app/javascript/components for files with "use client" directives and
|
|
8
|
-
* emits public/react-client-manifest.json so the Rails gem can resolve
|
|
9
|
-
* component names to chunk URLs.
|
|
10
|
-
*
|
|
11
|
-
* Manifest format:
|
|
12
|
-
* {
|
|
13
|
-
* "LikeButton": {
|
|
14
|
-
* "id": "/assets/LikeButton-abc123.js",
|
|
15
|
-
* "name": "LikeButton",
|
|
16
|
-
* "chunks": ["/assets/LikeButton-abc123.js"]
|
|
17
|
-
* }
|
|
18
|
-
* }
|
|
19
|
-
*/
|
|
20
|
-
export default function ruact(options = {}) {
|
|
21
|
-
const {
|
|
22
|
-
componentsDir = "app/javascript/components",
|
|
23
|
-
manifestOutput = "public/react-client-manifest.json",
|
|
24
|
-
} = options;
|
|
25
|
-
|
|
26
|
-
let root;
|
|
27
|
-
let manifest = {};
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
name: "vite-plugin-ruact",
|
|
31
|
-
|
|
32
|
-
configResolved(config) {
|
|
33
|
-
root = config.root;
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
// During dev: build the manifest from source files
|
|
37
|
-
buildStart() {
|
|
38
|
-
manifest = buildManifest(path.resolve(root, componentsDir));
|
|
39
|
-
writeManifest(path.resolve(root, manifestOutput), manifest);
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
// During build: update with hashed chunk URLs from the bundle
|
|
43
|
-
generateBundle(_options, bundle) {
|
|
44
|
-
const updated = {};
|
|
45
|
-
|
|
46
|
-
for (const [chunkFileName, chunk] of Object.entries(bundle)) {
|
|
47
|
-
if (chunk.type !== "chunk") continue;
|
|
48
|
-
|
|
49
|
-
const facadeId = chunk.facadeModuleId;
|
|
50
|
-
if (!facadeId) continue;
|
|
51
|
-
|
|
52
|
-
// Find manifest entries whose source file matches this chunk
|
|
53
|
-
for (const [name, entry] of Object.entries(manifest)) {
|
|
54
|
-
if (facadeId === entry._sourceFile) {
|
|
55
|
-
const url = "/" + chunkFileName;
|
|
56
|
-
updated[name] = {
|
|
57
|
-
id: url,
|
|
58
|
-
name,
|
|
59
|
-
chunks: [url],
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Merge: keep entries that didn't get a hashed URL (dev mode)
|
|
66
|
-
const final = { ...manifest, ...updated };
|
|
67
|
-
// Strip internal _sourceFile field
|
|
68
|
-
for (const entry of Object.values(final)) {
|
|
69
|
-
delete entry._sourceFile;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
writeManifest(path.resolve(root, manifestOutput), final);
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
// Dev server: watch components dir and rebuild manifest on change
|
|
76
|
-
configureServer(server) {
|
|
77
|
-
const dir = path.resolve(root, componentsDir);
|
|
78
|
-
server.watcher.add(dir);
|
|
79
|
-
server.watcher.on("change", (file) => {
|
|
80
|
-
if (file.startsWith(dir)) {
|
|
81
|
-
manifest = buildManifest(dir);
|
|
82
|
-
writeManifest(path.resolve(root, manifestOutput), manifest);
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function buildManifest(componentsDir) {
|
|
90
|
-
const manifest = {};
|
|
91
|
-
|
|
92
|
-
if (!fs.existsSync(componentsDir)) return manifest;
|
|
93
|
-
|
|
94
|
-
const files = walkDir(componentsDir).filter((f) =>
|
|
95
|
-
/\.(jsx?|tsx?)$/.test(f)
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
for (const file of files) {
|
|
99
|
-
const content = fs.readFileSync(file, "utf8");
|
|
100
|
-
if (!hasUseClient(content)) continue;
|
|
101
|
-
|
|
102
|
-
const exports = extractExportNames(content);
|
|
103
|
-
const relUrl = "/" + path.relative(componentsDir, file);
|
|
104
|
-
|
|
105
|
-
for (const name of exports) {
|
|
106
|
-
manifest[name] = {
|
|
107
|
-
id: relUrl,
|
|
108
|
-
name,
|
|
109
|
-
chunks: [relUrl],
|
|
110
|
-
_sourceFile: file, // used during build to match hashed chunks
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return manifest;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function hasUseClient(content) {
|
|
119
|
-
// "use client" must appear as a directive at the top of the file
|
|
120
|
-
return /^\s*["']use client["']/m.test(content);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function extractExportNames(content) {
|
|
124
|
-
const names = new Set();
|
|
125
|
-
|
|
126
|
-
// export function Foo
|
|
127
|
-
// export const Foo
|
|
128
|
-
// export class Foo
|
|
129
|
-
const namedRe = /export\s+(?:default\s+)?(?:function|const|class|let|var)\s+([A-Z][A-Za-z0-9]*)/g;
|
|
130
|
-
let m;
|
|
131
|
-
while ((m = namedRe.exec(content)) !== null) {
|
|
132
|
-
names.add(m[1]);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// export { Foo, Bar }
|
|
136
|
-
const bracedRe = /export\s+\{([^}]+)\}/g;
|
|
137
|
-
while ((m = bracedRe.exec(content)) !== null) {
|
|
138
|
-
for (const part of m[1].split(",")) {
|
|
139
|
-
const name = part.trim().split(/\s+as\s+/).pop().trim();
|
|
140
|
-
if (/^[A-Z]/.test(name)) names.add(name);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return Array.from(names);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function writeManifest(outputPath, manifest) {
|
|
148
|
-
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
149
|
-
fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function walkDir(dir) {
|
|
153
|
-
const results = [];
|
|
154
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
155
|
-
const full = path.join(dir, entry.name);
|
|
156
|
-
if (entry.isDirectory()) {
|
|
157
|
-
results.push(...walkDir(full));
|
|
158
|
-
} else {
|
|
159
|
-
results.push(full);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return results;
|
|
163
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Ruact
|
|
4
|
-
# Holds the client components encountered during ERB rendering.
|
|
5
|
-
# Thread-local so it's safe under concurrent requests.
|
|
6
|
-
module ComponentRegistry
|
|
7
|
-
THREAD_KEY = :__rsc_component_registry__
|
|
8
|
-
|
|
9
|
-
def self.start
|
|
10
|
-
Thread.current[THREAD_KEY] = [] # rubocop:disable Ruact/NoSharedState -- TODO: refactor to explicit arg passing (NFR8)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def self.register(name, props)
|
|
14
|
-
token = "__RSC_#{components.length}__"
|
|
15
|
-
components << { token: token, name: name, props: props }
|
|
16
|
-
token
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.components
|
|
20
|
-
Thread.current[THREAD_KEY] ||= [] # rubocop:disable Ruact/NoSharedState -- TODO: refactor to explicit arg passing (NFR8)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def self.reset
|
|
24
|
-
Thread.current[THREAD_KEY] = nil # rubocop:disable Ruact/NoSharedState -- TODO: refactor to explicit arg passing (NFR8)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.by_token(token)
|
|
28
|
-
components.find { |c| c[:token] == token }
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|