humid 0.1.0 → 0.5.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 +173 -57
- data/lib/humid/controller_runtime.rb +1 -1
- data/lib/humid/log_subscriber.rb +1 -1
- data/lib/humid/version.rb +2 -2
- data/lib/humid.rb +65 -78
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b62f6d6c3c7ffac0ba1c609965742a6a09dafebe0ebb9fc05cbae3c9200299e
|
|
4
|
+
data.tar.gz: 56557384d6768ada9b8fa9e9403720b5e75f03a579e39483892afcb631cb04a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4465a746beab25d302782cc71b8a70cd7fe827dc6ce3058e6720056c121bb86357733a9d31a7c266ceee6a53f938b174fec1eef111dbc634aa6699ffccb30ac9
|
|
7
|
+
data.tar.gz: c5d8a1c61b84b49a14a78c7d198af09871bbdf9cebc8c9bbd1d4b32c2cdd95ac7de2bad06214f80ec12a8507158b8bb95a592eff313e51e454dcd768e5a2cdc1
|
data/README.md
CHANGED
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
Humid is a
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Humid is a set of helper functions for using `mini_racer` for Server Side
|
|
6
|
+
Rendering (SSR). **There are only 2 pure public functions and a `configure` to set
|
|
7
|
+
default args**. `mini_racer` does the heavy lifting, Humid just provides a few
|
|
8
|
+
conveniences.
|
|
9
|
+
|
|
10
|
+
While it was built with React in mind, it can work with any JS function that
|
|
11
|
+
returns an HTML string.
|
|
12
|
+
|
|
13
|
+
## Design
|
|
14
|
+
|
|
15
|
+
Humid is designed for the common case where all data is gathered before
|
|
16
|
+
rendering. Your application fetches everything needed, passes it as props, and
|
|
17
|
+
Humid returns the rendered HTML in a single synchronous call. It does not
|
|
18
|
+
support streaming or async data fetching during render.
|
|
8
19
|
|
|
9
20
|
## Caution
|
|
10
21
|
|
|
@@ -26,12 +37,14 @@ For source-map support, also add
|
|
|
26
37
|
yarn add source-map-support
|
|
27
38
|
```
|
|
28
39
|
|
|
29
|
-
|
|
30
40
|
## Configuration
|
|
31
41
|
|
|
32
|
-
Add an initializer to configure
|
|
42
|
+
Add an initializer to configure the default options for `Humid.render`. These
|
|
43
|
+
are overridable on `Humid.render`.
|
|
33
44
|
|
|
34
45
|
```ruby
|
|
46
|
+
# app/initializers/humid.rb
|
|
47
|
+
|
|
35
48
|
Humid.configure do |config|
|
|
36
49
|
# Path to your build file located in `app/assets/builds/`. You should use a
|
|
37
50
|
# separate build apart from your `application.js`.
|
|
@@ -55,41 +68,70 @@ Humid.configure do |config|
|
|
|
55
68
|
# the respective logger levels on the ruby side.
|
|
56
69
|
#
|
|
57
70
|
# Defaults to `nil`
|
|
58
|
-
config.logger = Rails.env.
|
|
59
|
-
|
|
60
|
-
# Options passed to mini_racer.
|
|
61
|
-
#
|
|
62
|
-
# Defaults to empty `{}`.
|
|
63
|
-
config.context_options = {
|
|
64
|
-
timeout: 1000,
|
|
65
|
-
ensure_gc_after_idle: 2000
|
|
66
|
-
}
|
|
71
|
+
config.logger = Rails.env.local? ? Rails.logger : nil
|
|
67
72
|
end
|
|
68
73
|
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
|
|
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
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Usage
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
### Create the MiniRacer Context.
|
|
86
|
+
|
|
87
|
+
On local development or test environments, uncomment the below.
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
if Rails.env.local?
|
|
72
91
|
# Use single_threaded mode for Spring and other forked envs.
|
|
73
92
|
MiniRacer::Platform.set_flags! :single_threaded
|
|
74
|
-
|
|
93
|
+
ctx = MiniRacer::Context.new(timeout: 100, ensure_gc_after_idle: 2000)
|
|
94
|
+
MINI_RACER_CONTEXT = Humid.prepare(ctx)
|
|
75
95
|
end
|
|
76
96
|
```
|
|
77
97
|
|
|
78
|
-
|
|
98
|
+
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.**
|
|
79
102
|
|
|
80
|
-
|
|
81
|
-
workers ENV.fetch("WEB_CONCURRENCY") { 1 }
|
|
103
|
+
For example with puma:
|
|
82
104
|
|
|
105
|
+
```ruby
|
|
106
|
+
# config/puma.rb
|
|
83
107
|
on_worker_boot do
|
|
84
|
-
|
|
108
|
+
ctx = MiniRacer::Context.new(timeout: 100, ensure_gc_after_idle: 2000)
|
|
109
|
+
MINI_RACER_CONTEXT = Humid.prepare(ctx)
|
|
85
110
|
end
|
|
86
111
|
|
|
87
112
|
on_worker_shutdown do
|
|
88
|
-
|
|
113
|
+
MINI_RACER_CONTEXT.dispose
|
|
89
114
|
end
|
|
90
115
|
```
|
|
91
116
|
|
|
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.
|
|
122
|
+
|
|
123
|
+
You can also override config options per-context:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
MINI_RACER_CONTEXT = Humid.prepare(
|
|
127
|
+
MiniRacer::Context.new(timeout: 1000),
|
|
128
|
+
application_path: Rails.root.join("other_bundle.js"),
|
|
129
|
+
logger: nil
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
92
133
|
If you'd like support for source map support, you will need to
|
|
134
|
+
|
|
93
135
|
1. Add the following to your entry file, e.g, `server_rendering.js`.
|
|
94
136
|
2. set `config.source_map_path`.
|
|
95
137
|
|
|
@@ -103,27 +145,11 @@ require("source-map-support").install({
|
|
|
103
145
|
}
|
|
104
146
|
});
|
|
105
147
|
```
|
|
106
|
-
A [sample] webpack.config is available for reference.
|
|
107
|
-
|
|
108
|
-
## The mini_racer environment.
|
|
109
|
-
|
|
110
|
-
### Functions not available
|
|
111
|
-
|
|
112
|
-
The following functions are **not** available in the mini_racer environment
|
|
113
|
-
|
|
114
|
-
- `setTimeout`
|
|
115
|
-
- `clearTimeout`
|
|
116
|
-
- `setInterval`
|
|
117
|
-
- `clearInterval`
|
|
118
|
-
- `setImmediate`
|
|
119
|
-
- `clearImmediate`
|
|
120
148
|
|
|
121
|
-
|
|
149
|
+
See the [sample server_rendering.tsx](./sample/server_rendering.tsx) to see how
|
|
150
|
+
it is integrated.
|
|
122
151
|
|
|
123
|
-
|
|
124
|
-
respective methods on the configured logger.
|
|
125
|
-
|
|
126
|
-
## Usage
|
|
152
|
+
### Add a renderer and call `Humid.render`
|
|
127
153
|
|
|
128
154
|
In your entry file, e.g, `server_rendering.js`, pass your HTML render function
|
|
129
155
|
to `setHumidRenderer`. There is no need to require the function.
|
|
@@ -143,7 +169,7 @@ setHumidRenderer((json) => {
|
|
|
143
169
|
And finally call `render` from ERB.
|
|
144
170
|
|
|
145
171
|
```ruby
|
|
146
|
-
<%= Humid.render(
|
|
172
|
+
<%= Humid.render(MINI_RACER_CONTEXT, json).html_safe %>
|
|
147
173
|
```
|
|
148
174
|
|
|
149
175
|
Instrumentation is included:
|
|
@@ -152,24 +178,49 @@ Instrumentation is included:
|
|
|
152
178
|
Completed 200 OK in 14ms (Views: 0.2ms | Humid SSR: 11.0ms | ActiveRecord: 2.7ms)
|
|
153
179
|
```
|
|
154
180
|
|
|
155
|
-
|
|
181
|
+
## The prepared `mini_racer` environment.
|
|
156
182
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
183
|
+
### Functions not available
|
|
184
|
+
|
|
185
|
+
The following functions are **not** available in the mini_racer environment
|
|
186
|
+
|
|
187
|
+
- `setTimeout`
|
|
188
|
+
- `clearTimeout`
|
|
189
|
+
- `setInterval`
|
|
190
|
+
- `clearInterval`
|
|
191
|
+
- `setImmediate`
|
|
192
|
+
- `clearImmediate`
|
|
193
|
+
|
|
194
|
+
### `console.log`
|
|
195
|
+
|
|
196
|
+
`console.log` and friends (`info`, `error`, `warn`) are delegated to the
|
|
197
|
+
respective methods on the configured logger.
|
|
198
|
+
|
|
199
|
+
All arguments are passed through — MiniRacer converts JS objects to Ruby
|
|
200
|
+
hashes and arrays automatically. A `log_formatter` proc controls how these
|
|
201
|
+
arguments are formatted into a single string for the logger:
|
|
160
202
|
|
|
161
203
|
```ruby
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Humid.create_context
|
|
165
|
-
end
|
|
204
|
+
Humid.configure do |config|
|
|
205
|
+
config.logger = Rails.logger
|
|
166
206
|
|
|
167
|
-
|
|
168
|
-
|
|
207
|
+
config.log_formatter = proc { |level, message, *rest|
|
|
208
|
+
parts = [message]
|
|
209
|
+
parts += rest.map { |a| a.is_a?(String) ? a : JSON.pretty_generate(a) }
|
|
210
|
+
parts.join("\n")
|
|
211
|
+
}
|
|
169
212
|
end
|
|
170
213
|
```
|
|
171
214
|
|
|
172
|
-
|
|
215
|
+
The formatter receives `(level, message, *rest)` where:
|
|
216
|
+
- `level` — the log level as a symbol (`:debug`, `:info`, `:warn`, `:error`)
|
|
217
|
+
- `message` — the first argument passed to `console.log/info/warn/error`
|
|
218
|
+
- `rest` — any additional arguments (objects come through as Ruby hashes/arrays)
|
|
219
|
+
|
|
220
|
+
The default formatter returns `message` unchanged.
|
|
221
|
+
|
|
222
|
+
## Server-side libraries that detect node.js envs.
|
|
223
|
+
|
|
173
224
|
You may need webpacker to create aliases for server friendly libraries that can
|
|
174
225
|
not detect the `mini_racer` environment. For example, in `webpack.config.js`.
|
|
175
226
|
|
|
@@ -187,7 +238,7 @@ not detect the `mini_racer` environment. For example, in `webpack.config.js`.
|
|
|
187
238
|
[Vue has a resource][vue_ssr] on how to write universal code. Below
|
|
188
239
|
are a few highlights that are important to keep in mind.
|
|
189
240
|
|
|
190
|
-
|
|
241
|
+
## State
|
|
191
242
|
|
|
192
243
|
Humid uses a single context across multiple request. To avoid state pollution, we
|
|
193
244
|
provide a factory function to `setHumidRenderer` that builds a new app instance on
|
|
@@ -196,9 +247,9 @@ every call.
|
|
|
196
247
|
This provides better isolation, but as it is still a shared context, polluting
|
|
197
248
|
`global` is still possible. Be careful of modifying `global` in your code.
|
|
198
249
|
|
|
199
|
-
|
|
250
|
+
## Missing browser APIs
|
|
200
251
|
|
|
201
|
-
|
|
252
|
+
Some libraries that depend on browser APIs will fail in the
|
|
202
253
|
`mini_racer` environment because of missing browser APIs. Account for this by
|
|
203
254
|
moving the `require` to `useEffect` in your component.
|
|
204
255
|
|
|
@@ -209,6 +260,71 @@ moving the `require` to `useEffect` in your component.
|
|
|
209
260
|
}, [])
|
|
210
261
|
```
|
|
211
262
|
|
|
263
|
+
## Polyfills
|
|
264
|
+
|
|
265
|
+
React SSR may import node.js dependencies that you need to polyfill for. See
|
|
266
|
+
a sample esbuild [build script](./sample/bulid_ssr.js) and a [shim.js](./sample/shim.js)
|
|
267
|
+
to get around these issues.
|
|
268
|
+
|
|
269
|
+
## Testing
|
|
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:
|
|
273
|
+
|
|
274
|
+
```ruby
|
|
275
|
+
ActiveSupport.on_load(:action_dispatch_integration_test) do
|
|
276
|
+
include ActionView::Helpers::TranslationHelper
|
|
277
|
+
include Devise::Test::IntegrationHelpers
|
|
278
|
+
|
|
279
|
+
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))
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
parallelize_teardown do
|
|
287
|
+
MINI_RACER_CONTEXT.dispose if defined?(MINI_RACER_CONTEXT)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## Telemetry
|
|
293
|
+
|
|
294
|
+
The `MiniRacer::Context` gives you access to V8 heap statistics for monitoring
|
|
295
|
+
memory usage over time.
|
|
296
|
+
|
|
297
|
+
```ruby
|
|
298
|
+
MINI_RACER_CONTEXT.heap_stats
|
|
299
|
+
# {:total_heap_size=>3100672,
|
|
300
|
+
# :total_heap_size_executable=>4194304,
|
|
301
|
+
# :total_physical_size=>1280640,
|
|
302
|
+
# :total_available_size=>1501560832,
|
|
303
|
+
# :used_heap_size=>1205376,
|
|
304
|
+
# :heap_size_limit=>1501560832,
|
|
305
|
+
# ...}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
You can combine humid's instrumentation and OpenTelemetry to track heap growth
|
|
309
|
+
per worker:
|
|
310
|
+
|
|
311
|
+
```ruby
|
|
312
|
+
meter = OpenTelemetry.meter_provider.meter("humid")
|
|
313
|
+
render_histogram = meter.create_histogram("humid.render.duration", unit: "ms", description: "SSR render duration")
|
|
314
|
+
heap_gauge = meter.create_gauge("humid.heap.used_bytes", unit: "By", description: "V8 heap used bytes")
|
|
315
|
+
|
|
316
|
+
ActiveSupport::Notifications.subscribe("render.humid") do |event|
|
|
317
|
+
stats = MINI_RACER_CONTEXT.heap_stats
|
|
318
|
+
attributes = { "worker.pid" => Process.pid.to_s }
|
|
319
|
+
|
|
320
|
+
render_histogram.record(event.duration, attributes: attributes)
|
|
321
|
+
heap_gauge.record(stats[:used_heap_size], attributes: attributes)
|
|
322
|
+
end
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
A steadily climbing `used_heap_size` across requests indicates a memory leak in
|
|
326
|
+
your JavaScript bundle.
|
|
327
|
+
|
|
212
328
|
## Contributing
|
|
213
329
|
|
|
214
330
|
Please see [CONTRIBUTING.md](/CONTRIBUTING.md).
|
data/lib/humid/log_subscriber.rb
CHANGED
data/lib/humid/version.rb
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
VERSION = "0.
|
|
1
|
+
module Humid
|
|
2
|
+
VERSION = "0.5.0".freeze
|
|
3
3
|
end
|
data/lib/humid.rb
CHANGED
|
@@ -6,106 +6,93 @@ require "humid/log_subscriber"
|
|
|
6
6
|
require "humid/controller_runtime"
|
|
7
7
|
require "humid/version"
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
@@context = nil
|
|
11
|
-
|
|
9
|
+
module Humid
|
|
12
10
|
class RenderError < StandardError
|
|
13
11
|
end
|
|
14
12
|
|
|
15
13
|
class FileNotFound < StandardError
|
|
16
14
|
end
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
mattr_accessor :config
|
|
19
17
|
|
|
20
18
|
self.config = ActiveSupport::OrderedOptions.new.merge({
|
|
21
19
|
raise_render_errors: true,
|
|
22
|
-
|
|
20
|
+
log_formatter: proc { |_level, message, *_rest| message },
|
|
23
21
|
})
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def remove_functions
|
|
31
|
-
<<~JS
|
|
32
|
-
delete this.setTimeout;
|
|
33
|
-
delete this.setInterval;
|
|
34
|
-
delete this.clearTimeout;
|
|
35
|
-
delete this.clearInterval;
|
|
36
|
-
delete this.setImmediate;
|
|
37
|
-
delete this.clearImmediate;
|
|
38
|
-
JS
|
|
39
|
-
end
|
|
23
|
+
extend self
|
|
24
|
+
|
|
25
|
+
def configure
|
|
26
|
+
yield self.config
|
|
27
|
+
end
|
|
40
28
|
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
def prepare(ctx, options = {})
|
|
30
|
+
effective_config = config.merge(options)
|
|
31
|
+
logger = effective_config.logger
|
|
32
|
+
log_formatter = effective_config.log_formatter
|
|
33
|
+
|
|
34
|
+
if logger
|
|
35
|
+
fmt = log_formatter || proc { |_level, message, *_rest| message }
|
|
36
|
+
ctx.attach("console.log", proc { |*args| logger.debug(fmt.call(:debug, *args)) })
|
|
37
|
+
ctx.attach("console.info", proc { |*args| logger.info(fmt.call(:info, *args)) })
|
|
38
|
+
ctx.attach("console.error", proc { |*args| logger.error(fmt.call(:error, *args)) })
|
|
39
|
+
ctx.attach("console.warn", proc { |*args| logger.warn(fmt.call(:warn, *args)) })
|
|
43
40
|
end
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
__renderer = fn;
|
|
50
|
-
}
|
|
51
|
-
JS
|
|
52
|
-
end
|
|
42
|
+
js = ""
|
|
43
|
+
js << remove_functions
|
|
44
|
+
js << renderer
|
|
45
|
+
ctx.eval(js)
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
47
|
+
source_path = effective_config.application_path
|
|
48
|
+
map_path = effective_config.source_map_path
|
|
57
49
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@@context.dispose
|
|
61
|
-
@@context = nil
|
|
62
|
-
end
|
|
50
|
+
if map_path
|
|
51
|
+
ctx.attach("readSourceMap", proc { File.read(map_path) })
|
|
63
52
|
end
|
|
64
53
|
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
filename = File.basename(source_path.to_s)
|
|
55
|
+
ctx.eval(File.read(source_path), filename: filename)
|
|
67
56
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
ctx.attach("console.info", proc { |err| logger.info(err.to_s) })
|
|
71
|
-
ctx.attach("console.error", proc { |err| logger.error(err.to_s) })
|
|
72
|
-
ctx.attach("console.warn", proc { |err| logger.warn(err.to_s) })
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
js = ""
|
|
76
|
-
js << remove_functions
|
|
77
|
-
js << renderer
|
|
78
|
-
ctx.eval(js)
|
|
79
|
-
|
|
80
|
-
source_path = config.application_path
|
|
81
|
-
map_path = config.source_map_path
|
|
57
|
+
ctx
|
|
58
|
+
end
|
|
82
59
|
|
|
83
|
-
|
|
84
|
-
|
|
60
|
+
def render(ctx, *args)
|
|
61
|
+
ActiveSupport::Notifications.instrument("render.humid") do
|
|
62
|
+
ctx.call("__renderer", *args)
|
|
63
|
+
rescue MiniRacer::RuntimeError => e
|
|
64
|
+
message = ([e.message] + e.backtrace.filter { |x| x.starts_with? "JavaScript" }).join("\n")
|
|
65
|
+
render_error = Humid::RenderError.new(message)
|
|
66
|
+
|
|
67
|
+
if config.raise_render_errors
|
|
68
|
+
raise render_error
|
|
69
|
+
else
|
|
70
|
+
config.logger.error(render_error.inspect)
|
|
71
|
+
""
|
|
85
72
|
end
|
|
86
|
-
|
|
87
|
-
filename = File.basename(source_path.to_s)
|
|
88
|
-
@@current_filename = filename
|
|
89
|
-
ctx.eval(File.read(source_path), filename: filename)
|
|
90
|
-
|
|
91
|
-
@@context = ctx
|
|
92
73
|
end
|
|
74
|
+
end
|
|
93
75
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def remove_functions
|
|
79
|
+
<<~JS
|
|
80
|
+
delete this.setTimeout;
|
|
81
|
+
delete this.setInterval;
|
|
82
|
+
delete this.clearTimeout;
|
|
83
|
+
delete this.clearInterval;
|
|
84
|
+
delete this.setImmediate;
|
|
85
|
+
delete this.clearImmediate;
|
|
86
|
+
JS
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def renderer
|
|
90
|
+
<<~JS
|
|
91
|
+
var __renderer;
|
|
92
|
+
function setHumidRenderer(fn) {
|
|
93
|
+
__renderer = fn;
|
|
94
|
+
}
|
|
95
|
+
JS
|
|
109
96
|
end
|
|
110
97
|
end
|
|
111
98
|
|