react_on_rails_pro 16.4.0.rc.6 → 16.4.0.rc.7
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/CONTRIBUTING.md +2 -2
- data/Gemfile.development_dependencies +1 -1
- data/Gemfile.lock +20 -18
- data/app/helpers/react_on_rails_pro_helper.rb +20 -8
- data/docs/installation.md +35 -16
- data/docs/react-server-components/glossary.md +10 -0
- data/docs/streaming-server-rendering.md +31 -0
- data/docs/troubleshooting.md +8 -0
- data/docs/updating.md +10 -0
- data/lib/react_on_rails_pro/concerns/rsc_payload_renderer.rb +14 -1
- data/lib/react_on_rails_pro/concerns/stream.rb +49 -12
- data/lib/react_on_rails_pro/engine.rb +58 -0
- data/lib/react_on_rails_pro/request.rb +10 -0
- data/lib/react_on_rails_pro/stream_request.rb +10 -1
- data/lib/react_on_rails_pro/version.rb +1 -1
- metadata +5 -8
- data/docs/contributors-info/onboarding-customers.md +0 -7
- data/docs/contributors-info/releasing.md +0 -41
- data/docs/contributors-info/style.md +0 -41
- /data/app/views/react_on_rails_pro/{rsc_payload.html.erb → rsc_payload.text.erb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d8d5365a9653da4cdc8ea771167d5b26dd03602c4977d7fea747ec2a07cc6900
|
|
4
|
+
data.tar.gz: 57afd9dc58238f94d2d008cc01900596a18cb63894786cb60ce99471902500c9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fb6bb5c6f0b45d62151be232c4ddf9b8343aaa086162e1f8292f9468b2902c146a5668c1b1e79753a919a6063eae8ddbf1a19ad4cb8e178734e77fb9303efa1d
|
|
7
|
+
data.tar.gz: 9da57b6e9750c1f5fe4f830b375bfd2dd7e7e07b6c2135b5e9a30ec5156f70c4e41180a8737a205150bf7b8687dfa1b16c035bb88eb03fd3d89dbdc71e25c625
|
data/CONTRIBUTING.md
CHANGED
|
@@ -119,7 +119,7 @@ script/ci-changes-detector origin/master
|
|
|
119
119
|
- Push Pro changes without testing locally first
|
|
120
120
|
- Modify both Pro and main gem without running full tests
|
|
121
121
|
|
|
122
|
-
For comprehensive CI documentation, see [`../
|
|
122
|
+
For comprehensive CI documentation, see [`../internal/contributor-info/ci-optimization.md`](../internal/contributor-info/ci-optimization.md) in the repository root.
|
|
123
123
|
|
|
124
124
|
# IDE/Editor Setup
|
|
125
125
|
|
|
@@ -395,5 +395,5 @@ rake release[17.0.0,false,verdaccio]
|
|
|
395
395
|
|
|
396
396
|
For complete documentation, see:
|
|
397
397
|
|
|
398
|
-
- [Root Release Documentation](../
|
|
398
|
+
- [Root Release Documentation](../internal/contributor-info/releasing.md)
|
|
399
399
|
- Run `rake -D release` for inline help
|
data/Gemfile.lock
CHANGED
|
@@ -9,7 +9,7 @@ GIT
|
|
|
9
9
|
PATH
|
|
10
10
|
remote: ..
|
|
11
11
|
specs:
|
|
12
|
-
react_on_rails (16.4.0.rc.
|
|
12
|
+
react_on_rails (16.4.0.rc.7)
|
|
13
13
|
addressable
|
|
14
14
|
connection_pool
|
|
15
15
|
execjs (~> 2.5)
|
|
@@ -20,7 +20,7 @@ PATH
|
|
|
20
20
|
PATH
|
|
21
21
|
remote: .
|
|
22
22
|
specs:
|
|
23
|
-
react_on_rails_pro (16.4.0.rc.
|
|
23
|
+
react_on_rails_pro (16.4.0.rc.7)
|
|
24
24
|
addressable
|
|
25
25
|
async (>= 2.6)
|
|
26
26
|
connection_pool
|
|
@@ -29,7 +29,7 @@ PATH
|
|
|
29
29
|
httpx (~> 1.5)
|
|
30
30
|
jwt (~> 2.7)
|
|
31
31
|
rainbow
|
|
32
|
-
react_on_rails (= 16.4.0.rc.
|
|
32
|
+
react_on_rails (= 16.4.0.rc.7)
|
|
33
33
|
|
|
34
34
|
GEM
|
|
35
35
|
remote: https://rubygems.org/
|
|
@@ -165,7 +165,7 @@ GEM
|
|
|
165
165
|
drb (2.2.3)
|
|
166
166
|
equivalent-xml (0.6.0)
|
|
167
167
|
nokogiri (>= 1.4.3)
|
|
168
|
-
erb (6.0.
|
|
168
|
+
erb (6.0.2)
|
|
169
169
|
erubi (1.13.1)
|
|
170
170
|
execjs (2.10.0)
|
|
171
171
|
fakefs (2.8.0)
|
|
@@ -194,8 +194,9 @@ GEM
|
|
|
194
194
|
concurrent-ruby (~> 1.0)
|
|
195
195
|
io-console (0.8.2)
|
|
196
196
|
io-event (1.14.2)
|
|
197
|
-
irb (1.
|
|
197
|
+
irb (1.17.0)
|
|
198
198
|
pp (>= 0.6.0)
|
|
199
|
+
prism (>= 1.3.0)
|
|
199
200
|
rdoc (>= 4.0.0)
|
|
200
201
|
reline (>= 0.4.2)
|
|
201
202
|
jbuilder (2.12.0)
|
|
@@ -230,7 +231,8 @@ GEM
|
|
|
230
231
|
method_source (1.1.0)
|
|
231
232
|
metrics (0.15.0)
|
|
232
233
|
mini_mime (1.1.5)
|
|
233
|
-
minitest (6.0.
|
|
234
|
+
minitest (6.0.2)
|
|
235
|
+
drb (~> 2.0)
|
|
234
236
|
prism (~> 1.5)
|
|
235
237
|
mize (0.4.1)
|
|
236
238
|
protocol (~> 2.0)
|
|
@@ -247,11 +249,11 @@ GEM
|
|
|
247
249
|
net-smtp (0.5.1)
|
|
248
250
|
net-protocol
|
|
249
251
|
nio4r (2.7.5)
|
|
250
|
-
nokogiri (1.19.
|
|
252
|
+
nokogiri (1.19.1-arm64-darwin)
|
|
251
253
|
racc (~> 1.4)
|
|
252
|
-
nokogiri (1.19.
|
|
254
|
+
nokogiri (1.19.1-x86_64-darwin)
|
|
253
255
|
racc (~> 1.4)
|
|
254
|
-
nokogiri (1.19.
|
|
256
|
+
nokogiri (1.19.1-x86_64-linux-gnu)
|
|
255
257
|
racc (~> 1.4)
|
|
256
258
|
package_json (0.2.0)
|
|
257
259
|
parallel (1.27.0)
|
|
@@ -262,7 +264,7 @@ GEM
|
|
|
262
264
|
pp (0.6.3)
|
|
263
265
|
prettyprint
|
|
264
266
|
prettyprint (0.2.0)
|
|
265
|
-
prism (1.
|
|
267
|
+
prism (1.9.0)
|
|
266
268
|
protocol (2.0.0)
|
|
267
269
|
ruby_parser (~> 3.0)
|
|
268
270
|
pry (0.14.2)
|
|
@@ -282,7 +284,7 @@ GEM
|
|
|
282
284
|
puma (6.5.0)
|
|
283
285
|
nio4r (~> 2.0)
|
|
284
286
|
racc (1.8.1)
|
|
285
|
-
rack (3.2.
|
|
287
|
+
rack (3.2.5)
|
|
286
288
|
rack-proxy (0.7.7)
|
|
287
289
|
rack
|
|
288
290
|
rack-session (2.1.1)
|
|
@@ -310,8 +312,8 @@ GEM
|
|
|
310
312
|
activesupport (>= 5.0.0)
|
|
311
313
|
minitest
|
|
312
314
|
nokogiri (>= 1.6)
|
|
313
|
-
rails-html-sanitizer (1.
|
|
314
|
-
loofah (~> 2.
|
|
315
|
+
rails-html-sanitizer (1.7.0)
|
|
316
|
+
loofah (~> 2.25)
|
|
315
317
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
316
318
|
railties (7.2.3)
|
|
317
319
|
actionpack (= 7.2.3)
|
|
@@ -330,7 +332,7 @@ GEM
|
|
|
330
332
|
ffi (~> 1.0)
|
|
331
333
|
rbs (3.9.5)
|
|
332
334
|
logger
|
|
333
|
-
rdoc (7.
|
|
335
|
+
rdoc (7.2.0)
|
|
334
336
|
erb
|
|
335
337
|
psych (>= 4.0.0)
|
|
336
338
|
tsort
|
|
@@ -414,9 +416,9 @@ GEM
|
|
|
414
416
|
rexml (~> 3.2, >= 3.2.5)
|
|
415
417
|
rubyzip (>= 1.2.2, < 3.0)
|
|
416
418
|
websocket (~> 1.0)
|
|
417
|
-
semantic_range (3.1.
|
|
419
|
+
semantic_range (3.1.1)
|
|
418
420
|
sexp_processor (4.17.1)
|
|
419
|
-
shakapacker (9.
|
|
421
|
+
shakapacker (9.6.1)
|
|
420
422
|
activesupport (>= 5.2)
|
|
421
423
|
package_json
|
|
422
424
|
rack-proxy (>= 0.6.1)
|
|
@@ -483,7 +485,7 @@ GEM
|
|
|
483
485
|
xpath (3.2.0)
|
|
484
486
|
nokogiri (~> 1.8)
|
|
485
487
|
yard (0.9.36)
|
|
486
|
-
zeitwerk (2.7.
|
|
488
|
+
zeitwerk (2.7.5)
|
|
487
489
|
|
|
488
490
|
PLATFORMS
|
|
489
491
|
arm64-darwin-24
|
|
@@ -531,7 +533,7 @@ DEPENDENCIES
|
|
|
531
533
|
sass-rails
|
|
532
534
|
scss_lint
|
|
533
535
|
selenium-webdriver (= 4.9.0)
|
|
534
|
-
shakapacker (= 9.
|
|
536
|
+
shakapacker (= 9.6.1)
|
|
535
537
|
spring
|
|
536
538
|
spring-watcher-listen
|
|
537
539
|
sprockets
|
|
@@ -314,7 +314,13 @@ module ReactOnRailsProHelper
|
|
|
314
314
|
|
|
315
315
|
# Enqueue remaining chunks asynchronously
|
|
316
316
|
@async_barrier.async do
|
|
317
|
-
rest_chunks.each
|
|
317
|
+
rest_chunks.each do |chunk|
|
|
318
|
+
break if response.stream.closed?
|
|
319
|
+
|
|
320
|
+
@main_output_queue.enqueue(chunk)
|
|
321
|
+
end
|
|
322
|
+
rescue Async::Queue::ClosedError
|
|
323
|
+
# Queue closed due to error/disconnect in another component — stop enqueuing
|
|
318
324
|
end
|
|
319
325
|
|
|
320
326
|
# Return first chunk directly
|
|
@@ -436,8 +442,8 @@ module ReactOnRailsProHelper
|
|
|
436
442
|
# Start an async task on the barrier to stream all chunks
|
|
437
443
|
@async_barrier.async do
|
|
438
444
|
stream = yield
|
|
439
|
-
process_stream_chunks(stream, first_chunk_var, all_chunks)
|
|
440
|
-
on_complete&.call(all_chunks)
|
|
445
|
+
fully_consumed = process_stream_chunks(stream, first_chunk_var, all_chunks)
|
|
446
|
+
on_complete&.call(all_chunks) if fully_consumed
|
|
441
447
|
rescue StandardError => e
|
|
442
448
|
# Propagate the error to the calling fiber via the variable.
|
|
443
449
|
# Async::Variable can only be resolved once — if it was already resolved
|
|
@@ -457,9 +463,9 @@ module ReactOnRailsProHelper
|
|
|
457
463
|
end
|
|
458
464
|
end
|
|
459
465
|
|
|
460
|
-
# Wait for and return the first chunk (blocking)
|
|
461
|
-
|
|
462
|
-
result = first_chunk_var.
|
|
466
|
+
# Wait for and return the first chunk (blocking).
|
|
467
|
+
# Async::Variable#wait blocks until resolved, then returns the stored value.
|
|
468
|
+
result = first_chunk_var.wait
|
|
463
469
|
|
|
464
470
|
# If the async task stored an exception (pre-first-chunk error), raise it now.
|
|
465
471
|
# This happens BEFORE response.stream.write(template_string) in
|
|
@@ -470,12 +476,17 @@ module ReactOnRailsProHelper
|
|
|
470
476
|
result
|
|
471
477
|
end
|
|
472
478
|
|
|
479
|
+
# Returns true if the stream was fully consumed, false if aborted (client disconnect).
|
|
480
|
+
# When false, callers must NOT invoke on_complete to avoid caching partial data.
|
|
473
481
|
def process_stream_chunks(stream, first_chunk_var, all_chunks)
|
|
474
482
|
is_first = true
|
|
475
483
|
|
|
476
484
|
stream.each_chunk do |chunk|
|
|
477
|
-
#
|
|
478
|
-
|
|
485
|
+
# Client disconnected — abort without caching partial results
|
|
486
|
+
if response.stream.closed?
|
|
487
|
+
first_chunk_var.value = nil if is_first
|
|
488
|
+
return false
|
|
489
|
+
end
|
|
479
490
|
|
|
480
491
|
all_chunks&.push(chunk)
|
|
481
492
|
|
|
@@ -491,6 +502,7 @@ module ReactOnRailsProHelper
|
|
|
491
502
|
|
|
492
503
|
# Handle case where stream has no chunks
|
|
493
504
|
first_chunk_var.value = nil if is_first
|
|
505
|
+
true
|
|
494
506
|
end
|
|
495
507
|
|
|
496
508
|
def internal_stream_react_component(component_name, options = {})
|
data/docs/installation.md
CHANGED
|
@@ -8,7 +8,8 @@ Check the [CHANGELOG](https://github.com/shakacode/react_on_rails/blob/master/CH
|
|
|
8
8
|
|
|
9
9
|
## Version Format
|
|
10
10
|
|
|
11
|
-
For the below
|
|
11
|
+
For the commands below, choose versions from the CHANGELOG and replace placeholders like
|
|
12
|
+
`<gem_version>` and `<npm_version>`. Note that for pre-release versions:
|
|
12
13
|
|
|
13
14
|
- Gems use all periods: `16.2.0.beta.1`
|
|
14
15
|
- NPM packages use dashes: `16.2.0-beta.1`
|
|
@@ -22,11 +23,15 @@ The easiest way to set up React on Rails Pro is using the generator. This automa
|
|
|
22
23
|
For new React on Rails apps, use the `--pro` flag:
|
|
23
24
|
|
|
24
25
|
```bash
|
|
25
|
-
# Add the Pro gem
|
|
26
|
-
bundle add react_on_rails_pro
|
|
26
|
+
# Add the Pro gem first (pin exact version)
|
|
27
|
+
bundle add react_on_rails_pro --version="<gem_version>" --strict
|
|
28
|
+
|
|
29
|
+
# The generator requires a clean git working tree
|
|
30
|
+
git add .
|
|
31
|
+
git commit -m "Prepare app for React on Rails Pro install"
|
|
27
32
|
|
|
28
33
|
# Run the generator with --pro
|
|
29
|
-
rails generate react_on_rails:install --pro
|
|
34
|
+
bundle exec rails generate react_on_rails:install --pro
|
|
30
35
|
```
|
|
31
36
|
|
|
32
37
|
This creates the Pro initializer, node-renderer.js, installs npm packages, and adds the Node Renderer to Procfile.dev.
|
|
@@ -37,17 +42,31 @@ For existing React on Rails apps, use the standalone Pro generator:
|
|
|
37
42
|
|
|
38
43
|
```bash
|
|
39
44
|
# Add the Pro gem to your Gemfile
|
|
40
|
-
bundle add react_on_rails_pro
|
|
45
|
+
bundle add react_on_rails_pro --version="<gem_version>" --strict
|
|
41
46
|
|
|
42
47
|
# Run the Pro generator
|
|
43
|
-
rails generate react_on_rails:pro
|
|
48
|
+
bundle exec rails generate react_on_rails:pro
|
|
44
49
|
```
|
|
45
50
|
|
|
46
51
|
The standalone generator adds Pro-specific files and modifies your existing webpack configs (`serverWebpackConfig.js` and `ServerClientOrBoth.js`) to enable Pro features like `libraryTarget: 'commonjs2'` and `target = 'node'`.
|
|
47
52
|
|
|
48
53
|
## After Running the Generator
|
|
49
54
|
|
|
50
|
-
|
|
55
|
+
Run a quick validation, then configure your license.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
bundle exec rails react_on_rails:doctor
|
|
59
|
+
bin/shakapacker
|
|
60
|
+
bin/dev
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
If port 3000 is already in use:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
PORT=3001 bin/dev
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Set the license environment variable:
|
|
51
70
|
|
|
52
71
|
```bash
|
|
53
72
|
export REACT_ON_RAILS_PRO_LICENSE="your-license-token-here"
|
|
@@ -61,10 +80,10 @@ RSC requires React on Rails Pro and React 19.0.x. To add RSC support, use `--rsc
|
|
|
61
80
|
|
|
62
81
|
```bash
|
|
63
82
|
# Fresh install with RSC
|
|
64
|
-
rails generate react_on_rails:install --rsc
|
|
83
|
+
bundle exec rails generate react_on_rails:install --rsc
|
|
65
84
|
|
|
66
85
|
# Or add RSC to existing Pro app
|
|
67
|
-
rails generate react_on_rails:rsc
|
|
86
|
+
bundle exec rails generate react_on_rails:rsc
|
|
68
87
|
```
|
|
69
88
|
|
|
70
89
|
The RSC generator creates `rscWebpackConfig.js`, adds `RSCWebpackPlugin` to both server and client webpack configs, configures `RSC_BUNDLE_ONLY` handling in `ServerClientOrBoth.js`, and sets up the RSC bundle watcher process. See [React Server Components](./react-server-components/tutorial.md) for more information.
|
|
@@ -86,7 +105,7 @@ Ensure your **Rails** app is using the **react_on_rails** gem, version 16.0.0 or
|
|
|
86
105
|
Add the `react_on_rails_pro` gem to your **Gemfile**:
|
|
87
106
|
|
|
88
107
|
```ruby
|
|
89
|
-
gem "react_on_rails_pro", "
|
|
108
|
+
gem "react_on_rails_pro", "= <gem_version>"
|
|
90
109
|
```
|
|
91
110
|
|
|
92
111
|
Then run:
|
|
@@ -138,19 +157,19 @@ All React on Rails Pro users need to install the `react-on-rails-pro` npm packag
|
|
|
138
157
|
### Using npm:
|
|
139
158
|
|
|
140
159
|
```bash
|
|
141
|
-
npm install react-on-rails-pro
|
|
160
|
+
npm install react-on-rails-pro@<npm_version> --save-exact
|
|
142
161
|
```
|
|
143
162
|
|
|
144
163
|
### Using yarn:
|
|
145
164
|
|
|
146
165
|
```bash
|
|
147
|
-
yarn add react-on-rails-pro
|
|
166
|
+
yarn add react-on-rails-pro@<npm_version> --exact
|
|
148
167
|
```
|
|
149
168
|
|
|
150
169
|
### Using pnpm:
|
|
151
170
|
|
|
152
171
|
```bash
|
|
153
|
-
pnpm add react-on-rails-pro
|
|
172
|
+
pnpm add react-on-rails-pro@<npm_version> --save-exact
|
|
154
173
|
```
|
|
155
174
|
|
|
156
175
|
## Usage
|
|
@@ -187,13 +206,13 @@ See the [React Server Components tutorial](./react-server-components/tutorial.md
|
|
|
187
206
|
### Using npm:
|
|
188
207
|
|
|
189
208
|
```bash
|
|
190
|
-
npm install react-on-rails-pro-node-renderer
|
|
209
|
+
npm install react-on-rails-pro-node-renderer@<npm_version> --save-exact
|
|
191
210
|
```
|
|
192
211
|
|
|
193
212
|
### Using yarn:
|
|
194
213
|
|
|
195
214
|
```bash
|
|
196
|
-
yarn add react-on-rails-pro-node-renderer
|
|
215
|
+
yarn add react-on-rails-pro-node-renderer@<npm_version> --exact
|
|
197
216
|
```
|
|
198
217
|
|
|
199
218
|
### Add to package.json:
|
|
@@ -201,7 +220,7 @@ yarn add react-on-rails-pro-node-renderer
|
|
|
201
220
|
```json
|
|
202
221
|
{
|
|
203
222
|
"dependencies": {
|
|
204
|
-
"react-on-rails-pro-node-renderer": "
|
|
223
|
+
"react-on-rails-pro-node-renderer": "<npm_version>"
|
|
205
224
|
}
|
|
206
225
|
}
|
|
207
226
|
```
|
|
@@ -9,6 +9,16 @@ A React architecture that allows components to execute exclusively on the server
|
|
|
9
9
|
- Improved initial page load
|
|
10
10
|
- Better SEO
|
|
11
11
|
|
|
12
|
+
<!-- H2 is intentional here: this callout must stand out above the H3 glossary entries to prevent confusion -->
|
|
13
|
+
## Important: `.client.` / `.server.` File Suffixes Are Unrelated
|
|
14
|
+
|
|
15
|
+
React on Rails has a separate, older concept where files can have `.client.jsx` or `.server.jsx` suffixes. These control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) and have nothing to do with React Server Components.
|
|
16
|
+
|
|
17
|
+
- `Component.client.jsx` → only imported in the client (browser) bundle
|
|
18
|
+
- `Component.server.jsx` → only imported in the server and the RSC bundle
|
|
19
|
+
|
|
20
|
+
A `.server.jsx` file is NOT a React Server Component. A `.client.jsx` file is NOT necessarily a React Client Component. The RSC classification is determined solely by the `'use client'` directive, regardless of file suffix. These suffixes only make sense for client components, as server components exist only in the RSC bundle. See the [auto-bundling docs](../../../docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md#server-rendering-and-client-rendering-components) for details on file suffixes.
|
|
21
|
+
|
|
12
22
|
## Types of Components
|
|
13
23
|
|
|
14
24
|
### Server Components
|
|
@@ -155,6 +155,37 @@ For example, with our `MyStreamingComponent`, the sequence might be:
|
|
|
155
155
|
</script>
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
+
## Compression Middleware Compatibility
|
|
159
|
+
|
|
160
|
+
Streaming responses use `ActionController::Live`, which writes chunks to a `SizedQueue` (a destructive, non-idempotent data structure). Standard Rack compression middleware (`Rack::Deflater`, `Rack::Brotli`) works correctly with streaming **by default** — each chunk is compressed and flushed immediately, preserving low TTFB.
|
|
161
|
+
|
|
162
|
+
However, if you pass an `:if` condition that calls `body.each` to check the response size, **streaming responses will deadlock**. The `:if` callback destructively consumes all chunks from the queue, leaving nothing for the compressor to read.
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
# BAD — causes deadlocks with streaming responses
|
|
166
|
+
config.middleware.use Rack::Deflater, if: lambda { |*, body|
|
|
167
|
+
sum = 0
|
|
168
|
+
body.each { |i| sum += i.length } # destructive — drains the queue
|
|
169
|
+
sum > 512
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The [Rack SPEC](https://github.com/rack/rack/blob/main/SPEC.rdoc) states that `each` must only be called once and middleware must not call `each` directly unless the body responds to `to_ary`. Streaming bodies explicitly do not support `to_ary`.
|
|
174
|
+
|
|
175
|
+
**Correct pattern** — check `to_ary` before iterating:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
config.middleware.use Rack::Deflater, if: lambda { |*, body|
|
|
179
|
+
# Streaming bodies don't support to_ary — always compress them.
|
|
180
|
+
# Rack::Deflater handles streaming correctly with sync flush per chunk.
|
|
181
|
+
return true unless body.respond_to?(:to_ary)
|
|
182
|
+
|
|
183
|
+
body.to_ary.sum(&:bytesize) > 512
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The same applies to `Rack::Brotli` or any middleware that accepts an `:if` callback.
|
|
188
|
+
|
|
158
189
|
## When to Use Streaming
|
|
159
190
|
|
|
160
191
|
Streaming SSR is particularly valuable in specific scenarios. Here's when to consider it:
|
data/docs/troubleshooting.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
# Troubleshooting
|
|
2
2
|
|
|
3
3
|
For issues related to upgrading from GitHub Packages to public distribution, see the [Upgrading Guide](./updating.md).
|
|
4
|
+
|
|
5
|
+
## Streaming SSR request hangs indefinitely
|
|
6
|
+
|
|
7
|
+
**Symptom**: Requests to streaming pages (or RSC payload endpoints) hang forever and never complete.
|
|
8
|
+
|
|
9
|
+
**Cause**: A compression middleware (`Rack::Deflater`, `Rack::Brotli`) is configured with an `:if` condition that calls `body.each` to check the response size. This destructively consumes streaming chunks from the `SizedQueue`, causing a deadlock.
|
|
10
|
+
|
|
11
|
+
**Fix**: See the "Compression Middleware Compatibility" section in the [Streaming Server Rendering guide](./streaming-server-rendering.md).
|
data/docs/updating.md
CHANGED
|
@@ -198,6 +198,16 @@ export REACT_ON_RAILS_PRO_LICENSE="your-license-token-here"
|
|
|
198
198
|
|
|
199
199
|
For complete licensing details, see [LICENSE_SETUP.md](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/LICENSE_SETUP.md).
|
|
200
200
|
|
|
201
|
+
### Additional Upgrade Notes
|
|
202
|
+
|
|
203
|
+
#### Upgrading to 16.4.0 or later
|
|
204
|
+
|
|
205
|
+
##### RSC payload template overrides
|
|
206
|
+
|
|
207
|
+
React on Rails Pro now renders the built-in RSC payload template with `formats: [:text]` so Rails view annotations cannot inject HTML comments into NDJSON responses.
|
|
208
|
+
|
|
209
|
+
If your app overrides `custom_rsc_payload_template`, make sure that override resolves to a text or format-neutral template path, such as `app/views/.../rsc_payload.text.erb`. Overrides that only exist as `.html.erb` templates will raise `ActionView::MissingTemplate` when the RSC payload endpoint renders.
|
|
210
|
+
|
|
201
211
|
### Verify Migration
|
|
202
212
|
|
|
203
213
|
#### 1. Verify Gem Installation
|
|
@@ -15,7 +15,20 @@ module ReactOnRailsPro
|
|
|
15
15
|
|
|
16
16
|
stream_view_containing_react_components(
|
|
17
17
|
template: custom_rsc_payload_template,
|
|
18
|
-
layout: false
|
|
18
|
+
layout: false,
|
|
19
|
+
# Render as text so Rails does not inject HTML view annotation comments
|
|
20
|
+
# into the NDJSON stream. Custom template overrides must resolve to a
|
|
21
|
+
# text or format-neutral template, not `.html.erb`.
|
|
22
|
+
formats: [:text],
|
|
23
|
+
content_type: "application/x-ndjson"
|
|
24
|
+
)
|
|
25
|
+
rescue ActionView::MissingTemplate => e
|
|
26
|
+
raise e.exception(
|
|
27
|
+
"[React on Rails Pro] RSC payload templates are now rendered with format :text. " \
|
|
28
|
+
"If you override `custom_rsc_payload_template`, make sure the override resolves to " \
|
|
29
|
+
"a text or format-neutral template (for example `rsc_payload.text.erb`) instead of " \
|
|
30
|
+
"only `.html.erb`. See react_on_rails_pro/docs/updating.md for upgrade notes.\n\n" \
|
|
31
|
+
"Original error: #{e.message}"
|
|
19
32
|
)
|
|
20
33
|
end
|
|
21
34
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "English"
|
|
4
|
+
|
|
3
5
|
module ReactOnRailsPro
|
|
4
6
|
module Stream
|
|
5
7
|
extend ActiveSupport::Concern
|
|
@@ -12,6 +14,10 @@ module ReactOnRailsPro
|
|
|
12
14
|
#
|
|
13
15
|
# @param template [String] The path to the template file to be streamed.
|
|
14
16
|
# @param close_stream_at_end [Boolean] Whether to automatically close the stream after rendering (default: true).
|
|
17
|
+
# @param content_type [String, nil] Optional response content type. Set after rendering but before the first
|
|
18
|
+
# stream write, overriding any content type inferred from the template format. When using
|
|
19
|
+
# a non-HTML `formats:` value (for example `[:text]`), pass `content_type` too unless
|
|
20
|
+
# committing the format-derived MIME type is intentional.
|
|
15
21
|
# @param render_options [Hash] Additional options to pass to `render_to_string`.
|
|
16
22
|
#
|
|
17
23
|
# components must be added to the view using the `stream_react_component` helper.
|
|
@@ -30,10 +36,13 @@ module ReactOnRailsPro
|
|
|
30
36
|
# For more details, refer to `lib/react_on_rails/helper.rb` in the react_on_rails repository.
|
|
31
37
|
#
|
|
32
38
|
# @see ReactOnRails::Helper#stream_react_component
|
|
33
|
-
def stream_view_containing_react_components(
|
|
39
|
+
def stream_view_containing_react_components(
|
|
40
|
+
template:, close_stream_at_end: true, content_type: nil, **render_options
|
|
41
|
+
)
|
|
34
42
|
require "async"
|
|
35
43
|
require "async/barrier"
|
|
36
44
|
require "async/limited_queue"
|
|
45
|
+
warn_on_non_html_formats_without_content_type(render_options[:formats], content_type)
|
|
37
46
|
|
|
38
47
|
Sync do |parent_task|
|
|
39
48
|
# Initialize async primitives for concurrent component streaming
|
|
@@ -48,6 +57,11 @@ module ReactOnRailsPro
|
|
|
48
57
|
# View may contain extra newlines, chunk already contains a newline
|
|
49
58
|
# Having multiple newlines between chunks causes hydration errors
|
|
50
59
|
# So we strip extra newlines from the template string and add a single newline
|
|
60
|
+
# `formats: [:text]` causes render_to_string to set response.content_type
|
|
61
|
+
# to `text/plain`; override it here before the first stream write, which
|
|
62
|
+
# is when ActionController::Live commits headers. render_to_string itself
|
|
63
|
+
# never writes to response.stream, so this assignment is always safe.
|
|
64
|
+
response.content_type = content_type if content_type
|
|
51
65
|
response.stream.write(template_string)
|
|
52
66
|
|
|
53
67
|
drain_streams_concurrently(parent_task)
|
|
@@ -80,8 +94,6 @@ module ReactOnRailsPro
|
|
|
80
94
|
# - Barrier is stopped to cancel all producer tasks, preventing wasted work
|
|
81
95
|
# - No exception propagates to the controller for client disconnects
|
|
82
96
|
def drain_streams_concurrently(parent_task)
|
|
83
|
-
client_disconnected = false
|
|
84
|
-
|
|
85
97
|
writing_task = parent_task.async do
|
|
86
98
|
# Drain all remaining chunks from the queue to the response stream
|
|
87
99
|
while (chunk = @main_output_queue.dequeue)
|
|
@@ -89,8 +101,13 @@ module ReactOnRailsPro
|
|
|
89
101
|
end
|
|
90
102
|
rescue IOError, Errno::EPIPE => e
|
|
91
103
|
# Client disconnected - stop writing gracefully
|
|
92
|
-
client_disconnected = true
|
|
93
104
|
log_client_disconnect("writer", e)
|
|
105
|
+
ensure
|
|
106
|
+
# Cancel all producers when writer exits for ANY reason (normal completion,
|
|
107
|
+
# client disconnect, or unexpected error). Prevents deadlock where producers
|
|
108
|
+
# block on enqueue to a full queue that nobody is consuming.
|
|
109
|
+
# Idempotent — no-op if barrier tasks already completed.
|
|
110
|
+
@async_barrier.stop
|
|
94
111
|
end
|
|
95
112
|
|
|
96
113
|
# Wait for all component streaming tasks to complete
|
|
@@ -101,16 +118,22 @@ module ReactOnRailsPro
|
|
|
101
118
|
raise e
|
|
102
119
|
end
|
|
103
120
|
ensure
|
|
104
|
-
#
|
|
105
|
-
|
|
121
|
+
# Capture the primary exception (if any) BEFORE any cleanup that could raise.
|
|
122
|
+
# In an ensure block, $ERROR_INFO holds the exception currently propagating
|
|
123
|
+
# out of the method (nil if returning normally). We must snapshot it before
|
|
124
|
+
# the begin/rescue below, where $ERROR_INFO would reflect the caught exception.
|
|
125
|
+
primary_exception = $ERROR_INFO
|
|
106
126
|
|
|
107
|
-
#
|
|
108
|
-
|
|
109
|
-
# writing_task's rescue block sets the flag)
|
|
110
|
-
writing_task.wait
|
|
127
|
+
# Close the queue to unblock writing_task (it may be waiting on dequeue)
|
|
128
|
+
@main_output_queue.close
|
|
111
129
|
|
|
112
|
-
#
|
|
113
|
-
|
|
130
|
+
# Wait for writing_task to finish. Wrap in rescue to avoid masking a primary
|
|
131
|
+
# exception (e.g., producer error) with a secondary writing_task exception.
|
|
132
|
+
begin
|
|
133
|
+
writing_task.wait
|
|
134
|
+
rescue StandardError
|
|
135
|
+
raise unless primary_exception
|
|
136
|
+
end
|
|
114
137
|
end
|
|
115
138
|
|
|
116
139
|
def log_client_disconnect(context, exception)
|
|
@@ -120,5 +143,19 @@ module ReactOnRailsPro
|
|
|
120
143
|
"[React on Rails Pro] Client disconnected during streaming (#{context}): #{exception.class}"
|
|
121
144
|
end
|
|
122
145
|
end
|
|
146
|
+
|
|
147
|
+
def warn_on_non_html_formats_without_content_type(formats, content_type)
|
|
148
|
+
return if content_type.present?
|
|
149
|
+
|
|
150
|
+
requested_formats = Array(formats).compact.map(&:to_sym)
|
|
151
|
+
return if requested_formats.empty? || requested_formats.all?(:html)
|
|
152
|
+
|
|
153
|
+
Rails.logger.warn(
|
|
154
|
+
"[React on Rails Pro] stream_view_containing_react_components received non-HTML formats " \
|
|
155
|
+
"#{requested_formats.inspect} without `content_type:`. Rails will commit the format-derived " \
|
|
156
|
+
"MIME type (for example `text/plain` for `:text`). Pass `content_type:` explicitly when " \
|
|
157
|
+
"streaming non-HTML responses."
|
|
158
|
+
)
|
|
159
|
+
end
|
|
123
160
|
end
|
|
124
161
|
end
|
|
@@ -7,8 +7,10 @@ module ReactOnRailsPro
|
|
|
7
7
|
LICENSE_URL = "https://www.shakacode.com/react-on-rails-pro/"
|
|
8
8
|
# TODO: Remove this legacy migration warning path after 16.5.0 stable release (target: 2026-05-31).
|
|
9
9
|
LEGACY_LICENSE_FILE = "config/react_on_rails_pro_license.key"
|
|
10
|
+
RSC_STREAMING_MIDDLEWARE_WARNING_TARGETS = ["Rack::Deflater"].freeze
|
|
10
11
|
private_constant :LICENSE_URL
|
|
11
12
|
private_constant :LEGACY_LICENSE_FILE
|
|
13
|
+
private_constant :RSC_STREAMING_MIDDLEWARE_WARNING_TARGETS
|
|
12
14
|
|
|
13
15
|
initializer "react_on_rails_pro.routes" do
|
|
14
16
|
ActionDispatch::Routing::Mapper.include ReactOnRailsPro::Routes
|
|
@@ -20,6 +22,10 @@ module ReactOnRailsPro
|
|
|
20
22
|
config.after_initialize { ReactOnRailsPro::Engine.log_license_status }
|
|
21
23
|
end
|
|
22
24
|
|
|
25
|
+
initializer "react_on_rails_pro.check_rsc_streaming_middleware" do
|
|
26
|
+
config.after_initialize { ReactOnRailsPro::Engine.log_rsc_streaming_middleware_warning }
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
class << self
|
|
24
30
|
def log_license_status
|
|
25
31
|
status = ReactOnRailsPro::LicenseValidator.license_status
|
|
@@ -40,6 +46,24 @@ module ReactOnRailsPro
|
|
|
40
46
|
end
|
|
41
47
|
end
|
|
42
48
|
|
|
49
|
+
def log_rsc_streaming_middleware_warning
|
|
50
|
+
return unless ReactOnRailsPro.configuration.enable_rsc_support
|
|
51
|
+
return if Rails.env.test?
|
|
52
|
+
|
|
53
|
+
middleware_names = middleware_stack_names
|
|
54
|
+
problematic = RSC_STREAMING_MIDDLEWARE_WARNING_TARGETS & middleware_names
|
|
55
|
+
return if problematic.empty?
|
|
56
|
+
|
|
57
|
+
route_path = ReactOnRailsPro.configuration.rsc_payload_generation_url_path
|
|
58
|
+
Rails.logger.warn(
|
|
59
|
+
"[React on Rails Pro] React Server Components support is enabled and the middleware " \
|
|
60
|
+
"stack includes #{problematic.join(', ')}. Compression and other response-transforming " \
|
|
61
|
+
"middleware can interfere with ActionController::Live NDJSON streaming. If your " \
|
|
62
|
+
"`#{route_path}` payload route is not already exempt, consider bypassing " \
|
|
63
|
+
"#{problematic.join(', ')} for that endpoint if you see stalled or corrupted RSC payloads."
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
|
|
43
67
|
private
|
|
44
68
|
|
|
45
69
|
def log_valid_license
|
|
@@ -105,6 +129,40 @@ module ReactOnRailsPro
|
|
|
105
129
|
Rails.logger.info message
|
|
106
130
|
end
|
|
107
131
|
end
|
|
132
|
+
|
|
133
|
+
def middleware_stack_names
|
|
134
|
+
middleware_stack = Rails.application&.middleware
|
|
135
|
+
return [] unless middleware_stack
|
|
136
|
+
|
|
137
|
+
entries =
|
|
138
|
+
if middleware_stack.respond_to?(:middlewares)
|
|
139
|
+
middleware_stack.middlewares
|
|
140
|
+
elsif middleware_stack.respond_to?(:to_a)
|
|
141
|
+
middleware_stack.to_a
|
|
142
|
+
else
|
|
143
|
+
Array(middleware_stack)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
entries.filter_map { |entry| middleware_entry_name(entry) }.uniq
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def middleware_entry_name(entry)
|
|
150
|
+
candidate =
|
|
151
|
+
if entry.respond_to?(:klass) && entry.klass
|
|
152
|
+
entry.klass
|
|
153
|
+
elsif entry.is_a?(Array)
|
|
154
|
+
entry.first
|
|
155
|
+
else
|
|
156
|
+
entry
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
case candidate
|
|
160
|
+
when Module
|
|
161
|
+
candidate.name
|
|
162
|
+
else
|
|
163
|
+
candidate.to_s.presence
|
|
164
|
+
end
|
|
165
|
+
end
|
|
108
166
|
end
|
|
109
167
|
end
|
|
110
168
|
end
|
|
@@ -319,6 +319,16 @@ module ReactOnRailsPro
|
|
|
319
319
|
end
|
|
320
320
|
|
|
321
321
|
response = HTTPX.get(path)
|
|
322
|
+
error = response.error
|
|
323
|
+
if error
|
|
324
|
+
# Re-raise via rescue so Ruby sets error.cause for exception chaining.
|
|
325
|
+
begin
|
|
326
|
+
raise error
|
|
327
|
+
rescue StandardError
|
|
328
|
+
raise ReactOnRailsPro::Error, "Failed to fetch dev-server asset from #{path}: #{error}"
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
322
332
|
response.body
|
|
323
333
|
else
|
|
324
334
|
Pathname.new(path)
|
|
@@ -113,7 +113,7 @@ module ReactOnRailsPro
|
|
|
113
113
|
|
|
114
114
|
def process_response_chunks(stream_response, error_body)
|
|
115
115
|
loop_response_lines(stream_response) do |chunk|
|
|
116
|
-
if
|
|
116
|
+
if response_has_error_status?(stream_response)
|
|
117
117
|
error_body << chunk
|
|
118
118
|
next
|
|
119
119
|
end
|
|
@@ -123,6 +123,15 @@ module ReactOnRailsPro
|
|
|
123
123
|
end
|
|
124
124
|
end
|
|
125
125
|
|
|
126
|
+
def response_has_error_status?(response)
|
|
127
|
+
return true if response.is_a?(HTTPX::ErrorResponse)
|
|
128
|
+
|
|
129
|
+
response.status >= 400
|
|
130
|
+
rescue NoMethodError
|
|
131
|
+
# HTTPX::StreamResponse can fail to delegate #status for non-streaming errors.
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
|
|
126
135
|
def handle_http_error(error, error_body, send_bundle)
|
|
127
136
|
response = error.response
|
|
128
137
|
case response.status
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: react_on_rails_pro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 16.4.0.rc.
|
|
4
|
+
version: 16.4.0.rc.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Gordon
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -128,14 +128,14 @@ dependencies:
|
|
|
128
128
|
requirements:
|
|
129
129
|
- - '='
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: 16.4.0.rc.
|
|
131
|
+
version: 16.4.0.rc.7
|
|
132
132
|
type: :runtime
|
|
133
133
|
prerelease: false
|
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
|
136
136
|
- - '='
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
|
-
version: 16.4.0.rc.
|
|
138
|
+
version: 16.4.0.rc.7
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
140
|
name: bundler
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -223,15 +223,12 @@ files:
|
|
|
223
223
|
- Rakefile
|
|
224
224
|
- app/controllers/react_on_rails_pro/rsc_payload_controller.rb
|
|
225
225
|
- app/helpers/react_on_rails_pro_helper.rb
|
|
226
|
-
- app/views/react_on_rails_pro/rsc_payload.
|
|
226
|
+
- app/views/react_on_rails_pro/rsc_payload.text.erb
|
|
227
227
|
- babel.config.js
|
|
228
228
|
- docs/bundle-caching.md
|
|
229
229
|
- docs/caching.md
|
|
230
230
|
- docs/code-splitting-loadable-components.md
|
|
231
231
|
- docs/configuration.md
|
|
232
|
-
- docs/contributors-info/onboarding-customers.md
|
|
233
|
-
- docs/contributors-info/releasing.md
|
|
234
|
-
- docs/contributors-info/style.md
|
|
235
232
|
- docs/home-pro.md
|
|
236
233
|
- docs/installation.md
|
|
237
234
|
- docs/js-memory-leaks.md
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Releasing React on Rails Pro
|
|
2
|
-
|
|
3
|
-
⚠️ **This documentation is outdated.**
|
|
4
|
-
|
|
5
|
-
React on Rails Pro is now released together with React on Rails using a unified release script.
|
|
6
|
-
|
|
7
|
-
## Current Release Process
|
|
8
|
-
|
|
9
|
-
Please refer to the main release documentation:
|
|
10
|
-
|
|
11
|
-
👉 **[/docs/contributor-info/releasing.md](../../../docs/contributor-info/releasing.md)**
|
|
12
|
-
|
|
13
|
-
Or run from the repository root:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
cd .. && rake -D release
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Quick Reference
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
# From repository root (not from react_on_rails_pro/)
|
|
23
|
-
cd /path/to/react_on_rails
|
|
24
|
-
|
|
25
|
-
# Release with version bump
|
|
26
|
-
rake release[17.0.0]
|
|
27
|
-
|
|
28
|
-
# Dry run first (recommended)
|
|
29
|
-
rake release[17.0.0,true]
|
|
30
|
-
|
|
31
|
-
# Test with local Verdaccio
|
|
32
|
-
rake release[17.0.0,false,verdaccio]
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
This unified script releases all 5 packages together:
|
|
36
|
-
|
|
37
|
-
- react-on-rails (NPM)
|
|
38
|
-
- react-on-rails-pro (NPM)
|
|
39
|
-
- react-on-rails-pro-node-renderer (NPM)
|
|
40
|
-
- react_on_rails (RubyGem)
|
|
41
|
-
- react_on_rails_pro (RubyGem)
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Code Style
|
|
2
|
-
|
|
3
|
-
This document describes the coding style of [ShakaCode](http://www.shakacode.com). Yes, it's opinionated, as all style guidelines should be. We shall put as little as possible into this guide and instead rely on:
|
|
4
|
-
|
|
5
|
-
- Use of linters with our standard linter configuration.
|
|
6
|
-
- References to existing style guidelines that support the linter configuration.
|
|
7
|
-
- Anything additional goes next.
|
|
8
|
-
|
|
9
|
-
## Client Side JavaScript and React
|
|
10
|
-
|
|
11
|
-
- See the [Shakacode JavaScript Style Guide](https://github.com/shakacode/style-guide-javascript)
|
|
12
|
-
|
|
13
|
-
## Style Guides to Follow
|
|
14
|
-
|
|
15
|
-
Follow these style guidelines per the linter configuration. Basically, lint your code and if you have questions about the suggested fixes, look here:
|
|
16
|
-
|
|
17
|
-
### Ruby Coding Standards
|
|
18
|
-
|
|
19
|
-
- [ShakaCode Ruby Coding Standards](https://github.com/shakacode/style-guide-ruby)
|
|
20
|
-
- [Ruby Documentation](http://guides.rubyonrails.org/api_documentation_guidelines.html)
|
|
21
|
-
|
|
22
|
-
### JavaScript Coding Standards
|
|
23
|
-
|
|
24
|
-
- [ShakaCode Javascript](https://github.com/shakacode/style-guide-javascript)
|
|
25
|
-
- Use the [eslint-config-shakacode](https://github.com/shakacode/style-guide-javascript/tree/master/packages/eslint-config-shakacode) npm package with eslint.
|
|
26
|
-
- [JSDoc](http://usejsdoc.org/)
|
|
27
|
-
|
|
28
|
-
### Git coding Standards
|
|
29
|
-
|
|
30
|
-
- [Git Coding Standards](http://chlg.co/1GV2m9p)
|
|
31
|
-
|
|
32
|
-
### Sass Coding Standards
|
|
33
|
-
|
|
34
|
-
- [Sass Guidelines](http://sass-guidelin.es/) by [Hugo Giraudel](http://hugogiraudel.com/)
|
|
35
|
-
- [GitHub Front End Guidelines](http://primercss.io/guidelines/)
|
|
36
|
-
|
|
37
|
-
# Git Usage
|
|
38
|
-
|
|
39
|
-
- Follow a github-flow model where you branch off of master for features.
|
|
40
|
-
- Before merging a branch to master, rebase it on top of master, by using command like `git fetch; git checkout my-branch; git rebase -i origin/master`. Clean up your commit message at this point. Be super careful to communicate with anybody else working on this branch and do not do this when others have uncommitted changes. Ideally, your merge of your feature back to master should be one nice commit.
|
|
41
|
-
- Run hosted CI and code coverage.
|
|
File without changes
|