react_on_rails_pro 16.4.0.rc.5 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b71e54f44331a34669c58c5f6997825fe0469a96de8520d24029605134068f2
4
- data.tar.gz: ec4dd8f6d56ab2097f99dcd1c51c54002c2385595890c43fc959cb8ca2cc11ab
3
+ metadata.gz: d8d5365a9653da4cdc8ea771167d5b26dd03602c4977d7fea747ec2a07cc6900
4
+ data.tar.gz: 57afd9dc58238f94d2d008cc01900596a18cb63894786cb60ce99471902500c9
5
5
  SHA512:
6
- metadata.gz: 3ab4f06e700c5710649c0edf4be00398eaeddad34704325cc426c14813b5db3c2a67f2af44832d6e7830b3c4982ad4994774ca0bc24d52afb575c2c7abfd2b25
7
- data.tar.gz: a2c840298e0efda608cefedc7211ff8561788aa55eabe4efc9eaf461bf85a48971eaf8247bffee247c232b1caa2689d1348e89284d95043ba039e6cbc977a016
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 [`../docs/contributor-info/ci-optimization.md`](../docs/contributor-info/ci-optimization.md) in the repository root.
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](../docs/contributor-info/releasing.md)
398
+ - [Root Release Documentation](../internal/contributor-info/releasing.md)
399
399
  - Run `rake -D release` for inline help
@@ -8,7 +8,7 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
8
8
 
9
9
  gem "react_on_rails", path: "../"
10
10
 
11
- gem "shakapacker", "9.5.0"
11
+ gem "shakapacker", "9.6.1"
12
12
  gem "bootsnap", require: false
13
13
  gem "rails", "~> 7.1"
14
14
  gem "puma", "~> 6"
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.5)
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.5)
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.5)
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.1)
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.16.0)
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.1)
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.0-arm64-darwin)
252
+ nokogiri (1.19.1-arm64-darwin)
251
253
  racc (~> 1.4)
252
- nokogiri (1.19.0-x86_64-darwin)
254
+ nokogiri (1.19.1-x86_64-darwin)
253
255
  racc (~> 1.4)
254
- nokogiri (1.19.0-x86_64-linux-gnu)
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.6.0)
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.4)
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.6.2)
314
- loofah (~> 2.21)
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.1.0)
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.0)
419
+ semantic_range (3.1.1)
418
420
  sexp_processor (4.17.1)
419
- shakapacker (9.5.0)
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.4)
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.5.0)
536
+ shakapacker (= 9.6.1)
535
537
  spring
536
538
  spring-watcher-listen
537
539
  sprockets
data/README.md CHANGED
@@ -191,11 +191,12 @@ High-performance standalone Node.js server for server-side rendering with connec
191
191
  **Example Configuration:**
192
192
 
