humid 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +179 -0
- data/lib/humid.rb +109 -0
- data/lib/humid/controller_runtime.rb +41 -0
- data/lib/humid/log_subscriber.rb +22 -0
- data/lib/humid/version.rb +3 -0
- data/spec/controller_runtime_spec.rb +79 -0
- data/spec/log_subscriber_spec.rb +54 -0
- data/spec/render_spec.rb +139 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 331e268f4bfc9f9b46e4246a9fb1af56245616bedecfb13a9b220040fca74636
|
4
|
+
data.tar.gz: 87631778cddbd5511202a0a3aaaa54fb6827b8aee8bdae29f80297ee6764cd55
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5161834e3f6b0a8d6cb9e991965df392491e204373c0ec54773cf114f8c489be88f435a5d6ba90c226dc6a698ea053ca3ccaf64581cb01399272057ecb600990
|
7
|
+
data.tar.gz: a545a0ffb5c7f1dfdf333bb960566a28fb355fd3dfc60ede7ed88f3210f507ca21e7b389138c07b2a773903110df66b7e60df844a57815c0a87fb624a15ee44c
|
data/README.md
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
# Humid
|
2
|
+
|
3
|
+
Humid is a lightweight helper that leans on [mini_racer] and [webpacker] to
|
4
|
+
generate Server Side Rendered (SSR) pages from your javascript application.
|
5
|
+
|
6
|
+
[![Build
|
7
|
+
Status](https://circleci.com/gh/thoughtbot/humid.svg?style=shield)](https://circleci.com/gh/thoughtbot/humid)
|
8
|
+
|
9
|
+
## Caution
|
10
|
+
|
11
|
+
This project is in its early phases of development. Its interface,
|
12
|
+
behavior, and name are likely to change drastically before a major version
|
13
|
+
release.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add Humid to your Gemfile.
|
18
|
+
|
19
|
+
```
|
20
|
+
gem 'humid'
|
21
|
+
```
|
22
|
+
|
23
|
+
For source-map support, also add
|
24
|
+
|
25
|
+
```
|
26
|
+
yarn add source-map-support
|
27
|
+
```
|
28
|
+
|
29
|
+
|
30
|
+
## Configuration
|
31
|
+
|
32
|
+
Add an initializer to configure
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
Humid.configure do |config|
|
36
|
+
# name of your webpacker pack. Defaults to "server_rendering.js"
|
37
|
+
config.server_rendering_source = "server_rendering.js"
|
38
|
+
|
39
|
+
# name of your webpacker pack source map. Defaults to `nil`
|
40
|
+
config.server_rendering_source_map = "server_rendering.js.map"
|
41
|
+
|
42
|
+
# The logger instance. Defaults to `Logger.new(STDOUT)`
|
43
|
+
# `console.log` and friends (`warn`, `error`) are delegated to
|
44
|
+
# the respective logger levels on the ruby side.
|
45
|
+
config.logger = Rails.logger
|
46
|
+
|
47
|
+
# context_options. Options passed to mini_racer. Defaults to
|
48
|
+
# config.context_options = {
|
49
|
+
# timeout: 1000,
|
50
|
+
# ensure_gc_after_idle: 2000
|
51
|
+
# }
|
52
|
+
end
|
53
|
+
|
54
|
+
# If using puma in single mode
|
55
|
+
# Humid.create_context
|
56
|
+
```
|
57
|
+
|
58
|
+
If you'd like support for source map support, you will need to
|
59
|
+
1. Ensure `config.server_rendering_source_map` has a value
|
60
|
+
2. Add the following to your `server_rendering.js` pack.
|
61
|
+
|
62
|
+
```javascript
|
63
|
+
require("source-map-support").install({
|
64
|
+
retrieveSourceMap: filename => {
|
65
|
+
return {
|
66
|
+
url: filename,
|
67
|
+
map: readSourceMap(filename)
|
68
|
+
};
|
69
|
+
}
|
70
|
+
});
|
71
|
+
```
|
72
|
+
|
73
|
+
## The mini_racer environment.
|
74
|
+
|
75
|
+
The following functions are **not** available in the mini_racer environment
|
76
|
+
|
77
|
+
- `setTimeout`
|
78
|
+
- `clearTimeout`
|
79
|
+
- `setInterval`
|
80
|
+
- `clearInterval`
|
81
|
+
- `setImmediate`
|
82
|
+
- `clearImmediate`
|
83
|
+
|
84
|
+
### `console.log`
|
85
|
+
|
86
|
+
`console.log` and friends (`info`, `error`, `warn`) are delegated to the
|
87
|
+
respective methods on the configured logger.
|
88
|
+
|
89
|
+
### Webpacker
|
90
|
+
You may need webpacker to create aliases for server friendly libraries that can
|
91
|
+
not detect the `mini_racer` environment.
|
92
|
+
|
93
|
+
```diff
|
94
|
+
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
|
95
|
+
|
96
|
+
const environment = require('./environment')
|
97
|
+
+const path = require('path')
|
98
|
+
+const ConfigObject = require('@rails/webpacker/package/config_types/config
|
99
|
+
|
100
|
+
-module.exports = environment.toWebpackConfig()
|
101
|
+
+const webConfig = environment.toWebpackConfig()
|
102
|
+
+const ssrConfig = new ConfigObject(webConfig.toObject())
|
103
|
+
+
|
104
|
+
+ssrConfig.delete('entry')
|
105
|
+
+ssrConfig.merge({
|
106
|
+
+ entry: {
|
107
|
+
+ server_rendering: webConfig.entry.server_rendering
|
108
|
+
+ },
|
109
|
+
+ resolve: {
|
110
|
+
+ alias: {
|
111
|
+
+ 'html-dom-parser': path.resolve(__dirname, '../../node_modules/html-dom-parser/lib/html-to-dom-server')
|
112
|
+
+ }
|
113
|
+
+ }
|
114
|
+
+})
|
115
|
+
+
|
116
|
+
+delete webConfig.entry.server_rendering
|
117
|
+
+module.exports = [ssrConfig, webConfig]
|
118
|
+
```
|
119
|
+
|
120
|
+
## Usage
|
121
|
+
|
122
|
+
Pass your HTML render function to `setHumidRenderer`
|
123
|
+
|
124
|
+
```javascript
|
125
|
+
setHumidRenderer((json) => {
|
126
|
+
const initialState = JSON.parse(json)
|
127
|
+
return ReactDOMServer.renderToString(
|
128
|
+
<Application initialPage={initialState}/>
|
129
|
+
)
|
130
|
+
})
|
131
|
+
```
|
132
|
+
|
133
|
+
And finally call `render` from ERB.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
<%= Humid.render(initial_state) %>
|
137
|
+
```
|
138
|
+
|
139
|
+
### Puma
|
140
|
+
|
141
|
+
`mini_racer` is thread safe, but not fork safe. To use with web servers that
|
142
|
+
employ forking, use `Humid.create_context` only on forked processes.
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
# Puma
|
146
|
+
on_worker_boot do
|
147
|
+
Humid.create_context
|
148
|
+
end
|
149
|
+
|
150
|
+
on_worker_shutdown do
|
151
|
+
Humid.dispose
|
152
|
+
end
|
153
|
+
```
|
154
|
+
|
155
|
+
## Contributing
|
156
|
+
|
157
|
+
Please see [CONTRIBUTING.md](/CONTRIBUTING.md).
|
158
|
+
|
159
|
+
## License
|
160
|
+
|
161
|
+
Humid is Copyright © 2021-2021 Johny Ho.
|
162
|
+
It is free software, and may be redistributed under the terms specified in the
|
163
|
+
[LICENSE](/LICENSE.md) file.
|
164
|
+
|
165
|
+
## About thoughtbot
|
166
|
+
|
167
|
+
![thoughtbot](https://thoughtbot.com/brand_assets/93:44.svg)
|
168
|
+
|
169
|
+
Humid is maintained and funded by thoughtbot, inc.
|
170
|
+
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
171
|
+
|
172
|
+
We love open source software!
|
173
|
+
See [our other projects][community] or
|
174
|
+
[hire us][hire] to design, develop, and grow your product.
|
175
|
+
|
176
|
+
[community]: https://thoughtbot.com/community?utm_source=github
|
177
|
+
[hire]: https://thoughtbot.com?utm_source=github
|
178
|
+
[mini_racer]: https://github.com/rubyjs/mini_racer
|
179
|
+
[webpacker]: https://github.com/rails/webpacker
|
data/lib/humid.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require "mini_racer"
|
2
|
+
require "logger"
|
3
|
+
require "webpacker"
|
4
|
+
require "active_support"
|
5
|
+
require "active_support/core_ext"
|
6
|
+
require "humid/log_subscriber"
|
7
|
+
require "humid/controller_runtime"
|
8
|
+
require "humid/version"
|
9
|
+
|
10
|
+
module Humid
|
11
|
+
extend self
|
12
|
+
include ActiveSupport::Configurable
|
13
|
+
|
14
|
+
config_accessor :server_rendering_file do
|
15
|
+
"server_rendering.js"
|
16
|
+
end
|
17
|
+
|
18
|
+
config_accessor :server_rendering_source_map do
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
config_accessor :logger do
|
23
|
+
Logger.new(STDOUT)
|
24
|
+
end
|
25
|
+
|
26
|
+
config_accessor :context_options do
|
27
|
+
{
|
28
|
+
timeout: 1000,
|
29
|
+
ensure_gc_after_idle: 2000
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_functions
|
34
|
+
<<~JS
|
35
|
+
delete this.setTimeout;
|
36
|
+
delete this.setInterval;
|
37
|
+
delete this.clearTimeout;
|
38
|
+
delete this.clearInterval;
|
39
|
+
delete this.setImmediate;
|
40
|
+
delete this.clearImmediate;
|
41
|
+
JS
|
42
|
+
end
|
43
|
+
|
44
|
+
def logger
|
45
|
+
config.logger
|
46
|
+
end
|
47
|
+
|
48
|
+
def renderer
|
49
|
+
<<~JS
|
50
|
+
var __renderer;
|
51
|
+
function setHumidRenderer(fn) {
|
52
|
+
__renderer = fn;
|
53
|
+
}
|
54
|
+
JS
|
55
|
+
end
|
56
|
+
|
57
|
+
def context
|
58
|
+
if @@context && Webpacker.env.development? && Webpacker.compiler.stale?
|
59
|
+
Webpacker.compiler.compile
|
60
|
+
dispose
|
61
|
+
create_context
|
62
|
+
else
|
63
|
+
@@context
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def dispose
|
68
|
+
if @@context
|
69
|
+
@@context.dispose
|
70
|
+
@@context = nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_context
|
75
|
+
ctx = MiniRacer::Context.new(config.context_options)
|
76
|
+
ctx.attach("console.log", proc { |err| logger.debug(err.to_s) })
|
77
|
+
ctx.attach("console.info", proc { |err| logger.info(err.to_s) })
|
78
|
+
ctx.attach("console.error", proc { |err| logger.error(err.to_s) })
|
79
|
+
ctx.attach("console.warn", proc { |err| logger.warn(err.to_s) })
|
80
|
+
|
81
|
+
js = ""
|
82
|
+
js << remove_functions
|
83
|
+
js << renderer
|
84
|
+
ctx.eval(js)
|
85
|
+
|
86
|
+
public_path = Webpacker.config.public_path
|
87
|
+
asset_path = public_path.join(Webpacker.manifest.lookup(config.server_rendering_file)[1..-1])
|
88
|
+
filename = File.basename(asset_path.to_s)
|
89
|
+
ctx.eval(File.read(asset_path), filename: filename)
|
90
|
+
|
91
|
+
if config.server_rendering_source_map
|
92
|
+
map_path = public_path.join(Webpacker.manifest.lookup(config.server_rendering_source_map)[1..-1])
|
93
|
+
ctx.attach("readSourceMap", proc { File.read(map_path) })
|
94
|
+
end
|
95
|
+
|
96
|
+
@@context = ctx
|
97
|
+
end
|
98
|
+
|
99
|
+
def render(*args)
|
100
|
+
ActiveSupport::Notifications.instrument("render.humid") do
|
101
|
+
@@context.call("__renderer", *args)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
Humid::LogSubscriber.attach_to :humid
|
107
|
+
ActiveSupport.on_load(:action_controller) do
|
108
|
+
include Humid::ControllerRuntime
|
109
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Humid
|
2
|
+
module ControllerRuntime
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def log_process_action(payload)
|
7
|
+
messages, humid_runtime = super, payload[:humid_runtime]
|
8
|
+
messages << ("Humid SSR: %.1fms" % humid_runtime.to_f) if humid_runtime
|
9
|
+
messages
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_internal :humid_runtime
|
16
|
+
|
17
|
+
# Reset the runtime before each action.
|
18
|
+
def process_action(action, *args)
|
19
|
+
Humid::LogSubscriber.reset_runtime
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def cleanup_view_runtime
|
24
|
+
if logger&.info?
|
25
|
+
humid_rt_before_render = Humid::LogSubscriber.reset_runtime
|
26
|
+
self.humid_runtime = (humid_runtime || 0) + humid_rt_before_render
|
27
|
+
runtime = super
|
28
|
+
humid_rt_after_render = Humid::LogSubscriber.reset_runtime
|
29
|
+
self.humid_runtime += humid_rt_after_render
|
30
|
+
runtime - humid_rt_after_render
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def append_info_to_payload(payload)
|
37
|
+
super
|
38
|
+
payload[:humid_runtime] = (humid_runtime || 0) + Humid::LogSubscriber.reset_runtime
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Humid
|
2
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
3
|
+
thread_cattr_accessor :humid_runtime
|
4
|
+
|
5
|
+
def self.runtime=(value)
|
6
|
+
self.humid_runtime = value
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.runtime
|
10
|
+
self.humid_runtime ||= 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.reset_runtime
|
14
|
+
rt, self.runtime = runtime, 0
|
15
|
+
rt
|
16
|
+
end
|
17
|
+
|
18
|
+
def render(event)
|
19
|
+
self.class.runtime += event.duration
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,79 @@
|
|
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
|
@@ -0,0 +1,54 @@
|
|
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_file") { "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
ADDED
@@ -0,0 +1,139 @@
|
|
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_file") { "simple.js" }
|
18
|
+
Humid.create_context
|
19
|
+
|
20
|
+
expect(Humid.context).to be_kind_of(MiniRacer::Context)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "does not have timeouts, immediates, and intervals" do
|
24
|
+
allow(Humid.config).to receive("server_rendering_file") { "simple.js" }
|
25
|
+
|
26
|
+
Humid.create_context
|
27
|
+
|
28
|
+
expect {
|
29
|
+
Humid.context.eval("setTimeout()")
|
30
|
+
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: setTimeout is not defined")
|
31
|
+
expect {
|
32
|
+
Humid.context.eval("setInterval()")
|
33
|
+
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: setInterval is not defined")
|
34
|
+
expect {
|
35
|
+
Humid.context.eval("clearTimeout()")
|
36
|
+
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: clearTimeout is not defined")
|
37
|
+
expect {
|
38
|
+
Humid.context.eval("setImmediate()")
|
39
|
+
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: setImmediate is not defined")
|
40
|
+
expect {
|
41
|
+
Humid.context.eval("clearImmediate()")
|
42
|
+
}.to raise_error(MiniRacer::RuntimeError, "ReferenceError: clearImmediate is not defined")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "proxies to Rails logger" do
|
46
|
+
allow(Humid.config).to receive("server_rendering_file") { "simple.js" }
|
47
|
+
Humid.create_context
|
48
|
+
expect(Humid.logger).to receive(:info).with("hello")
|
49
|
+
|
50
|
+
Humid.context.eval("console.info('hello')")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "context" do
|
55
|
+
it "returns the created context" do
|
56
|
+
allow(Humid.config).to receive("server_rendering_file") { "simple.js" }
|
57
|
+
|
58
|
+
Humid.create_context
|
59
|
+
|
60
|
+
expect(Humid.context).to be_kind_of(MiniRacer::Context)
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when the js is stale and env is NOT dev`" do
|
64
|
+
it "does not recompile the JS" do
|
65
|
+
allow(Webpacker).to receive_message_chain("env.development?") { false }
|
66
|
+
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
67
|
+
allow(Humid.config).to receive("server_rendering_file") { "simple.js" }
|
68
|
+
|
69
|
+
Humid.create_context
|
70
|
+
prev_context = Humid.context
|
71
|
+
expect(prev_context).to be_kind_of(MiniRacer::Context)
|
72
|
+
|
73
|
+
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
74
|
+
|
75
|
+
next_context = Humid.context
|
76
|
+
|
77
|
+
expect(prev_context).to eql(next_context)
|
78
|
+
expect(next_context).to be_kind_of(MiniRacer::Context)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when the js is stale and env is development" do
|
83
|
+
it "compiles the JS" do
|
84
|
+
allow(Webpacker).to receive_message_chain("env.development?") { true }
|
85
|
+
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
86
|
+
allow(Webpacker).to receive_message_chain("compiler.compile")
|
87
|
+
allow(Humid.config).to receive("server_rendering_file") { "simple.js" }
|
88
|
+
|
89
|
+
Humid.create_context
|
90
|
+
prev_context = Humid.context
|
91
|
+
expect(prev_context).to be_kind_of(MiniRacer::Context)
|
92
|
+
|
93
|
+
allow(Webpacker).to receive_message_chain("compiler.stale?") { true }
|
94
|
+
|
95
|
+
next_context = Humid.context
|
96
|
+
|
97
|
+
expect(prev_context).to_not eql(next_context)
|
98
|
+
expect(next_context).to be_kind_of(MiniRacer::Context)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "render" do
|
104
|
+
it "returns a js output" do
|
105
|
+
allow(Humid.config).to receive("server_rendering_file") { "simple.js" }
|
106
|
+
Humid.create_context
|
107
|
+
|
108
|
+
expect(Humid.render).to eql("hello")
|
109
|
+
end
|
110
|
+
|
111
|
+
it "applys args to the func" do
|
112
|
+
allow(Humid.config).to receive("server_rendering_file") { "args.js" }
|
113
|
+
Humid.create_context
|
114
|
+
|
115
|
+
args = ["a", 1, 2, [], {}]
|
116
|
+
|
117
|
+
expect(Humid.render(*args)).to eql({"0" => "a", "1" => 1, "2" => 2, "3" => [], "4" => {}})
|
118
|
+
end
|
119
|
+
|
120
|
+
it "can use source maps to see errors" do
|
121
|
+
allow(Humid.config).to receive("server_rendering_file") { "reporting.js" }
|
122
|
+
allow(Humid.config).to receive("server_rendering_source_map") {
|
123
|
+
"reporting.js.map"
|
124
|
+
}
|
125
|
+
|
126
|
+
Humid.create_context
|
127
|
+
|
128
|
+
expect {
|
129
|
+
Humid.render
|
130
|
+
}.to raise_error { |error|
|
131
|
+
expect(error).to be_a(MiniRacer::RuntimeError)
|
132
|
+
expect(error.message).to eql("Error: ^^ Look! These stack traces map to the actual source code :)")
|
133
|
+
expect(error.backtrace[0]).to eql("JavaScript at throwSomeError (/webpack:/app/javascript/packs/components/error-causing-component.js:2:1)")
|
134
|
+
expect(error.backtrace[1]).to eql("JavaScript at ErrorCausingComponent (/webpack:/app/javascript/packs/components/error-causing-component.js:8:1)")
|
135
|
+
expect(error.backtrace[2]).to eql("JavaScript at /webpack:/app/javascript/packs/reporting.js:18:1")
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: humid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Johny Ho
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-07-10 00:00:00.000000000 Z
|
12
|
+
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
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mini_racer
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.4'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '6.1'
|
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
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '12.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
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
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '9.0'
|
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.1'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '6.1'
|
111
|
+
description: Javascript SSR rendering for Rails
|
112
|
+
email: jho406@gmail.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- README.md
|
118
|
+
- lib/humid.rb
|
119
|
+
- lib/humid/controller_runtime.rb
|
120
|
+
- lib/humid/log_subscriber.rb
|
121
|
+
- lib/humid/version.rb
|
122
|
+
- spec/controller_runtime_spec.rb
|
123
|
+
- spec/log_subscriber_spec.rb
|
124
|
+
- spec/render_spec.rb
|
125
|
+
homepage: https://github.com/thoughtbot/humid/
|
126
|
+
licenses:
|
127
|
+
- MIT
|
128
|
+
metadata: {}
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubygems_version: 3.1.2
|
145
|
+
signing_key:
|
146
|
+
specification_version: 4
|
147
|
+
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
|