humid 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +73 -78
  3. data/lib/humid/version.rb +1 -1
  4. data/lib/humid.rb +13 -3
  5. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b62f6d6c3c7ffac0ba1c609965742a6a09dafebe0ebb9fc05cbae3c9200299e
4
- data.tar.gz: 56557384d6768ada9b8fa9e9403720b5e75f03a579e39483892afcb631cb04a4
3
+ metadata.gz: 4c7f343b4b1518296d59917fb37ce2f8a60ee6b1a57b71f3fd378ce2ad55a4d4
4
+ data.tar.gz: e11384d2812e0de2cb7e676fa237957d44fbe63cf788e73adf997c9a14b2015e
5
5
  SHA512:
6
- metadata.gz: 4465a746beab25d302782cc71b8a70cd7fe827dc6ce3058e6720056c121bb86357733a9d31a7c266ceee6a53f938b174fec1eef111dbc634aa6699ffccb30ac9
7
- data.tar.gz: c5d8a1c61b84b49a14a78c7d198af09871bbdf9cebc8c9bbd1d4b32c2cdd95ac7de2bad06214f80ec12a8507158b8bb95a592eff313e51e454dcd768e5a2cdc1
6
+ metadata.gz: d5ca07bdd2c64b97f51c45dd14de734ab37e608704414a494461cce0645a10d4fcfb3c1e414152066c16b9be3f98c2f55fdcb6cd1cb6e3e7464e3ebb64e7ed8f
7
+ data.tar.gz: 52923317087b7439e80c347022acc55e102435367f3f0d54d52079f9e40129271aae60cba245bfe4d5d4352441988abd30882429f04d817e2528c029564a8cc3
data/README.md CHANGED
@@ -43,25 +43,25 @@ Add an initializer to configure the default options for `Humid.render`. These
43
43
  are overridable on `Humid.render`.
44
44
 
45
45
  ```ruby
46
- # app/initializers/humid.rb
46
+ # config/initializers/humid.rb
47
47
 
48
48
  Humid.configure do |config|
49
49
  # Path to your build file located in `app/assets/builds/`. You should use a
50
50
  # separate build apart from your `application.js`.
51
51
  #
52
52
  # Required
53
- config.application_path = Rails.root.join('app', 'assets', 'builds', 'server_rendering.js')
53
+ config.application_path = Rails.root.join("app/assets/builds/server_rendering.js")
54
54
 
55
55
  # Path to your source map file
56
56
  #
57
57
  # Optional
58
- config.source_map_path = Rails.root.join('app', 'assets', 'builds', 'server_rendering.js.map')
58
+ config.source_map_path = Rails.root.join("app/assets/builds/server_rendering.js.map")
59
59
 
60
60
  # Raise errors if JS rendering failed. If false, the error will be
61
- # logged out to Rails log and Humid.render will return an empty string
61
+ # logged and Humid.render will return an empty string.
62
62
  #
63
63
  # Defaults to true.
64
- config.raise_render_errors = Rails.env.development? || Rails.env.test?
64
+ config.raise_render_errors = Rails.env.local?
65
65
 
66
66
  # The logger instance.
67
67
  # `console.log` and friends (`warn`, `error`) are delegated to
@@ -71,105 +71,105 @@ Humid.configure do |config|
71
71
  config.logger = Rails.env.local? ? Rails.logger : nil
72
72
  end
73
73
 
74
- # if Rails.env.local?
75
- # # Use single_threaded mode for Spring and other forked envs.
76
- # MiniRacer::Platform.set_flags! :single_threaded
77
- # ctx = MiniRacer::Context.new(timeout: 100, ensure_gc_after_idle: 2000)
78
- # MINI_RACER_CONTEXT = Humid.prepare(ctx)
79
- # end
74
+ if Rails.env.local?
75
+ # Use single_threaded mode for Spring and other forked envs.
76
+ MiniRacer::Platform.set_flags! :single_threaded
77
+ MINI_RACER_SSR = { context: MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000) }
78
+
79
+ # Reload the context when the SSR bundle changes
80
+ ssr_checker = ActiveSupport::FileUpdateChecker.new([Humid.config.application_path.to_s]) do
81
+ MINI_RACER_SSR[:context].dispose
82
+ MINI_RACER_SSR[:context] = MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000)
83
+ end
84
+
85
+ Rails.application.reloaders << ssr_checker
86
+ Rails.application.reloader.to_run do
87
+ ssr_checker.execute_if_updated
88
+ end
89
+ end
80
90
  ```
