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.
- checksums.yaml +4 -4
- data/README.md +73 -78
- data/lib/humid/version.rb +1 -1
- data/lib/humid.rb +13 -3
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c7f343b4b1518296d59917fb37ce2f8a60ee6b1a57b71f3fd378ce2ad55a4d4
|
|
4
|
+
data.tar.gz: e11384d2812e0de2cb7e676fa237957d44fbe63cf788e73adf997c9a14b2015e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
#
|
|
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(
|
|
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(
|
|
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
|
|
61
|
+
# logged and Humid.render will return an empty string.
|
|
62
62
|
#
|
|
63
63
|
# Defaults to true.
|
|
64
|
-
config.raise_render_errors = Rails.env.
|
|
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
|
-
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
100
|
-
|
|
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:
|
|
109
|
-
|
|
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
|
-
|
|
143
|
+
MINI_RACER_SSR[:context].dispose
|
|
114
144
|
end
|
|
115
145
|
```
|
|
116
146
|
|
|
117
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
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(
|
|
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
|
|
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
|
|
272
|
-
|
|
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
|
-
|
|
281
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
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.
|
|
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
|
|
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
|
|
71
|
+
summary: Javascript Server Side Rendering (SSR) for Rails
|
|
72
72
|
test_files: []
|