193
193
  ```javascript
194
- // react-on-rails-pro/react-on-rails-pro-node-renderer.js
195
- const { reactOnRailsProNodeRenderer } = require('@shakacode-tools/react-on-rails-pro-node-renderer');
194
+ // node-renderer.js
195
+ const path = require('path');
196
+ const { reactOnRailsProNodeRenderer } = require('react-on-rails-pro-node-renderer');
196
197
 
197
198
  reactOnRailsProNodeRenderer({
198
- bundlePath: path.resolve(__dirname, '../app/assets/webpack'),
199
+ serverBundleCachePath: path.resolve(__dirname, '.node-renderer-bundles'),
199
200
  port: 3800,
200
201
  workersCount: 4,
201
202
  supportModules: true, // Required for loadable-components
@@ -314,7 +314,13 @@ module ReactOnRailsProHelper
314
314
 
315
315
  # Enqueue remaining chunks asynchronously
316
316
  @async_barrier.async do
317
- rest_chunks.each { |chunk| @main_output_queue.enqueue(chunk) }
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,21 +442,51 @@ 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
447
+ rescue StandardError => e
448
+ # Propagate the error to the calling fiber via the variable.
449
+ # Async::Variable can only be resolved once — if it was already resolved
450
+ # (first chunk was returned successfully), the assignment raises and we
451
+ # fall through to re-raise so barrier.wait propagates the error later.
452
+ begin
453
+ first_chunk_var.value = e
454
+ # Variable accepted the error — this is a pre-first-chunk failure (e.g., shell error).
455
+ # The caller will detect the Exception value and raise it synchronously,
456
+ # BEFORE the response is committed, enabling a proper HTTP redirect.
457
+ # Do NOT re-raise here: the caller owns the error now.
458
+ rescue StandardError
459
+ # Variable was already resolved — the first chunk was returned successfully.
460
+ # This is a post-first-chunk error. Re-raise so barrier.wait propagates it
461
+ # (the response is already committed at that point, so only JS redirect is possible).
462
+ raise e
463
+ end
441
464
  end
442
465
 
443
- # Wait for and return the first chunk (blocking)
444
- first_chunk_var.wait
445
- first_chunk_var.value
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
469
+
470
+ # If the async task stored an exception (pre-first-chunk error), raise it now.
471
+ # This happens BEFORE response.stream.write(template_string) in
472
+ # stream_view_containing_react_components, so the response is NOT yet committed
473
+ # and rescue_from can perform a proper HTTP redirect.
474
+ raise result if result.is_a?(StandardError)
475
+
476
+ result
446
477
  end
447
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.
448
481
  def process_stream_chunks(stream, first_chunk_var, all_chunks)
449
482
  is_first = true
450
483
 
451
484
  stream.each_chunk do |chunk|
452
- # Check if client disconnected before processing chunk
453
- break if response.stream.closed?
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
454
490
 
455
491
  all_chunks&.push(chunk)
456
492
 
@@ -466,6 +502,7 @@ module ReactOnRailsProHelper
466
502
 
467
503
  # Handle case where stream has no chunks
468
504
  first_chunk_var.value = nil if is_first
505
+ true
469
506
  end
470
507
 
471
508
  def internal_stream_react_component(component_name, options = {})
@@ -284,9 +284,8 @@ reactOnRailsProNodeRenderer(config);
284
284
  ## Making HMR Work
285
285
 
286
286
  To make HMR work, it's best to disable loadable-components when using the Dev Server.
287
- Note: you will need access to our **private** React on Rails Pro repository to open the following links.
288
287
 
289
- Take a look at the code searches for ['imports-loadable'](https://github.com/shakacode/react_on_rails_pro/search?q=imports-loadable&type=code) and ['imports-hmr'](https://github.com/shakacode/react_on_rails_pro/search?q=imports-hmr&type=code)
288
+ Take a look at the code searches for ['imports-loadable'](https://github.com/shakacode/react_on_rails/search?q=imports-loadable&type=code) and ['imports-hmr'](https://github.com/shakacode/react_on_rails/search?q=imports-hmr&type=code)
290
289
 
291
290
  The general concept is that we have a non-loadable, HMR-ready, file that substitutes for the loadable-enabled one, with the suffixes `imports-hmr.js` instead of `imports-loadable.js`
292
291
 
@@ -294,7 +293,7 @@ The general concept is that we have a non-loadable, HMR-ready, file that substit
294
293
 
295
294
  Use the [NormalModuleReplacement plugin](https://webpack.js.org/plugins/normal-module-replacement-plugin/):
296
295
 
297
- [code](https://github.com/shakacode/react_on_rails_pro/blob/a361f4e163b9170f180ae07ee312fb9b4c719fc3/spec/dummy/config/webpack/environment.js#L81-L91)
296
+ [code](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/config/webpack/commonWebpackConfig.js#L41-L49)
298
297
 
299
298
  ```js