81
91
 
82
92
  ## Usage
83
93
 
94
+ ### Set a renderer
84
95
 
85
- ### Create the MiniRacer Context.
96
+ In your entry file, e.g, `server_rendering.js` (specified in
97
+ `config.application_path`), pass your HTML render function to
98
+ `setHumidRenderer`. There is no need to require the function, its included in
99
+ the environment.
86
100
 
87
- On local development or test environments, uncomment the below.
101
+ ```javascript
102
+ // Set a factory function that will create a new instance of our app
103
+ // for each request.
104
+ setHumidRenderer((json) => {
105
+ const initialState = JSON.parse(json)
88
106
 
89
- ```ruby
90
- if Rails.env.local?
91
- # Use single_threaded mode for Spring and other forked envs.
92
- MiniRacer::Platform.set_flags! :single_threaded
93
- ctx = MiniRacer::Context.new(timeout: 100, ensure_gc_after_idle: 2000)
94
- MINI_RACER_CONTEXT = Humid.prepare(ctx)
95
- end
107
+ return ReactDOMServer.renderToString(
108
+ <Application initialPage={initialState}/>
109
+ )
110
+ })
96
111
  ```
97
112
 
113
+ If you'd like support for source map support, you will need to add the following
114
+ to the same file and set `config.source_map_path` like the configuration above.
115
+
116
+ ```javascript
117
+ require("source-map-support").install({
118
+ retrieveSourceMap: filename => {
119
+ return {
120
+ url: filename,
121
+ map: readSourceMap(filename)
122
+ };
123
+ }
124
+ });
125
+ ```
126
+
127
+ ### Your webserver
128
+
98
129
  On production, keep in mind that `mini_racer` is **thread safe, but not fork
99
- safe**. When using with web servers that employ forking, create a
100
- `MINI_RACER_CONTEXT` with options of your choosing **on worker boot. There
101
- should be no context created on the master process.**
130
+ safe**. When using with web servers that employ forking, create the context
131
+ on worker boot. **There should be no context created on the master process.**
102
132
 
103
133
  For example with puma:
104
134
 
105
135
  ```ruby
106
136
  # config/puma.rb
107
137
  on_worker_boot do
108
- ctx = MiniRacer::Context.new(timeout: 100, ensure_gc_after_idle: 2000)
109
- MINI_RACER_CONTEXT = Humid.prepare(ctx)
138
+ ctx = MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000)
139
+ MINI_RACER_SSR = { context: Humid.prepare(ctx) }
110
140
  end
111
141
 
112
142
  on_worker_shutdown do
113
- MINI_RACER_CONTEXT.dispose
143
+ MINI_RACER_SSR[:context].dispose
114
144
  end
115
145
  ```
116
146
 
117
- ### Prepare the context with `Humid.prepare`
118
-
119
- `Humid.prepare` will prepare the context's environment by [removing
120
- functions](#functions-not-available), delegate `console.log` and friends to
121
- your logger, load the SSR js bundle, and add the render function.
147
+ `Humid.prepare` will prepare the context's
148
+ [environment](#the-mini_racer-environment).
122
149
 
123
150
  You can also override config options per-context:
124
151
 
125
152
  ```ruby
