isorun 0.1.7-x86_64-linux → 0.1.8-x86_64-linux
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/Rakefile +2 -2
- data/app/helpers/isorun/app_helper.rb +20 -6
- data/ext/isorun/Cargo.toml +10 -10
- data/ext/isorun/src/isorun/context.rs +13 -7
- data/ext/isorun/src/isorun/function.rs +5 -5
- data/ext/isorun/src/isorun/module.rs +5 -4
- data/ext/isorun/src/isorun/utils.rs +66 -0
- data/ext/isorun/src/js/worker.rs +1 -0
- data/ext/isorun/src/lib.rs +11 -0
- data/lib/isorun/2.7/isorun.so +0 -0
- data/lib/isorun/3.0/isorun.so +0 -0
- data/lib/isorun/3.1/isorun.so +0 -0
- data/lib/isorun/context.rb +49 -5
- data/lib/isorun/engine.rb +0 -1
- data/lib/isorun/version.rb +1 -1
- metadata +51 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b7fbac84c4db38f693ab09b2e841b9c8ef840cfeb50d212d1123d147e6bc8ff
|
4
|
+
data.tar.gz: bfa169c65285f23465e5016eb8b0e5a8700cad33e966ecaaa8e7bf101ed15bb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 426b9460bfda7af56298427b522808a0816506799895ea4f6adf57836ad259622e056b040d860e4c568a7a01d749496d65255aa45014fe02276b3ba27e32f7c6
|
7
|
+
data.tar.gz: 85d72159f954e240c8d68d1c415e5f07e751df504a23310f4305eba9f47c5d90d44b61ed42c92c536fe3b2b40d0ea85e9deba2e4b9811bf150dc67ed83453712
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require "rake/testtask"
|
|
6
6
|
require "rake/extensiontask"
|
7
7
|
require "rb_sys"
|
8
8
|
|
9
|
-
cross_rubies = %w[3.1.0 3.0.0 2.7.0]
|
9
|
+
cross_rubies = %w[3.2.0 3.1.0 3.0.0 2.7.0]
|
10
10
|
cross_platforms = %w[
|
11
11
|
arm64-darwin
|
12
12
|
x86_64-darwin
|
@@ -72,7 +72,7 @@ begin
|
|
72
72
|
|
73
73
|
YARD::Rake::YardocTask.new
|
74
74
|
|
75
|
-
task docs
|
75
|
+
task :docs do
|
76
76
|
`yard server --reload`
|
77
77
|
end
|
78
78
|
rescue LoadError
|
@@ -2,10 +2,27 @@
|
|
2
2
|
|
3
3
|
module Isorun
|
4
4
|
module AppHelper
|
5
|
+
# The isorun_app helper is the most convenient way to server-side render
|
6
|
+
# a JavaScript application, including state extraction and automatic
|
7
|
+
# rehydration. The helper tries to render the application and will also
|
8
|
+
# inject the client-side code immediately after the rendered result.
|
9
|
+
#
|
10
|
+
# @example Renders a JavaScript application
|
11
|
+
# <html>
|
12
|
+
# <body>
|
13
|
+
# <%= isorun_app("my_app") %>
|
14
|
+
# </body>
|
15
|
+
# </html>
|
16
|
+
#
|
17
|
+
# @param id [String] An ID representing both, the asset bundle, and by
|
18
|
+
# convention, the target node (e.g. `<div id="my_app">`)
|
19
|
+
# @return [String]
|
5
20
|
def isorun_app(id) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
21
|
+
ActiveSupport::Notifications.instrument "start.render.isorun", { ts: Time.current }
|
22
|
+
|
6
23
|
module_path = Isorun.config.module_resolver.call(id)
|
7
24
|
|
8
|
-
ssr_html = Isorun::Context.create do |context|
|
25
|
+
ssr_html = Isorun::Context.create(receiver: Isorun.config.receiver) do |context|
|
9
26
|
render_context = { environment: Rails.env.to_s }
|
10
27
|
render_function = context.import.from(module_path)
|
11
28
|
|
@@ -17,13 +34,10 @@ module Isorun
|
|
17
34
|
return ""
|
18
35
|
end
|
19
36
|
|
20
|
-
# set receiver to allow calling into Ruby from JavaScript
|
21
|
-
context.receiver = Isorun.config.receiver
|
22
|
-
|
23
37
|
html = render_function.call(render_context)
|
24
38
|
|
25
|
-
|
26
|
-
|
39
|
+
ActiveSupport::Notifications.instrument "finish.render.isorun", { ts: Time.current }
|
40
|
+
ActiveSupport::Notifications.instrument "stats.isorun", Isorun.stats
|
27
41
|
|
28
42
|
html
|
29
43
|
end
|
data/ext/isorun/Cargo.toml
CHANGED
@@ -1,26 +1,26 @@
|
|
1
1
|
[package]
|
2
2
|
name = "isorun"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.8"
|
4
4
|
edition = "2021"
|
5
5
|
authors = ["Hannes Moser <box@hannesmoser.at>"]
|
6
6
|
homepage = "https://github.com/eliias/isorun"
|
7
7
|
repository = "https://github.com/eliias/isorun"
|
8
8
|
|
9
9
|
[dependencies]
|
10
|
-
deno_console = "0.
|
11
|
-
deno_core = "0.
|
12
|
-
deno_fetch = "0.
|
13
|
-
deno_runtime = "0.
|
14
|
-
deno_url = "0.
|
15
|
-
deno_web = "0.
|
16
|
-
deno_webidl = "0.
|
10
|
+
deno_console = "0.83.0"
|
11
|
+
deno_core = "0.165.0"
|
12
|
+
deno_fetch = "0.107.0"
|
13
|
+
deno_runtime = "0.91.0"
|
14
|
+
deno_url = "0.83.0"
|
15
|
+
deno_web = "0.114.0"
|
16
|
+
deno_webidl = "0.83.0"
|
17
17
|
lazy_static = "1.4.0"
|
18
|
-
magnus = { git = "https://github.com/eliias/magnus", rev = "
|
18
|
+
magnus = { git = "https://github.com/eliias/magnus", rev = "5220756ca0ab4f2bc32d38310c26f7dda2be9bd6" }
|
19
19
|
tokio = { version = "1.21.1", features = ["full"] }
|
20
20
|
v8 = "0.60.0"
|
21
21
|
|
22
22
|
[dev-dependencies]
|
23
|
-
magnus = { git = "https://github.com/eliias/magnus", rev = "
|
23
|
+
magnus = { git = "https://github.com/eliias/magnus", rev = "5220756ca0ab4f2bc32d38310c26f7dda2be9bd6", features = ["embed"] }
|
24
24
|
|
25
25
|
[lib]
|
26
26
|
name = "isorun"
|
@@ -3,7 +3,7 @@ use crate::js::module::Module;
|
|
3
3
|
use crate::js::worker::WORKER;
|
4
4
|
use deno_core::JsRealm;
|
5
5
|
use magnus::block::Proc;
|
6
|
-
use magnus::Error;
|
6
|
+
use magnus::{exception, Error};
|
7
7
|
use std::cell::RefCell;
|
8
8
|
use std::rc::Rc;
|
9
9
|
|
@@ -19,7 +19,10 @@ impl Context {
|
|
19
19
|
.with(|worker| worker.create_realm())
|
20
20
|
.map(|realm| Context(Rc::new(RefCell::from(realm))))
|
21
21
|
.map_err(|_error| {
|
22
|
-
Error::
|
22
|
+
Error::new(
|
23
|
+
exception::runtime_error(),
|
24
|
+
"cannot create JavaScript context",
|
25
|
+
)
|
23
26
|
})
|
24
27
|
}
|
25
28
|
|
@@ -41,11 +44,14 @@ impl Context {
|
|
41
44
|
})
|
42
45
|
.map(|module| isorun::Module(RefCell::from(module)))
|
43
46
|
.map_err(|error| {
|
44
|
-
Error::
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
47
|
+
Error::new(
|
48
|
+
exception::runtime_error(),
|
49
|
+
format!(
|
50
|
+
"cannot load module: `{}`: {}",
|
51
|
+
path.as_str(),
|
52
|
+
error
|
53
|
+
),
|
54
|
+
)
|
49
55
|
})
|
50
56
|
}
|
51
57
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
use crate::js;
|
2
2
|
use crate::js::worker::WORKER;
|
3
|
-
use magnus::Error;
|
3
|
+
use magnus::{exception, Error};
|
4
4
|
use std::cell::RefCell;
|
5
5
|
use std::ops::Deref;
|
6
6
|
use v8::{Global, Value};
|
@@ -28,10 +28,10 @@ impl Function {
|
|
28
28
|
|
29
29
|
let result =
|
30
30
|
self.0.borrow().call(v8_args.as_slice()).map_err(|error| {
|
31
|
-
Error::
|
32
|
-
|
33
|
-
error
|
34
|
-
)
|
31
|
+
Error::new(
|
32
|
+
exception::runtime_error(),
|
33
|
+
format!("cannot call function: {}", error),
|
34
|
+
)
|
35
35
|
});
|
36
36
|
|
37
37
|
result
|
@@ -1,6 +1,6 @@
|
|
1
1
|
use crate::isorun::function::Function;
|
2
2
|
use crate::js;
|
3
|
-
use magnus::Error;
|
3
|
+
use magnus::{exception, Error};
|
4
4
|
use std::cell::RefCell;
|
5
5
|
|
6
6
|
#[magnus::wrap(class = "Isorun::Module")]
|
@@ -19,9 +19,10 @@ impl Module {
|
|
19
19
|
export_name: String,
|
20
20
|
) -> Result<magnus::Value, Error> {
|
21
21
|
let module = self.0.borrow();
|
22
|
-
let module_item =
|
23
|
-
.import(export_name.as_str())
|
24
|
-
|
22
|
+
let module_item =
|
23
|
+
module.import(export_name.as_str()).map_err(|error| {
|
24
|
+
Error::new(exception::runtime_error(), format!("{}", error))
|
25
|
+
})?;
|
25
26
|
|
26
27
|
match module_item {
|
27
28
|
js::module_item::ModuleItem::Value(v) => Ok(v.to_ruby().unwrap()),
|
@@ -1,3 +1,4 @@
|
|
1
|
+
use crate::js::worker::WORKER;
|
1
2
|
use deno_core::error::AnyError;
|
2
3
|
use magnus::r_hash::ForEach;
|
3
4
|
use magnus::value::{Qfalse, Qtrue};
|
@@ -5,6 +6,7 @@ use magnus::{
|
|
5
6
|
Integer, RArray, RFloat, RHash, RString, RStruct, Symbol, Value, QFALSE,
|
6
7
|
QNIL, QTRUE,
|
7
8
|
};
|
9
|
+
use std::collections::HashMap;
|
8
10
|
use v8::{Array, GetPropertyNamesArgs, Global, HandleScope, Local, Object};
|
9
11
|
|
10
12
|
pub fn convert_v8_to_ruby(
|
@@ -157,3 +159,67 @@ pub fn convert_ruby_to_v8<'s>(
|
|
157
159
|
|
158
160
|
Ok(v8::null(scope).into())
|
159
161
|
}
|
162
|
+
|
163
|
+
pub(crate) fn low_memory_notification() {
|
164
|
+
WORKER.with(|worker| {
|
165
|
+
let mut worker = worker.worker.borrow_mut();
|
166
|
+
worker.js_runtime.v8_isolate().low_memory_notification();
|
167
|
+
});
|
168
|
+
}
|
169
|
+
|
170
|
+
pub(crate) fn stats() -> RHash {
|
171
|
+
WORKER.with(|worker| {
|
172
|
+
let mut worker = worker.worker.borrow_mut();
|
173
|
+
|
174
|
+
let heap_stats = &mut Default::default();
|
175
|
+
worker
|
176
|
+
.js_runtime
|
177
|
+
.v8_isolate()
|
178
|
+
.get_heap_statistics(heap_stats);
|
179
|
+
|
180
|
+
let current_thread = std::thread::current();
|
181
|
+
let thread = HashMap::from([(
|
182
|
+
"thread_id",
|
183
|
+
format!("{:?}", current_thread.id()),
|
184
|
+
)]);
|
185
|
+
|
186
|
+
let heap = HashMap::from([
|
187
|
+
("external_memory", heap_stats.external_memory()),
|
188
|
+
("heap_size_limit", heap_stats.heap_size_limit()),
|
189
|
+
("malloced_memory", heap_stats.malloced_memory()),
|
190
|
+
(
|
191
|
+
"number_of_detached_contexts",
|
192
|
+
heap_stats.number_of_detached_contexts(),
|
193
|
+
),
|
194
|
+
(
|
195
|
+
"number_of_native_contexts",
|
196
|
+
heap_stats.number_of_native_contexts(),
|
197
|
+
),
|
198
|
+
("peak_malloced_memory", heap_stats.peak_malloced_memory()),
|
199
|
+
("total_available_size", heap_stats.total_available_size()),
|
200
|
+
(
|
201
|
+
"total_global_handles_size",
|
202
|
+
heap_stats.total_global_handles_size(),
|
203
|
+
),
|
204
|
+
("total_heap_size", heap_stats.total_heap_size()),
|
205
|
+
(
|
206
|
+
"total_heap_size_executable",
|
207
|
+
heap_stats.total_heap_size_executable(),
|
208
|
+
),
|
209
|
+
("total_physical_size", heap_stats.total_physical_size()),
|
210
|
+
(
|
211
|
+
"used_global_handles_size",
|
212
|
+
heap_stats.used_global_handles_size(),
|
213
|
+
),
|
214
|
+
("used_heap_size", heap_stats.used_heap_size()),
|
215
|
+
]);
|
216
|
+
|
217
|
+
let h = RHash::new();
|
218
|
+
h.aset("current_thread", RHash::from_iter(thread))
|
219
|
+
.expect("cannot set stats for current_thread");
|
220
|
+
h.aset("heap", RHash::from_iter(heap))
|
221
|
+
.expect("cannot set stats for heap");
|
222
|
+
|
223
|
+
h
|
224
|
+
})
|
225
|
+
}
|
data/ext/isorun/src/js/worker.rs
CHANGED
data/ext/isorun/src/lib.rs
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
use self::isorun::utils::stats;
|
1
2
|
use crate::isorun::context::Context;
|
3
|
+
use crate::isorun::utils::low_memory_notification;
|
2
4
|
use isorun::function::Function;
|
3
5
|
use isorun::module::Module;
|
4
6
|
use magnus::{define_module, function, method, Error, Module as M, Object};
|
@@ -10,6 +12,15 @@ mod js;
|
|
10
12
|
fn init() -> Result<(), Error> {
|
11
13
|
let root = define_module("Isorun").expect("cannot define module: Isorun");
|
12
14
|
|
15
|
+
root.define_module_function("stats", function!(stats, 0))
|
16
|
+
.expect("cannot define module function: stats");
|
17
|
+
|
18
|
+
root.define_module_function(
|
19
|
+
"low_memory_notification",
|
20
|
+
function!(low_memory_notification, 0),
|
21
|
+
)
|
22
|
+
.expect("cannot define module function: low_memory_notification");
|
23
|
+
|
13
24
|
let context = root
|
14
25
|
.define_class("Context", Default::default())
|
15
26
|
.expect("cannot define class: Isorun::Context");
|
data/lib/isorun/2.7/isorun.so
CHANGED
Binary file
|
data/lib/isorun/3.0/isorun.so
CHANGED
Binary file
|
data/lib/isorun/3.1/isorun.so
CHANGED
Binary file
|
data/lib/isorun/context.rb
CHANGED
@@ -10,7 +10,10 @@ module Isorun
|
|
10
10
|
@export_names = export_names
|
11
11
|
end
|
12
12
|
|
13
|
+
# Specify the module to import from
|
13
14
|
def from(module_path)
|
15
|
+
module_path = module_path.to_s if module_path.is_a? Pathname
|
16
|
+
|
14
17
|
mod = load(module_path)
|
15
18
|
imports = export_names.map { |export_name| mod.import(export_name) }
|
16
19
|
return imports.first if imports.size == 1
|
@@ -23,7 +26,7 @@ module Isorun
|
|
23
26
|
CACHE_KEY = "isorun_module_path_mtime"
|
24
27
|
private_constant :CACHE_KEY
|
25
28
|
|
26
|
-
def load(module_path)
|
29
|
+
def load(module_path) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
27
30
|
return context.load(module_path) if Rails.env.production?
|
28
31
|
|
29
32
|
key = module_path.parameterize
|
@@ -41,10 +44,14 @@ module Isorun
|
|
41
44
|
# map to URI scheme to allow adding a timestamp to bust module cache
|
42
45
|
module_path = "file://#{module_path}?t=#{mtime}"
|
43
46
|
|
44
|
-
|
47
|
+
if cache_miss
|
48
|
+
ActiveSupport::Notifications.instrument "load.module.isorun", { path: module_path }
|
49
|
+
return context.load(module_path)
|
50
|
+
end
|
45
51
|
|
46
52
|
Rails.cache.write("#{CACHE_KEY}:#{key}", mtime) if prev_mtime < mtime
|
47
53
|
|
54
|
+
ActiveSupport::Notifications.instrument "load.module.isorun", { path: module_path }
|
48
55
|
context.load(module_path)
|
49
56
|
end
|
50
57
|
end
|
@@ -52,11 +59,30 @@ module Isorun
|
|
52
59
|
private_constant :Import
|
53
60
|
|
54
61
|
class << self
|
55
|
-
|
62
|
+
# Creates a new context and yields the context as the first argument to
|
63
|
+
# the block.
|
64
|
+
#
|
65
|
+
# @example Creates a new context, imports the default as function
|
66
|
+
# result = Isorun::Context.create do |context|
|
67
|
+
# func = context.import.from(module_path)
|
68
|
+
# func.call("Hello, World!")
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @yield [context] The newly created JavaScript context
|
72
|
+
# @yieldparam [Isorun::Context] context
|
73
|
+
# @yieldreturn [Object, nil] An optional return value from the execution context
|
74
|
+
def create(options = default_options, &block)
|
56
75
|
raise "[Isorun::Context] block missing when creating context" unless block
|
57
76
|
|
58
77
|
context = Isorun::Context.new
|
59
|
-
|
78
|
+
|
79
|
+
context.receiver = options[:receiver] if options[:receiver].present?
|
80
|
+
|
81
|
+
result = yield(context)
|
82
|
+
|
83
|
+
context.receiver = nil if options[:receiver].present?
|
84
|
+
|
85
|
+
result
|
60
86
|
end
|
61
87
|
|
62
88
|
# @!method new()
|
@@ -66,11 +92,28 @@ module Isorun
|
|
66
92
|
|
67
93
|
def default_options
|
68
94
|
{
|
69
|
-
receiver:
|
95
|
+
receiver: nil
|
70
96
|
}
|
71
97
|
end
|
72
98
|
end
|
73
99
|
|
100
|
+
# Specify items you want to import from the module. If none is specified,
|
101
|
+
# the default export is taken.
|
102
|
+
#
|
103
|
+
# @example Import default export
|
104
|
+
# result = Isorun::Context.create do |context|
|
105
|
+
# item = context.import.from(module_path)
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# @example Import default export explicitly
|
109
|
+
# result = Isorun::Context.create do |context|
|
110
|
+
# item = context.import(:default).from(module_path)
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# @example Import various exports
|
114
|
+
# result = Isorun::Context.create do |context|
|
115
|
+
# hello, world = context.import(:hello, :world).from(module_path)
|
116
|
+
# end
|
74
117
|
def import(*export_names)
|
75
118
|
export_names = [*export_names].map(&:to_s)
|
76
119
|
export_names = [:default.to_s] if export_names.empty?
|
@@ -78,6 +121,7 @@ module Isorun
|
|
78
121
|
end
|
79
122
|
|
80
123
|
# @!method receiver=(receiver)
|
124
|
+
#
|
81
125
|
# @param receiver [Proc, nil]
|
82
126
|
# @return [Isorun::Context] the newly created context
|
83
127
|
end
|
data/lib/isorun/engine.rb
CHANGED
data/lib/isorun/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: isorun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: x86_64-linux
|
6
6
|
authors:
|
7
7
|
- Hannes Moser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 0.9.46
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake-compiler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,20 @@ dependencies:
|
|
80
94
|
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: rspec-rails
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,10 +122,27 @@ dependencies:
|
|
94
122
|
- - ">="
|
95
123
|
- !ruby/object:Gem::Version
|
96
124
|
version: '0'
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.22.0
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.22.0
|
139
|
+
description: |
|
140
|
+
Import ECMAScript modules into Ruby and use values and functions like
|
141
|
+
JavaScript is part of Ruby. Enables easy to set up server-side rendering for
|
142
|
+
modern frontend stacks.
|
143
|
+
|
144
|
+
Isorun embeds v8 into Ruby via a native extension built with Rust and
|
145
|
+
deno_core.
|
101
146
|
email:
|
102
147
|
- box@hannesmoser.at
|
103
148
|
executables: []
|