300
299
  if (isWebpackDevServer) {
@@ -313,17 +312,15 @@ And compare:
313
312
 
314
313
  ### Routes file
315
314
 
316
- Note: you will need access to our **private** React on Rails Pro repository to open the following links.
317
-
318
- - [spec/dummy/client/app/components/Loadable/routes/Routes.imports-hmr.jsx](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/components/Loadable/routes/Routes.imports-hmr.jsx)
319
- - [spec/dummy/client/app/components/Loadable/routes/Routes.imports-loadable.jsx](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/components/Loadable/routes/Routes.imports-loadable.jsx)
315
+ - [spec/dummy/client/app/components/Loadable/routes/Routes.imports-hmr.jsx](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/client/app/components/Loadable/routes/Routes.imports-hmr.jsx)
316
+ - [spec/dummy/client/app/components/Loadable/routes/Routes.imports-loadable.jsx](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/client/app/components/Loadable/routes/Routes.imports-loadable.jsx)
320
317
 
321
318
  ### Client-Side Startup
322
319
 
323
- - [spec/dummy/client/app/loadable/loadable-client.imports-hmr.js](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-client.imports-hmr.js)
324
- - [spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx)
320
+ - [spec/dummy/client/app/loadable/loadable-client.imports-hmr.jsx](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/client/app/loadable/loadable-client.imports-hmr.jsx)
321
+ - [spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/client/app/loadable/loadable-client.imports-loadable.jsx)
325
322
 
326
323
  ### Server-Side Startup
327
324
 
328
- - [spec/dummy/client/app/loadable/loadable-server.imports-hmr.jsx](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-server.imports-hmr.jsx)
329
- - [spec/dummy/client/app/loadable/loadable-server.imports-loadable.jsx](https://github.com/shakacode/react_on_rails_pro/blob/master/spec/dummy/client/app/loadable/loadable-server.imports-loadable.jsx)
325
+ - [spec/dummy/client/app/loadable/loadable-server.imports-hmr.jsx](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/client/app/loadable/loadable-server.imports-hmr.jsx)
326
+ - [spec/dummy/client/app/loadable/loadable-server.imports-loadable.jsx](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/spec/dummy/client/app/loadable/loadable-server.imports-loadable.jsx)
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 docs, find the desired `<version>` in the CHANGELOG. Note that for pre-release versions:
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 to your Gemfile first
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
- You still need to configure your license. Set the environment variable:
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", "~> 16.2"
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": "^16.2.0"
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
data/docs/ruby-api.md CHANGED
@@ -1,11 +1,9 @@
1
1
  # Ruby API
2
2
 
3
- Note: you will need access to our **private** React on Rails Pro repository to open the following links.
4
-
5
3
  ## View Helpers
6
4
 
7
- See the [app/helpers/react_on_rails_pro_helper.rb](https://github.com/shakacode/react_on_rails_pro/blob/master/app/helpers/react_on_rails_pro_helper.rb) source.
5
+ See the [app/helpers/react_on_rails_pro_helper.rb](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb) source.
8
6
 
9
7
  ## Utility Methods
10
8
 
11
- See the [lib/react_on_rails_pro/utils.rb](https://github.com/shakacode/react_on_rails_pro/blob/master/lib/react_on_rails_pro/utils.rb) source.
9
+ See the [lib/react_on_rails_pro/utils.rb](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails_pro/lib/react_on_rails_pro/utils.rb) source.
@@ -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:
@@ -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
@@ -6,7 +6,7 @@
6
6
 
7
7
  This guide is for existing React on Rails Pro customers who are:
8
8
 
9
- - Currently using GitHub Packages authentication (private distribution)
9
+ - Previously using GitHub Packages authentication (private distribution)
10
10
  - On version 16.2.0-beta.x or earlier
11
11
  - Upgrading to version 16.2.0 or higher
12
12
 
@@ -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(template:, close_stream_at_end: true, **render_options)
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
@@ -41,20 +50,33 @@ module ReactOnRailsPro
41
50
  buffer_size = ReactOnRailsPro.configuration.concurrent_component_streaming_buffer_size
42
51
  @main_output_queue = Async::LimitedQueue.new(buffer_size)
43
52
 
44
- # Render template - components will start streaming immediately
53
+ # Render template - components will start streaming immediately.
54
+ # If a shell error occurs, consumer_stream_async raises PrerenderError here
55
+ # (BEFORE the response is committed), enabling a proper HTTP redirect.
45
56
  template_string = render_to_string(template: template, **render_options)
46
57
  # View may contain extra newlines, chunk already contains a newline
47
58
  # Having multiple newlines between chunks causes hydration errors
48
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
49
65
  response.stream.write(template_string)
50
66
 
51
- begin
52
- drain_streams_concurrently(parent_task)
53
- # Do not close the response stream in an ensure block.
54
- # If an error occurs we may need the stream open to send diagnostic/error details
55
- # (for example, ApplicationController#rescue_from in the dummy app).
56
- response.stream.close if close_stream_at_end
57
- end
67
+ drain_streams_concurrently(parent_task)
68
+ # Do not close the response stream in an ensure block.
69
+ # If an error occurs we may need the stream open to send diagnostic/error details
70
+ # (for example, ApplicationController#rescue_from in the dummy app).
71
+ response.stream.close if close_stream_at_end
72
+ rescue StandardError
73
+ # Stop all streaming tasks to prevent leaked async work.
74
+ # For pre-commit errors (e.g., shell error raised during render_to_string),
75
+ # the barrier may still have pending tasks that must be cancelled.
76
+ # For post-commit errors (from drain_streams_concurrently), the barrier
77
+ # is already stopped inside that method — stopping again is a no-op.
78
+ @async_barrier&.stop
79
+ raise
58
80
  end
59
81
  end
60
82
 
@@ -72,8 +94,6 @@ module ReactOnRailsPro
72
94
  # - Barrier is stopped to cancel all producer tasks, preventing wasted work
73
95
  # - No exception propagates to the controller for client disconnects
74
96
  def drain_streams_concurrently(parent_task)
75
- client_disconnected = false
76
-
77
97
  writing_task = parent_task.async do
78
98
  # Drain all remaining chunks from the queue to the response stream
79
99
  while (chunk = @main_output_queue.dequeue)
@@ -81,8 +101,13 @@ module ReactOnRailsPro
81
101
  end
82
102
  rescue IOError, Errno::EPIPE => e
83
103
  # Client disconnected - stop writing gracefully
84
- client_disconnected = true
85
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
86
111
  end
87
112
 
88
113
  # Wait for all component streaming tasks to complete
@@ -93,16 +118,22 @@ module ReactOnRailsPro
93
118
  raise e
94
119
  end
95
120
  ensure
96
- # Close the queue first to unblock writing_task (it may be waiting on dequeue)
97
- @main_output_queue.close
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
98
126
 
99
- # Wait for writing_task to ensure client_disconnected flag is set
100
- # before we check it (fixes race condition where ensure runs before
101
- # writing_task's rescue block sets the flag)
102
- writing_task.wait
127
+ # Close the queue to unblock writing_task (it may be waiting on dequeue)
128
+ @main_output_queue.close
103
129
 
104
- # If client disconnected, stop all producer tasks to avoid wasted work
105
- @async_barrier.stop if client_disconnected
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
106
137
  end
107
138
 
108
139
  def log_client_disconnect(context, exception)
@@ -112,5 +143,19 @@ module ReactOnRailsPro
112
143
  "[React on Rails Pro] Client disconnected during streaming (#{context}): #{exception.class}"
113
144
  end
114
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
115
160
  end
116
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 stream_response.is_a?(HTTPX::ErrorResponse) || stream_response.status >= 400
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRailsPro
4
- VERSION = "16.4.0.rc.5"
4
+ VERSION = "16.4.0.rc.7"
5
5
  PROTOCOL_VERSION = "2.0.0"
6
6
  end
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.5
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-02-26 00:00:00.000000000 Z
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.5
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.5
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.html.erb
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,7 +0,0 @@
1
- # Creating a github OAuth Token
2
-
3
- _[Document for ShakaCode Staff](https://docs.google.com/document/d/10snzXEWgkorcai76_OxlhjQcDae_WoxRfBCdVbmcQoU/edit)_
4
-
5
- # Customer Steps
6
-
7
- See [Installation](../installation.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.