126
- MINI_RACER_CONTEXT = Humid.prepare(
153
+ ctx = Humid.prepare(
127
154
  MiniRacer::Context.new(timeout: 1000),
128
155
  application_path: Rails.root.join("other_bundle.js"),
129
156
  logger: nil
130
157
  )
158
+ MINI_RACER_SSR = { context: ctx }
131
159
  ```
132
160
 
133
- If you'd like support for source map support, you will need to
134
-
135
- 1. Add the following to your entry file, e.g, `server_rendering.js`.
136
- 2. set `config.source_map_path`.
137
-
138
- ```javascript
139
- require("source-map-support").install({
140
- retrieveSourceMap: filename => {
141
- return {
142
- url: filename,
143
- map: readSourceMap(filename)
144
- };
145
- }
146
- });
147
- ```
161
+ > [!NOTE]
162
+ > If you pass a context that was already prepared, `prepare` will noop and return the context back to you.
148
163
 
149
164
  See the [sample server_rendering.tsx](./sample/server_rendering.tsx) to see how
150
165
  it is integrated.
151
166
 
152
- ### Add a renderer and call `Humid.render`
153
-
154
- In your entry file, e.g, `server_rendering.js`, pass your HTML render function
155
- to `setHumidRenderer`. There is no need to require the function.
156
-
157
- ```javascript
158
- // Set a factory function that will create a new instance of our app
159
- // for each request.
160
- setHumidRenderer((json) => {
161
- const initialState = JSON.parse(json)
162
-
163
- return ReactDOMServer.renderToString(
164
- <Application initialPage={initialState}/>
165
- )
166
- })
167
- ```
167
+ ### Call `Humid.render`
168
168
 
169
169
  And finally call `render` from ERB.
170
170
 
171
171
  ```ruby
172
- <%= Humid.render(MINI_RACER_CONTEXT, json).html_safe %>
172
+ <%= Humid.render(MINI_RACER_SSR[:context], json).html_safe %>
173
173
  ```
174
174
 
175
175
  Instrumentation is included:
@@ -178,7 +178,7 @@ Instrumentation is included:
178
178
  Completed 200 OK in 14ms (Views: 0.2ms | Humid SSR: 11.0ms | ActiveRecord: 2.7ms)
179
179
  ```
180
180
 
181
- ## The prepared `mini_racer` environment.
181
+ ## The `mini_racer` environment
182
182
 
183
183
  ### Functions not available
184
184
 
@@ -268,23 +268,19 @@ to get around these issues.
268
268
 
269
269
  ## Testing
270
270
 
271
- When running in test environments that also forks, you may need to set up new mini_racer
272
- contexts for each parallel worker. For example:
271
+ The snippet When running in test environments that fork (e.g., parallel tests), each
272
+ worker needs its own context since MiniRacer is not fork-safe. Using
273
+ `MINI_RACER_SSR` as a hash makes this straightforward:
273
274
 
274
275
  ```ruby
275
276
  ActiveSupport.on_load(:action_dispatch_integration_test) do
276
- include ActionView::Helpers::TranslationHelper
277
- include Devise::Test::IntegrationHelpers
278
-
279
277
  parallelize_setup do
280
- MINI_RACER_CONTEXT.dispose if defined?(MINI_RACER_CONTEXT)
281
- ctx = MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000)
282
- Object.send(:remove_const, :MINI_RACER_CONTEXT) if defined?(MINI_RACER_CONTEXT)
283
- Object.const_set(:MINI_RACER_CONTEXT, Humid.prepare(ctx))
278
+ MINI_RACER_SSR[:context].dispose
279
+ MINI_RACER_SSR[:context] = MiniRacer::Context.new(timeout: 1000, ensure_gc_after_idle: 2000)
284
280
  end
285
281
 
286
282
  parallelize_teardown do
287
- MINI_RACER_CONTEXT.dispose if defined?(MINI_RACER_CONTEXT)
283
+ MINI_RACER_SSR[:context].dispose
288
284
  end
289
285
  end
290
286
  ```
@@ -295,7 +291,7 @@ The `MiniRacer::Context` gives you access to V8 heap statistics for monitoring
295
291
  memory usage over time.
296
292
 
297
293
  ```ruby
298
- MINI_RACER_CONTEXT.heap_stats
294
+ MINI_RACER_SSR[:context].heap_stats
299
295
  # {:total_heap_size=>3100672,
300
296
  # :total_heap_size_executable=>4194304,
301
297
  # :total_physical_size=>1280640,
@@ -314,7 +310,7 @@ render_histogram = meter.create_histogram("humid.render.duration", unit: "ms", d
314
310
  heap_gauge = meter.create_gauge("humid.heap.used_bytes", unit: "By", description: "V8 heap used bytes")
315
311
 
316
312
  ActiveSupport::Notifications.subscribe("render.humid") do |event|
317
- stats = MINI_RACER_CONTEXT.heap_stats
313
+ stats = MINI_RACER_SSR[:context].heap_stats
318
314
  attributes = { "worker.pid" => Process.pid.to_s }
319
315
 
320
316
  render_histogram.record(event.duration, attributes: attributes)
@@ -350,7 +346,6 @@ We are [available for hire][hire].
350
346
  [community]: https://thoughtbot.com/community?utm_source=github
351
347
  [hire]: https://thoughtbot.com/hire-us?utm_source=github
352
348
 
353
-
354
349
  <!-- END /templates/footer.md -->
355
350
 
356
351
  [mini_racer]: https://github.com/rubyjs/mini_racer
data/lib/humid/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Humid
2
- VERSION = "0.5.0".freeze
2
+ VERSION = "0.7.0".freeze
3
3
  end
data/lib/humid.rb CHANGED
@@ -13,6 +13,9 @@ module Humid
13
13
  class FileNotFound < StandardError
14
14
  end
15
15
 
16
+ class NotPrepared < StandardError
17
+ end
18
+
16
19
  mattr_accessor :config
17
20
 
18
21
  self.config = ActiveSupport::OrderedOptions.new.merge({
@@ -27,6 +30,8 @@ module Humid
27
30
  end
28
31
 
29
32
  def prepare(ctx, options = {})
33
+ return ctx if ctx.respond_to?(:humid_prepared?) && ctx.humid_prepared?
34
+
30
35
  effective_config = config.merge(options)
31
36
  logger = effective_config.logger
32
37
  log_formatter = effective_config.log_formatter
@@ -39,9 +44,7 @@ module Humid
39
44
  ctx.attach("console.warn", proc { |*args| logger.warn(fmt.call(:warn, *args)) })
40
45
  end
41
46
 
42
- js = ""
43
- js << remove_functions
44
- js << renderer
47
+ js = remove_functions + renderer
45
48
  ctx.eval(js)
46
49
 
47
50
  source_path = effective_config.application_path
@@ -54,10 +57,17 @@ module Humid
54
57
  filename = File.basename(source_path.to_s)
55
58
  ctx.eval(File.read(source_path), filename: filename)
56
59
 
60
+ def ctx.humid_prepared?
61
+ true
62
+ end
63
+
57
64
  ctx
58
65
  end
59
66
 
60
67
  def render(ctx, *args)
68
+ is_prepared = ctx.respond_to?(:humid_prepared?) && ctx.humid_prepared?
69
+ raise Humid::NotPrepared, "Context was not prepared with Humid.prepare" unless is_prepared
70
+
61
71
  ActiveSupport::Notifications.instrument("render.humid") do
62
72
  ctx.call("__renderer", *args)
63
73
  rescue MiniRacer::RuntimeError => e
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: humid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johny Ho
@@ -37,7 +37,7 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '8.0'
40
- description: Javascript SSR rendering for Rails
40
+ description: Javascript Server Side Rendering (SSR) for Rails
41
41
  email: jho406@gmail.com
42
42
  executables: []
43
43
  extensions: []
@@ -68,5 +68,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
68
  requirements: []
69
69
  rubygems_version: 3.6.9
70
70
  specification_version: 4
71
- summary: Javascript SSR rendering for Rails
71
+ summary: Javascript Server Side Rendering (SSR) for Rails
72
72
  test_files: []