humid 0.0.5 → 0.1.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 +67 -70
- 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 +73 -108
- metadata +7 -86
- data/spec/controller_runtime_spec.rb +0 -79
- data/spec/log_subscriber_spec.rb +0 -54
- data/spec/render_spec.rb +0 -188
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6c4f5090d85ea4b1c4998f6c8533816a8875039f2ffe5b5785e3e571092445c6
|
|
4
|
+
data.tar.gz: 844410054db5d2c89fa3fc1fd3ac4d64f83605cf4a157573ebd6d172b01d0a7f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 574e6c64e749180f964a3d9ffe4dd91f18179408901b4b26960b2ef3c9bbe12c601e0879fc97bb60b340ed0270be627aaf0cc92d18827deda5f45dd515d952c4
|
|
7
|
+
data.tar.gz: b1511fc86f5655ac063bf6d927866bd00096c7ddca23e822e2cd3dbe03a97d1e4f62288f1242c9b436e67695402c2a61a59e4f096a0dc0f3dbf450ac0fbdc250
|
data/README.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# Humid
|
|
2
|
-
[](https://circleci.com/gh/thoughtbot/humid)
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Humid is a lightweight wrapper around [mini_racer] used to generate Server
|
|
6
|
+
Side Rendered (SSR) pages from your js-bundling builds. While it was built
|
|
7
|
+
for React, it can work with any JS function that returns a HTML string.
|
|
9
8
|
|
|
10
9
|
## Caution
|
|
11
10
|
|
|
@@ -34,16 +33,16 @@ Add an initializer to configure
|
|
|
34
33
|
|
|
35
34
|
```ruby
|
|
36
35
|
Humid.configure do |config|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
36
|
+
# Path to your build file located in `app/assets/builds/`. You should use a
|
|
37
|
+
# separate build apart from your `application.js`.
|
|
39
38
|
#
|
|
40
|
-
#
|
|
41
|
-
config.
|
|
39
|
+
# Required
|
|
40
|
+
config.application_path = Rails.root.join('app', 'assets', 'builds', 'server_rendering.js')
|
|
42
41
|
|
|
43
|
-
#
|
|
42
|
+
# Path to your source map file
|
|
44
43
|
#
|
|
45
|
-
#
|
|
46
|
-
config.
|
|
44
|
+
# Optional
|
|
45
|
+
config.source_map_path = Rails.root.join('app', 'assets', 'builds', 'server_rendering.js.map')
|
|
47
46
|
|
|
48
47
|
# Raise errors if JS rendering failed. If false, the error will be
|
|
49
48
|
# logged out to Rails log and Humid.render will return an empty string
|
|
@@ -55,8 +54,8 @@ Humid.configure do |config|
|
|
|
55
54
|
# `console.log` and friends (`warn`, `error`) are delegated to
|
|
56
55
|
# the respective logger levels on the ruby side.
|
|
57
56
|
#
|
|
58
|
-
# Defaults to `
|
|
59
|
-
config.logger = Rails.logger
|
|
57
|
+
# Defaults to `nil`
|
|
58
|
+
config.logger = Rails.env.development? ? Rails.logger : nil
|
|
60
59
|
|
|
61
60
|
# Options passed to mini_racer.
|
|
62
61
|
#
|
|
@@ -67,19 +66,32 @@ Humid.configure do |config|
|
|
|
67
66
|
}
|
|
68
67
|
end
|
|
69
68
|
|
|
70
|
-
#
|
|
71
|
-
|
|
69
|
+
# Capybara defines its own puma config which is set up to run a single puma process
|
|
70
|
+
# with a thread pool. This ensures that a context gets created on that process.
|
|
71
|
+
if Rails.env.test?
|
|
72
72
|
# Use single_threaded mode for Spring and other forked envs.
|
|
73
73
|
MiniRacer::Platform.set_flags! :single_threaded
|
|
74
|
+
Humid.create_context
|
|
75
|
+
end
|
|
76
|
+
```
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
Then add to your `config/puma.rb`
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
workers ENV.fetch("WEB_CONCURRENCY") { 1 }
|
|
82
|
+
|
|
83
|
+
on_worker_boot do
|
|
76
84
|
Humid.create_context
|
|
77
85
|
end
|
|
86
|
+
|
|
87
|
+
on_worker_shutdown do
|
|
88
|
+
Humid.dispose
|
|
89
|
+
end
|
|
78
90
|
```
|
|
79
91
|
|
|
80
92
|
If you'd like support for source map support, you will need to
|
|
81
|
-
1.
|
|
82
|
-
2.
|
|
93
|
+
1. Add the following to your entry file, e.g, `server_rendering.js`.
|
|
94
|
+
2. set `config.source_map_path`.
|
|
83
95
|
|
|
84
96
|
```javascript
|
|
85
97
|
require("source-map-support").install({
|
|
@@ -91,6 +103,7 @@ require("source-map-support").install({
|
|
|
91
103
|
}
|
|
92
104
|
});
|
|
93
105
|
```
|
|
106
|
+
A [sample] webpack.config is available for reference.
|
|
94
107
|
|
|
95
108
|
## The mini_racer environment.
|
|
96
109
|
|
|
@@ -112,7 +125,8 @@ respective methods on the configured logger.
|
|
|
112
125
|
|
|
113
126
|
## Usage
|
|
114
127
|
|
|
115
|
-
|
|
128
|
+
In your entry file, e.g, `server_rendering.js`, pass your HTML render function
|
|
129
|
+
to `setHumidRenderer`. There is no need to require the function.
|
|
116
130
|
|
|
117
131
|
```javascript
|
|
118
132
|
// Set a factory function that will create a new instance of our app
|
|
@@ -129,7 +143,7 @@ setHumidRenderer((json) => {
|
|
|
129
143
|
And finally call `render` from ERB.
|
|
130
144
|
|
|
131
145
|
```ruby
|
|
132
|
-
<%= Humid.render(initial_state) %>
|
|
146
|
+
<%= Humid.render(initial_state).html_safe %>
|
|
133
147
|
```
|
|
134
148
|
|
|
135
149
|
Instrumentation is included:
|
|
@@ -141,7 +155,8 @@ Completed 200 OK in 14ms (Views: 0.2ms | Humid SSR: 11.0ms | ActiveRecord: 2.7ms
|
|
|
141
155
|
### Puma
|
|
142
156
|
|
|
143
157
|
`mini_racer` is thread safe, but not fork safe. To use with web servers that
|
|
144
|
-
employ forking, use `Humid.create_context` only on forked processes.
|
|
158
|
+
employ forking, use `Humid.create_context` only on forked processes. On
|
|
159
|
+
production, There should be no context created on the master process.
|
|
145
160
|
|
|
146
161
|
```ruby
|
|
147
162
|
# Puma
|
|
@@ -156,41 +171,20 @@ end
|
|
|
156
171
|
|
|
157
172
|
### Server-side libraries that detect node.js envs.
|
|
158
173
|
You may need webpacker to create aliases for server friendly libraries that can
|
|
159
|
-
not detect the `mini_racer` environment.
|
|
174
|
+
not detect the `mini_racer` environment. For example, in `webpack.config.js`.
|
|
160
175
|
|
|
161
176
|
```diff
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
+const path = require('path')
|
|
170
|
-
+const ConfigObject = require('@rails/webpacker/package/config_types/config
|
|
171
|
-
|
|
172
|
-
-module.exports = environment.toWebpackConfig()
|
|
173
|
-
+const webConfig = environment.toWebpackConfig()
|
|
174
|
-
+const ssrConfig = new ConfigObject(webConfig.toObject())
|
|
175
|
-
+
|
|
176
|
-
+ssrConfig.delete('entry')
|
|
177
|
-
+ssrConfig.merge({
|
|
178
|
-
+ entry: {
|
|
179
|
-
+ server_rendering: webConfig.entry.server_rendering
|
|
180
|
-
+ },
|
|
181
|
-
+ resolve: {
|
|
182
|
-
+ alias: {
|
|
183
|
-
+ 'html-dom-parser': path.resolve(__dirname, '../../node_modules/html-dom-parser/lib/html-to-dom-server')
|
|
184
|
-
+ }
|
|
185
|
-
+ }
|
|
186
|
-
+})
|
|
187
|
-
+
|
|
188
|
-
+delete webConfig.entry.server_rendering
|
|
189
|
-
+module.exports = [ssrConfig, webConfig]
|
|
177
|
+
...
|
|
178
|
+
resolve: {
|
|
179
|
+
alias: {
|
|
180
|
+
'html-dom-parser': path.resolve(__dirname, '../../node_modules/html-dom-parser/lib/html-to-dom-server')
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
...
|
|
190
184
|
```
|
|
191
185
|
|
|
192
186
|
## Writing universal code
|
|
193
|
-
[Vue has
|
|
187
|
+
[Vue has a resource][vue_ssr] on how to write universal code. Below
|
|
194
188
|
are a few highlights that are important to keep in mind.
|
|
195
189
|
|
|
196
190
|
### State
|
|
@@ -202,19 +196,17 @@ every call.
|
|
|
202
196
|
This provides better isolation, but as it is still a shared context, polluting
|
|
203
197
|
`global` is still possible. Be careful of modifying `global` in your code.
|
|
204
198
|
|
|
205
|
-
###
|
|
199
|
+
### Missing browser APIs
|
|
206
200
|
|
|
207
|
-
Polyfills
|
|
208
|
-
browser APIs. Account for this by
|
|
209
|
-
in your component.
|
|
201
|
+
Polyfills and some libraries that depend on browser APIs will fail in the
|
|
202
|
+
`mini_racer` environment because of missing browser APIs. Account for this by
|
|
203
|
+
moving the `require` to `useEffect` in your component.
|
|
210
204
|
|
|
211
205
|
```
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.dialog.current.showModal()
|
|
217
|
-
}
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
const svgPanZoom = require('svg-pan-zoom')
|
|
208
|
+
//...
|
|
209
|
+
}, [])
|
|
218
210
|
```
|
|
219
211
|
|
|
220
212
|
## Contributing
|
|
@@ -223,23 +215,28 @@ Please see [CONTRIBUTING.md](/CONTRIBUTING.md).
|
|
|
223
215
|
|
|
224
216
|
## License
|
|
225
217
|
|
|
226
|
-
Humid is Copyright © 2021-
|
|
218
|
+
Humid is Copyright © 2021-2024 Johny Ho.
|
|
227
219
|
It is free software, and may be redistributed under the terms specified in the
|
|
228
220
|
[LICENSE](/LICENSE.md) file.
|
|
229
221
|
|
|
222
|
+
<!-- START /templates/footer.md -->
|
|
230
223
|
## About thoughtbot
|
|
231
224
|
|
|
232
|
-

|
|
233
226
|
|
|
234
|
-
|
|
227
|
+
This repo is maintained and funded by thoughtbot, inc.
|
|
235
228
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
|
236
229
|
|
|
237
230
|
We love open source software!
|
|
238
|
-
See [our other projects][community]
|
|
239
|
-
[hire
|
|
231
|
+
See [our other projects][community].
|
|
232
|
+
We are [available for hire][hire].
|
|
240
233
|
|
|
241
234
|
[community]: https://thoughtbot.com/community?utm_source=github
|
|
242
|
-
[hire]: https://thoughtbot.com?utm_source=github
|
|
235
|
+
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
<!-- END /templates/footer.md -->
|
|
239
|
+
|
|
243
240
|
[mini_racer]: https://github.com/rubyjs/mini_racer
|
|
244
|
-
[webpacker]: https://github.com/rails/webpacker
|
|
245
241
|
[vue_ssr]: https://ssr.vuejs.org/
|
|
242
|
+
[sample]: ./webpack.config.js
|
data/lib/humid/log_subscriber.rb
CHANGED
data/lib/humid/version.rb
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
VERSION = "0.0
|
|
1
|
+
class Humid
|
|
2
|
+
VERSION = "0.1.0".freeze
|
|
3
3
|
end
|
data/lib/humid.rb
CHANGED
|
@@ -1,144 +1,109 @@
|
|
|
1
1
|
require "mini_racer"
|
|
2
2
|
require "logger"
|
|
3
|
-
require "webpacker"
|
|
4
3
|
require "active_support"
|
|
5
4
|
require "active_support/core_ext"
|
|
6
5
|
require "humid/log_subscriber"
|
|
7
6
|
require "humid/controller_runtime"
|
|
8
7
|
require "humid/version"
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
include ActiveSupport::Configurable
|
|
9
|
+
class Humid
|
|
10
|
+
@@context = nil
|
|
13
11
|
|
|
14
12
|
class RenderError < StandardError
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
class FileNotFound < StandardError
|
|
18
16
|
end
|
|
17
|
+
|
|
18
|
+
class_attribute :config
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
config_accessor :use_source_map do
|
|
27
|
-
false
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
config_accessor :raise_render_errors do
|
|
31
|
-
true
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
config_accessor :logger do
|
|
35
|
-
Logger.new(STDOUT)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
config_accessor :context_options do
|
|
39
|
-
{}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def remove_functions
|
|
43
|
-
<<~JS
|
|
44
|
-
delete this.setTimeout;
|
|
45
|
-
delete this.setInterval;
|
|
46
|
-
delete this.clearTimeout;
|
|
47
|
-
delete this.clearInterval;
|
|
48
|
-
delete this.setImmediate;
|
|
49
|
-
delete this.clearImmediate;
|
|
50
|
-
JS
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def logger
|
|
54
|
-
config.logger
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def renderer
|
|
58
|
-
<<~JS
|
|
59
|
-
var __renderer;
|
|
60
|
-
function setHumidRenderer(fn) {
|
|
61
|
-
__renderer = fn;
|
|
62
|
-
}
|
|
63
|
-
JS
|
|
64
|
-
end
|
|
20
|
+
self.config = ActiveSupport::OrderedOptions.new.merge({
|
|
21
|
+
raise_render_errors: true,
|
|
22
|
+
context_options: {},
|
|
23
|
+
})
|
|
65
24
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
25
|
+
class << self
|
|
26
|
+
def configure
|
|
27
|
+
yield config
|
|
69
28
|
end
|
|
70
29
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
|
75
40
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
create_context
|
|
41
|
+
def logger
|
|
42
|
+
config.logger
|
|
79
43
|
end
|
|
80
|
-
end
|
|
81
44
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
45
|
+
def renderer
|
|
46
|
+
<<~JS
|
|
47
|
+
var __renderer;
|
|
48
|
+
function setHumidRenderer(fn) {
|
|
49
|
+
__renderer = fn;
|
|
50
|
+
}
|
|
51
|
+
JS
|
|
85
52
|
end
|
|
86
53
|
|
|
87
|
-
|
|
88
|
-
|
|
54
|
+
def context
|
|
55
|
+
@@context
|
|
56
|
+
end
|
|
89
57
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
58
|
+
def dispose
|
|
59
|
+
if @@context
|
|
60
|
+
@@context.dispose
|
|
61
|
+
@@context = nil
|
|
62
|
+
end
|
|
94
63
|
end
|
|
95
|
-
end
|
|
96
64
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
ctx.attach("console.log", proc { |err| logger.debug(err.to_s) })
|
|
100
|
-
ctx.attach("console.info", proc { |err| logger.info(err.to_s) })
|
|
101
|
-
ctx.attach("console.error", proc { |err| logger.error(err.to_s) })
|
|
102
|
-
ctx.attach("console.warn", proc { |err| logger.warn(err.to_s) })
|
|
65
|
+
def create_context
|
|
66
|
+
ctx = MiniRacer::Context.new(**config.context_options)
|
|
103
67
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
68
|
+
if logger
|
|
69
|
+
ctx.attach("console.log", proc { |err| logger.debug(err.to_s) })
|
|
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
|
|
108
74
|
|
|
109
|
-
|
|
75
|
+
js = ""
|
|
76
|
+
js << remove_functions
|
|
77
|
+
js << renderer
|
|
78
|
+
ctx.eval(js)
|
|
110
79
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
raise FileNotFound.new("Humid could not find a built pack for #{config.server_rendering_pack}")
|
|
114
|
-
end
|
|
80
|
+
source_path = config.application_path
|
|
81
|
+
map_path = config.source_map_path
|
|
115
82
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
ctx.attach("readSourceMap", proc { File.read(map_path) })
|
|
120
|
-
end
|
|
83
|
+
if map_path
|
|
84
|
+
ctx.attach("readSourceMap", proc { File.read(map_path) })
|
|
85
|
+
end
|
|
121
86
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
ctx.eval(File.read(source_path), filename: filename)
|
|
87
|
+
filename = File.basename(source_path.to_s)
|
|
88
|
+
@@current_filename = filename
|
|
89
|
+
ctx.eval(File.read(source_path), filename: filename)
|
|
126
90
|
|
|
127
|
-
|
|
128
|
-
|
|
91
|
+
@@context = ctx
|
|
92
|
+
end
|
|
129
93
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
94
|
+
def render(*args)
|
|
95
|
+
ActiveSupport::Notifications.instrument("render.humid") do
|
|
96
|
+
context.call("__renderer", *args)
|
|
97
|
+
rescue MiniRacer::RuntimeError => e
|
|
98
|
+
message = ([e.message] + e.backtrace.filter { |x| x.starts_with? "JavaScript" }).join("\n")
|
|
99
|
+
render_error = Humid::RenderError.new(message)
|
|
100
|
+
|
|
101
|
+
if config.raise_render_errors
|
|
102
|
+
raise render_error
|
|
103
|
+
else
|
|
104
|
+
config.logger.error(render_error.inspect)
|
|
105
|
+
""
|
|
106
|
+
end
|
|
142
107
|
end
|
|
143
108
|
end
|
|
144
109
|
end
|
metadata
CHANGED
|
@@ -1,29 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: humid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Johny Ho
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: webpacker
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '4.0'
|
|
20
|
-
type: :runtime
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '4.0'
|
|
27
12
|
- !ruby/object:Gem::Dependency
|
|
28
13
|
name: mini_racer
|
|
29
14
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -41,73 +26,17 @@ dependencies:
|
|
|
41
26
|
- !ruby/object:Gem::Dependency
|
|
42
27
|
name: activesupport
|
|
43
28
|
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - ">="
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '6.0'
|
|
48
|
-
type: :runtime
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - ">="
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '6.0'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: rake
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '12.0'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
29
|
requirements:
|
|
66
30
|
- - "~>"
|
|
67
31
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
69
|
-
|
|
70
|
-
name: rspec
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '3.8'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '3.8'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: byebug
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '9.0'
|
|
90
|
-
type: :development
|
|
32
|
+
version: '8.0'
|
|
33
|
+
type: :runtime
|
|
91
34
|
prerelease: false
|
|
92
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
36
|
requirements:
|
|
94
37
|
- - "~>"
|
|
95
38
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: rails
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - ">="
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '6.0'
|
|
104
|
-
type: :development
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - ">="
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '6.0'
|
|
39
|
+
version: '8.0'
|
|
111
40
|
description: Javascript SSR rendering for Rails
|
|
112
41
|
email: jho406@gmail.com
|
|
113
42
|
executables: []
|
|
@@ -119,14 +48,10 @@ files:
|
|
|
119
48
|
- lib/humid/controller_runtime.rb
|
|
120
49
|
- lib/humid/log_subscriber.rb
|
|
121
50
|
- lib/humid/version.rb
|
|
122
|
-
- spec/controller_runtime_spec.rb
|
|
123
|
-
- spec/log_subscriber_spec.rb
|
|
124
|
-
- spec/render_spec.rb
|
|
125
51
|
homepage: https://github.com/thoughtbot/humid/
|
|
126
52
|
licenses:
|
|
127
53
|
- MIT
|
|
128
54
|
metadata: {}
|
|
129
|
-
post_install_message:
|
|
130
55
|
rdoc_options: []
|
|
131
56
|
require_paths:
|
|
132
57
|
- lib
|
|
@@ -141,11 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
66
|
- !ruby/object:Gem::Version
|
|
142
67
|
version: '0'
|
|
143
68
|
requirements: []
|
|
144
|
-
rubygems_version: 3.
|
|
145
|
-
signing_key:
|
|
69
|
+
rubygems_version: 3.6.9
|
|
146
70
|
specification_version: 4
|
|
147
71
|
summary: Javascript SSR rendering for Rails
|
|
148
|
-
test_files:
|
|
149
|
-
- spec/render_spec.rb
|
|
150
|
-
- spec/log_subscriber_spec.rb
|
|
151
|
-
- spec/controller_runtime_spec.rb
|
|
72
|
+
test_files: []
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
require_relative "./support/helper"
|
|
2
|
-
|
|
3
|
-
describe Humid::ControllerRuntime do
|
|
4
|
-
controller_runtime = Humid::ControllerRuntime
|
|
5
|
-
|
|
6
|
-
def set_metric value
|
|
7
|
-
Humid::LogSubscriber.runtime = value
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def clear_metric!
|
|
11
|
-
Humid::LogSubscriber.reset_runtime = 0
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
reference_controller_class = Class.new {
|
|
15
|
-
def process_action *_
|
|
16
|
-
@process_action = true
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def cleanup_view_runtime *_
|
|
20
|
-
@cleanup_view_runtime.call
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def append_info_to_payload *_
|
|
24
|
-
@append_info_to_payload = true
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def self.log_process_action *_
|
|
28
|
-
@log_process_action.call
|
|
29
|
-
end
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
controller_class = Class.new reference_controller_class do
|
|
33
|
-
include controller_runtime
|
|
34
|
-
|
|
35
|
-
def logger
|
|
36
|
-
Logger.new(STDOUT)
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
let(:controller) { controller_class.new }
|
|
41
|
-
|
|
42
|
-
it "resets the metric before each action" do
|
|
43
|
-
set_metric 42
|
|
44
|
-
controller.send(:process_action, "foo")
|
|
45
|
-
expect(Humid::LogSubscriber.runtime).to be(0)
|
|
46
|
-
expect(controller.instance_variable_get("@process_action")).to be(true)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
it "strips the metric of other sources of the runtime" do
|
|
50
|
-
set_metric 1
|
|
51
|
-
controller.instance_variable_set "@cleanup_view_runtime", -> {
|
|
52
|
-
controller.instance_variable_set "@cleanup_view_runtime", true
|
|
53
|
-
set_metric 13
|
|
54
|
-
42
|
|
55
|
-
}
|
|
56
|
-
returned = controller.send :cleanup_view_runtime
|
|
57
|
-
expect(controller.instance_variable_get("@cleanup_view_runtime")).to be(true)
|
|
58
|
-
expect(controller.humid_runtime).to eq(14)
|
|
59
|
-
expect(returned).to be(29)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
it "appends the metric to payload" do
|
|
63
|
-
payload = {}
|
|
64
|
-
set_metric 42
|
|
65
|
-
controller.send :append_info_to_payload, payload
|
|
66
|
-
expect(controller.instance_variable_get("@append_info_to_payload")).to be(true)
|
|
67
|
-
expect(payload[:humid_runtime]).to eq(42)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "adds metric to log message" do
|
|
71
|
-
controller_class.instance_variable_set "@log_process_action", -> {
|
|
72
|
-
controller_class.instance_variable_set "@log_process_action", true
|
|
73
|
-
[]
|
|
74
|
-
}
|
|
75
|
-
messages = controller_class.log_process_action humid_runtime: 42.101
|
|
76
|
-
expect(controller_class.instance_variable_get("@log_process_action")).to be(true)
|
|
77
|
-
expect(messages).to eq(["Humid SSR: 42.1ms"])
|
|
78
|
-
end
|
|
79
|
-
end
|
data/spec/log_subscriber_spec.rb
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
require_relative "./support/helper"
|
|
2
|
-
require "active_support/log_subscriber/test_helper"
|
|
3
|
-
require "byebug"
|
|
4
|
-
|
|
5
|
-
RSpec.describe Humid::LogSubscriber do
|
|
6
|
-
around(:each) do |example|
|
|
7
|
-
app_path = File.expand_path("./testapp", File.dirname(__FILE__))
|
|
8
|
-
Dir.chdir(app_path) do
|
|
9
|
-
example.run
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
before(:each) do
|
|
14
|
-
Humid::LogSubscriber.reset_runtime
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
context ".runtime" do
|
|
18
|
-
it "is returns the runtime from the thread local" do
|
|
19
|
-
expect(Humid::LogSubscriber.runtime).to eql 0
|
|
20
|
-
key = "attr_Humid::LogSubscriber_humid_runtime"
|
|
21
|
-
Thread.current[key] = 3
|
|
22
|
-
expect(Humid::LogSubscriber.runtime).to eql 3
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
context ".runtime=" do
|
|
27
|
-
it "sets the runtime in a thread-safe manner" do
|
|
28
|
-
expect(Humid::LogSubscriber.runtime).to eql 0
|
|
29
|
-
Humid::LogSubscriber.runtime = 3
|
|
30
|
-
key = "attr_Humid::LogSubscriber_humid_runtime"
|
|
31
|
-
expect(Thread.current[key]).to eql 3
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
context ".reset_runtime" do
|
|
36
|
-
it "resets the runtime" do
|
|
37
|
-
Humid::LogSubscriber.runtime = 3
|
|
38
|
-
key = "attr_Humid::LogSubscriber_humid_runtime"
|
|
39
|
-
expect(Thread.current[key]).to eql 3
|
|
40
|
-
|
|
41
|
-
Humid::LogSubscriber.reset_runtime
|
|
42
|
-
expect(Thread.current[key]).to eql 0
|
|
43
|
-
expect(Humid::LogSubscriber.runtime).to eql 0
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "is attached" do
|
|
48
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
49
|
-
Humid.create_context
|
|
50
|
-
expect(Humid::LogSubscriber.runtime).to eql(0)
|
|
51
|
-
Humid.render
|
|
52
|
-
expect(Humid::LogSubscriber.runtime).to be > 0
|
|
53
|
-
end
|
|
54
|
-
end
|
data/spec/render_spec.rb
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
require_relative "./support/helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe "Humid" do
|
|
4
|
-
around(:each) do |example|
|
|
5
|
-
app_path = File.expand_path("./testapp", File.dirname(__FILE__))
|
|
6
|
-
Dir.chdir(app_path) do
|
|
7
|
-
example.run
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe "create_context" do
|
|
12
|
-
after(:each) do
|
|
13
|
-
Humid.dispose
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it "creates a context with initial js" do
|
|
17
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
18
|
-
Humid.create_context
|
|
19
|
-
|
|
20
|
-
expect(Humid.context).to be_kind_of(MiniRacer::Context)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context "When the file can not be found" do
|
|
24
|
-
it "raises" do
|
|
25
|
-
allow(Humid.config).to receive("server_rendering_pack") { "does_not_exist.js" }
|
|
26
|
-
|
|
27
|
-
expect {
|
|
28
|
-
Humid.create_context
|
|
29
|
-
}.to raise_error(Humid::FileNotFound, "Humid could not find a built pack for does_not_exist.js")
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "does not have timeouts, immediates, and intervals" do
|
|
34
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
35
|
-
|
|
36
|
-
Humid.create_context
|
|
37
|
-
|
|
38
|
-
expect {
|
|
39
|
-
Humid.context.eval("setTimeout()")
|
|
40
|
-
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: setTimeout is not defined")
|
|
41
|
-
expect {
|
|
42
|
-
Humid.context.eval("setInterval()")
|
|
43
|
-
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: setInterval is not defined")
|
|
44
|
-
expect {
|
|
45
|
-
Humid.context.eval("clearTimeout()")
|
|
46
|
-
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: clearTimeout is not defined")
|
|
47
|
-
expect {
|
|
48
|
-
Humid.context.eval("setImmediate()")
|
|
49
|
-
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: setImmediate is not defined")
|
|
50
|
-
expect {
|
|
51
|
-
Humid.context.eval("clearImmediate()")
|
|
52
|
-
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: clearImmediate is not defined")
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "proxies to Rails logger" do
|
|
56
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
57
|
-
Humid.create_context
|
|
58
|
-
expect(Humid.logger).to receive(:info).with("hello")
|
|
59
|
-
|
|
60
|
-
Humid.context.eval("console.info('hello')")
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
describe "context" do
|
|
65
|
-
it "returns the created context" do
|
|
66
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
67
|
-
|
|
68
|
-
Humid.create_context
|
|
69
|
-
|
|
70
|
-
expect(Humid.context).to be_kind_of(MiniRacer::Context)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
context "when the js is stale and env is NOT dev`" do
|
|
74
|
-
it "does not recompile the JS" do
|
|
75
|
-
allow(Webpacker).to receive_message_chain("env.development?") { false }
|
|
76
|
-
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
|
77
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
78
|
-
|
|
79
|
-
Humid.create_context
|
|
80
|
-
prev_context = Humid.context
|
|
81
|
-
expect(prev_context).to be_kind_of(MiniRacer::Context)
|
|
82
|
-
|
|
83
|
-
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
|
84
|
-
|
|
85
|
-
next_context = Humid.context
|
|
86
|
-
|
|
87
|
-
expect(prev_context).to eql(next_context)
|
|
88
|
-
expect(next_context).to be_kind_of(MiniRacer::Context)
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
context "when the env is development" do
|
|
93
|
-
it "compiles the JS when stale" do
|
|
94
|
-
allow(Webpacker).to receive_message_chain("env.development?") { true }
|
|
95
|
-
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
|
96
|
-
allow(Webpacker).to receive_message_chain("compiler.compile")
|
|
97
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
98
|
-
|
|
99
|
-
Humid.create_context
|
|
100
|
-
prev_context = Humid.context
|
|
101
|
-
expect(prev_context).to be_kind_of(MiniRacer::Context)
|
|
102
|
-
|
|
103
|
-
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
|
104
|
-
# This simulates a changing file
|
|
105
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple_changed.js" }
|
|
106
|
-
|
|
107
|
-
next_context = Humid.context
|
|
108
|
-
|
|
109
|
-
expect(prev_context).to_not eql(next_context)
|
|
110
|
-
expect(next_context).to be_kind_of(MiniRacer::Context)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
it "creates a new context when webpack-devserver already handled JS staleness" do
|
|
114
|
-
allow(Webpacker).to receive_message_chain("env.development?") { true }
|
|
115
|
-
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
|
116
|
-
allow(Webpacker).to receive_message_chain("compiler.compile")
|
|
117
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
118
|
-
|
|
119
|
-
Humid.create_context
|
|
120
|
-
prev_context = Humid.context
|
|
121
|
-
expect(Humid.render).to eql("hello")
|
|
122
|
-
expect(prev_context).to be_kind_of(MiniRacer::Context)
|
|
123
|
-
|
|
124
|
-
allow(Webpacker).to receive_message_chain("compiler.stale?") { false }
|
|
125
|
-
# This simulates a changing file
|
|
126
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple_changed.js" }
|
|
127
|
-
|
|
128
|
-
next_context = Humid.context
|
|
129
|
-
|
|
130
|
-
expect(prev_context).to_not eql(next_context)
|
|
131
|
-
expect(next_context).to be_kind_of(MiniRacer::Context)
|
|
132
|
-
expect(Humid.render).to eql("hello changed")
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
describe "render" do
|
|
138
|
-
it "returns a js output" do
|
|
139
|
-
allow(Humid.config).to receive("server_rendering_pack") { "simple.js" }
|
|
140
|
-
Humid.create_context
|
|
141
|
-
|
|
142
|
-
expect(Humid.render).to eql("hello")
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
it "applys args to the func" do
|
|
146
|
-
allow(Humid.config).to receive("server_rendering_pack") { "args.js" }
|
|
147
|
-
Humid.create_context
|
|
148
|
-
|
|
149
|
-
args = ["a", 1, 2, [], {}]
|
|
150
|
-
|
|
151
|
-
expect(Humid.render(*args)).to eql({"0" => "a", "1" => 1, "2" => 2, "3" => [], "4" => {}})
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
it "can use source maps to see errors" do
|
|
155
|
-
allow(Humid.config).to receive("server_rendering_pack") { "reporting.js" }
|
|
156
|
-
allow(Humid.config).to receive("use_source_map") { true }
|
|
157
|
-
|
|
158
|
-
Humid.create_context
|
|
159
|
-
|
|
160
|
-
expect {
|
|
161
|
-
Humid.render
|
|
162
|
-
}.to raise_error { |error|
|
|
163
|
-
expect(error).to be_a(Humid::RenderError)
|
|
164
|
-
message = <<~MSG
|
|
165
|
-
Error: ^^ Look! These stack traces map to the actual source code :)
|
|
166
|
-
JavaScript at throwSomeError (/webpack:/app/javascript/packs/components/error-causing-component.js:2:1)
|
|
167
|
-
JavaScript at ErrorCausingComponent (/webpack:/app/javascript/packs/components/error-causing-component.js:8:1)
|
|
168
|
-
JavaScript at /webpack:/app/javascript/packs/reporting.js:18:1
|
|
169
|
-
MSG
|
|
170
|
-
|
|
171
|
-
expect(error.message).to eql message.strip
|
|
172
|
-
}
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
it "siliences render errors to the log" do
|
|
176
|
-
allow(Humid.config).to receive("server_rendering_pack") { "reporting.js" }
|
|
177
|
-
allow(Humid.config).to receive("raise_render_errors") { false }
|
|
178
|
-
allow(Humid.config).to receive("use_source_map") { true }
|
|
179
|
-
|
|
180
|
-
Humid.create_context
|
|
181
|
-
|
|
182
|
-
expect(Humid.logger).to receive(:error)
|
|
183
|
-
output = Humid.render
|
|
184
|
-
|
|
185
|
-
expect(output).to eql("")
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
end
|