opal-vite-rails 0.3.12 → 0.3.14
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 +51 -21
- data/lib/opal/vite/rails/engine.rb +16 -0
- data/lib/opal/vite/rails/generators/install_generator.rb +52 -8
- data/lib/opal/vite/rails/helper.rb +26 -20
- data/lib/opal/vite/rails/version.rb +1 -1
- data/templates/opal_entrypoint.js.tt +6 -0
- data/templates/vite.config.ts.tt +4 -13
- metadata +8 -2
- data/templates/application_loader.js.tt +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ef10da23927e3793b0aa7d4730e9007800bf70ab430b05ee9ddc550a81af197
|
|
4
|
+
data.tar.gz: d06c1b304ebf7e7985b74d89f352fa0ec6f08edba9a0726ed1a407733329bd02
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d8a1992423ad276695e0dfcb021e4b2d6f0109ebc6688b27f13251359eae7d7ccdebd36c832c73e41d3825f30a0bff791a66999d718127558562a52fbaae8223
|
|
7
|
+
data.tar.gz: d2e47d18cebb49f142b840985e7ff1361b3740c41bdc5002669450d66143f3d587f73fa022aae250127a85f9964ae9a693200a2b0f1f17a25e875eefbd2d5fd6
|
data/README.md
CHANGED
|
@@ -37,13 +37,18 @@ Run the generator:
|
|
|
37
37
|
rails generate opal_vite:install
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
This will
|
|
41
|
-
|
|
42
|
-
- Generate `app/opal/application.rb
|
|
40
|
+
This will (paths assume vite_ruby's default `sourceCodeDir` of `app/frontend`;
|
|
41
|
+
the generator reads `config/vite.json`):
|
|
42
|
+
- Generate `app/frontend/opal/application.rb`, the Ruby entry point
|
|
43
|
+
- Generate `app/frontend/entrypoints/opal.js`, the Vite entrypoint that imports it
|
|
43
44
|
- Configure Vite with the Opal plugin
|
|
44
|
-
- Create an example controller and view
|
|
45
|
+
- Create an example controller and view (`/opal_demo`)
|
|
45
46
|
- Add necessary routes
|
|
46
47
|
|
|
48
|
+
The engine tells Zeitwerk to ignore the Opal source directories
|
|
49
|
+
(`config.opal_vite.source_path`, default `app/opal`, and `<sourceCodeDir>/opal`),
|
|
50
|
+
so the browser-side Ruby is never loaded by the server.
|
|
51
|
+
|
|
47
52
|
Install JavaScript dependencies:
|
|
48
53
|
|
|
49
54
|
```bash
|
|
@@ -72,10 +77,16 @@ Visit `http://localhost:3000/opal_demo` to see Opal in action!
|
|
|
72
77
|
|
|
73
78
|
### Writing Opal Code
|
|
74
79
|
|
|
75
|
-
Create Ruby files in `app/opal
|
|
80
|
+
Create Ruby files in `app/frontend/opal/` and import them from an entrypoint
|
|
81
|
+
in `app/frontend/entrypoints/`:
|
|
82
|
+
|
|
83
|
+
```js
|
|
84
|
+
// app/frontend/entrypoints/hello.js
|
|
85
|
+
import '../opal/hello.rb'
|
|
86
|
+
```
|
|
76
87
|
|
|
77
88
|
```ruby
|
|
78
|
-
# app/opal/hello.rb
|
|
89
|
+
# app/frontend/opal/hello.rb
|
|
79
90
|
require 'native'
|
|
80
91
|
|
|
81
92
|
puts "Hello from Ruby running in the browser!"
|
|
@@ -117,9 +128,12 @@ Add Opal JavaScript to your views with the helper:
|
|
|
117
128
|
<%= opal_javascript_tag "hello" %>
|
|
118
129
|
```
|
|
119
130
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
`opal_javascript_tag "hello"` is `vite_javascript_tag "hello.js"`, so it
|
|
132
|
+
emits `type="module"` and switches between the Vite dev server and the build
|
|
133
|
+
manifest the same way.
|
|
134
|
+
|
|
135
|
+
The Opal runtime is imported by the compiled Ruby itself; you don't need a
|
|
136
|
+
separate tag or `import '/@opal-runtime'` for it.
|
|
123
137
|
|
|
124
138
|
### View Helpers
|
|
125
139
|
|
|
@@ -130,9 +144,12 @@ Loads an Opal JavaScript bundle:
|
|
|
130
144
|
```erb
|
|
131
145
|
<%= opal_javascript_tag "application" %>
|
|
132
146
|
<%= opal_javascript_tag "application", defer: true %>
|
|
133
|
-
<%= opal_javascript_tag "application", type: "module" %>
|
|
134
147
|
```
|
|
135
148
|
|
|
149
|
+
#### `opal_runtime_tag` (deprecated)
|
|
150
|
+
|
|
151
|
+
Outputs nothing. The runtime is loaded by the compiled `.rb` modules.
|
|
152
|
+
|
|
136
153
|
#### `opal_asset_path`
|
|
137
154
|
|
|
138
155
|
Gets the path to an Opal asset:
|
|
@@ -158,14 +175,14 @@ Checks if Vite dev server is running:
|
|
|
158
175
|
Organize your code with `require`:
|
|
159
176
|
|
|
160
177
|
```ruby
|
|
161
|
-
# app/opal/lib/calculator.rb
|
|
178
|
+
# app/frontend/opal/lib/calculator.rb
|
|
162
179
|
class Calculator
|
|
163
180
|
def add(a, b)
|
|
164
181
|
a + b
|
|
165
182
|
end
|
|
166
183
|
end
|
|
167
184
|
|
|
168
|
-
# app/opal/application.rb
|
|
185
|
+
# app/frontend/opal/application.rb
|
|
169
186
|
require 'lib/calculator'
|
|
170
187
|
|
|
171
188
|
calc = Calculator.new
|
|
@@ -211,15 +228,18 @@ config.opal_vite.public_output_path = "vite" # Default
|
|
|
211
228
|
|
|
212
229
|
```
|
|
213
230
|
app/
|
|
214
|
-
├──
|
|
215
|
-
│ ├──
|
|
216
|
-
│ ├──
|
|
217
|
-
│ └──
|
|
218
|
-
│
|
|
231
|
+
├── frontend/ # vite_ruby sourceCodeDir
|
|
232
|
+
│ ├── entrypoints/
|
|
233
|
+
│ │ ├── application.js # Created by `vite install`
|
|
234
|
+
│ │ └── opal.js # Imports ../opal/application.rb
|
|
235
|
+
│ └── opal/
|
|
236
|
+
│ ├── application.rb # Ruby entry point
|
|
237
|
+
│ └── lib/
|
|
238
|
+
│ └── my_module.rb # Your Ruby modules
|
|
219
239
|
├── controllers/
|
|
220
240
|
└── views/
|
|
221
241
|
|
|
222
|
-
vite.config.ts
|
|
242
|
+
vite.config.ts # Vite config with the opal plugin
|
|
223
243
|
```
|
|
224
244
|
|
|
225
245
|
## How It Works
|
|
@@ -243,14 +263,14 @@ Customize `vite.config.ts`:
|
|
|
243
263
|
|
|
244
264
|
```typescript
|
|
245
265
|
import { defineConfig } from 'vite'
|
|
246
|
-
import RubyPlugin from '
|
|
266
|
+
import RubyPlugin from 'vite-plugin-ruby'
|
|
247
267
|
import opal from 'vite-plugin-opal'
|
|
248
268
|
|
|
249
269
|
export default defineConfig({
|
|
250
270
|
plugins: [
|
|
251
271
|
RubyPlugin(),
|
|
252
272
|
opal({
|
|
253
|
-
loadPaths: ['./app/opal', './lib/opal'],
|
|
273
|
+
loadPaths: ['./app/frontend/opal', './lib/opal'],
|
|
254
274
|
sourceMap: true,
|
|
255
275
|
debug: process.env.NODE_ENV === 'development'
|
|
256
276
|
})
|
|
@@ -278,7 +298,7 @@ require 'ostruct' # OpenStruct
|
|
|
278
298
|
|
|
279
299
|
Make sure:
|
|
280
300
|
1. Vite dev server is running (`bin/vite dev`)
|
|
281
|
-
2.
|
|
301
|
+
2. The `.rb` file is imported from a file in `entrypoints/` (directly or via other imports)
|
|
282
302
|
3. Rails is configured to proxy to Vite in development
|
|
283
303
|
|
|
284
304
|
### Assets not loading in production
|
|
@@ -300,6 +320,16 @@ opal({
|
|
|
300
320
|
})
|
|
301
321
|
```
|
|
302
322
|
|
|
323
|
+
## Version Compatibility
|
|
324
|
+
|
|
325
|
+
The npm plugin runs the gem's Ruby code, so keep the two in step:
|
|
326
|
+
|
|
327
|
+
| vite-plugin-opal (npm) | opal-vite (gem) | opal-vite-rails (gem) | Notes |
|
|
328
|
+
|------------------------|-----------------|-----------------------|-------|
|
|
329
|
+
| >= 0.3.16 | >= 0.3.15 | >= 0.3.14 | Shared runtime: corelib is loaded once |
|
|
330
|
+
| >= 0.3.16 | 0.3.12 – 0.3.14 | — | Works; each `.rb` bundle carries its own corelib (warning at startup) |
|
|
331
|
+
| >= 0.3.16 | < 0.3.12 | — | Works without the `stubs` option (using it fails with a clear error) |
|
|
332
|
+
|
|
303
333
|
## Examples
|
|
304
334
|
|
|
305
335
|
See the [examples/rails-app](../../examples/rails-app) directory for a complete working example.
|
|
@@ -20,6 +20,22 @@ module Opal
|
|
|
20
20
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
# app/* subdirectories are Zeitwerk roots, so without this the Opal
|
|
24
|
+
# sources (browser code) would be eager loaded by MRI in production
|
|
25
|
+
# and fail with LoadError on `require 'native'` etc.
|
|
26
|
+
initializer "opal_vite.ignore_opal_sources" do |app|
|
|
27
|
+
opal_dirs = [
|
|
28
|
+
::Rails.root.join(app.config.opal_vite.source_path || Opal::Vite::Rails.config.source_path)
|
|
29
|
+
]
|
|
30
|
+
if defined?(ViteRuby)
|
|
31
|
+
opal_dirs << ViteRuby.config.root.join(ViteRuby.config.source_code_dir, "opal")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
::Rails.autoloaders.each do |autoloader|
|
|
35
|
+
opal_dirs.uniq.each { |dir| autoloader.ignore(dir) }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
23
39
|
initializer "opal_vite.view_helpers" do
|
|
24
40
|
ActiveSupport.on_load(:action_view) do
|
|
25
41
|
include Opal::Vite::Rails::Helper
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require "rails/generators/base"
|
|
2
|
+
require "json"
|
|
3
|
+
require "pathname"
|
|
2
4
|
|
|
3
5
|
module Opal
|
|
4
6
|
module Vite
|
|
@@ -7,6 +9,8 @@ module Opal
|
|
|
7
9
|
class InstallGenerator < ::Rails::Generators::Base
|
|
8
10
|
source_root File.expand_path("../../../../../templates", __dir__)
|
|
9
11
|
|
|
12
|
+
namespace "opal_vite:install"
|
|
13
|
+
|
|
10
14
|
desc "Install Opal-Vite in your Rails application"
|
|
11
15
|
|
|
12
16
|
def check_vite_rails
|
|
@@ -17,24 +21,27 @@ module Opal
|
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
# Opal sources live under vite_ruby's sourceCodeDir so that the Vite
|
|
25
|
+
# dev server and autoBuild watch them like any other frontend file.
|
|
26
|
+
def create_application_rb
|
|
27
|
+
template "application.rb.tt", File.join(opal_dir, "application.rb")
|
|
23
28
|
end
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
# An entrypoint is what puts the Ruby code into a Vite bundle; without
|
|
31
|
+
# it application.rb is never compiled.
|
|
32
|
+
def create_entrypoint
|
|
33
|
+
template "opal_entrypoint.js.tt", File.join(entrypoints_dir, "opal.js")
|
|
27
34
|
end
|
|
28
35
|
|
|
29
36
|
def create_vite_config
|
|
30
|
-
if File.exist?("vite.config.ts")
|
|
37
|
+
if File.exist?(File.join(destination_root, "vite.config.ts"))
|
|
31
38
|
inject_into_file "vite.config.ts", after: "import { defineConfig } from 'vite'\n" do
|
|
32
39
|
"import opal from 'vite-plugin-opal'\n"
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
inject_into_file "vite.config.ts", after: "plugins: [\n" do
|
|
36
43
|
" opal({\n" \
|
|
37
|
-
" loadPaths: ['
|
|
44
|
+
" loadPaths: ['./#{opal_dir}'],\n" \
|
|
38
45
|
" sourceMap: true\n" \
|
|
39
46
|
" }),\n"
|
|
40
47
|
end
|
|
@@ -58,7 +65,7 @@ module Opal
|
|
|
58
65
|
<p>Check your browser console to see Opal output!</p>
|
|
59
66
|
</div>
|
|
60
67
|
|
|
61
|
-
<%= opal_javascript_tag "
|
|
68
|
+
<%= opal_javascript_tag "opal" %>
|
|
62
69
|
ERB
|
|
63
70
|
end
|
|
64
71
|
|
|
@@ -90,6 +97,43 @@ module Opal
|
|
|
90
97
|
say " http://localhost:3000/opal_demo"
|
|
91
98
|
say "\n" + "="*60, :green
|
|
92
99
|
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def source_code_dir
|
|
104
|
+
vite_config_value(:source_code_dir, "sourceCodeDir", "app/frontend")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def entrypoints_dir
|
|
108
|
+
File.join(source_code_dir, vite_config_value(:entrypoints_dir, "entrypointsDir", "entrypoints"))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def opal_dir
|
|
112
|
+
File.join(source_code_dir, "opal")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Path of application.rb as imported from the entrypoint
|
|
116
|
+
def opal_import_path
|
|
117
|
+
path = Pathname.new(File.join(opal_dir, "application.rb"))
|
|
118
|
+
.relative_path_from(Pathname.new(entrypoints_dir)).to_s
|
|
119
|
+
path.start_with?(".") ? path : "./#{path}"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Read a vite_ruby setting, falling back to config/vite.json (vite_rails
|
|
123
|
+
# may have been installed by this generator in a separate process) and
|
|
124
|
+
# then to vite_ruby's default.
|
|
125
|
+
def vite_config_value(method, json_key, default)
|
|
126
|
+
return ViteRuby.config.public_send(method).to_s if defined?(ViteRuby)
|
|
127
|
+
|
|
128
|
+
vite_json.dig("all", json_key) || default
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def vite_json
|
|
132
|
+
@vite_json ||= begin
|
|
133
|
+
path = File.join(destination_root, "config", "vite.json")
|
|
134
|
+
File.exist?(path) ? JSON.parse(File.read(path)) : {}
|
|
135
|
+
end
|
|
136
|
+
end
|
|
93
137
|
end
|
|
94
138
|
end
|
|
95
139
|
end
|
|
@@ -2,20 +2,17 @@ module Opal
|
|
|
2
2
|
module Vite
|
|
3
3
|
module Rails
|
|
4
4
|
module Helper
|
|
5
|
-
# Generate script tag for Opal
|
|
5
|
+
# Generate script tag for an entrypoint that loads Opal code
|
|
6
6
|
#
|
|
7
7
|
# Usage in views:
|
|
8
8
|
# <%= opal_javascript_tag "application" %>
|
|
9
9
|
#
|
|
10
|
+
# Delegates to vite_javascript_tag in every environment: Vite emits ES
|
|
11
|
+
# modules, so the tag must carry type="module" (plus crossorigin and
|
|
12
|
+
# modulepreload links), and vite_ruby already switches between the dev
|
|
13
|
+
# server and the build manifest.
|
|
10
14
|
def opal_javascript_tag(name, **options)
|
|
11
|
-
|
|
12
|
-
# Development: load from Vite dev server
|
|
13
|
-
vite_javascript_tag("#{name}.js", **options)
|
|
14
|
-
else
|
|
15
|
-
# Production: load from manifest
|
|
16
|
-
asset_path = opal_asset_path("#{name}.js")
|
|
17
|
-
javascript_include_tag(asset_path, **options)
|
|
18
|
-
end
|
|
15
|
+
vite_javascript_tag("#{name}.js", **options)
|
|
19
16
|
end
|
|
20
17
|
|
|
21
18
|
# Generate multiple script tags for Opal JavaScript files
|
|
@@ -33,25 +30,34 @@ module Opal
|
|
|
33
30
|
end
|
|
34
31
|
|
|
35
32
|
# Get asset path from Vite manifest
|
|
33
|
+
#
|
|
34
|
+
# NOTE: the manifest lives on the ViteRuby *instance* — `ViteRuby.manifest`
|
|
35
|
+
# is not a class-level delegator (it raises NoMethodError), so we go
|
|
36
|
+
# through `ViteRuby.instance`. Use ViteRuby::Manifest#path_for (public)
|
|
37
|
+
# rather than #lookup: #lookup is *protected* and returns the raw manifest
|
|
38
|
+
# entry Hash ({ "file" => "..." }), so `lookup(name).to_s` would emit the
|
|
39
|
+
# Hash's inspect string instead of a URL. #path_for returns the resolved
|
|
40
|
+
# asset URL string.
|
|
36
41
|
def opal_asset_path(name)
|
|
37
42
|
if defined?(ViteRuby)
|
|
38
|
-
ViteRuby.manifest.
|
|
43
|
+
ViteRuby.instance.manifest.path_for(name)
|
|
39
44
|
else
|
|
40
45
|
# Fallback to standard asset path
|
|
41
46
|
"/#{Opal::Vite::Rails.config.public_output_path}/#{name}"
|
|
42
47
|
end
|
|
43
48
|
end
|
|
44
49
|
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
# Deprecated: outputs nothing.
|
|
51
|
+
#
|
|
52
|
+
# Compiled .rb modules import the Opal runtime (`/@opal-runtime`)
|
|
53
|
+
# themselves, and in production it is bundled into the entrypoint's
|
|
54
|
+
# chunks, so there is no separate runtime file to load. A standalone
|
|
55
|
+
# tag would load a second copy of the runtime in development.
|
|
56
|
+
def opal_runtime_tag(**_options)
|
|
57
|
+
ActiveSupport::Deprecation.new("0.4", "opal-vite-rails").warn(
|
|
58
|
+
"opal_runtime_tag is no longer needed and outputs nothing; remove it from your views."
|
|
59
|
+
)
|
|
60
|
+
"".html_safe
|
|
55
61
|
end
|
|
56
62
|
end
|
|
57
63
|
end
|
data/templates/vite.config.ts.tt
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
import { defineConfig } from 'vite'
|
|
2
|
-
import RubyPlugin from '
|
|
2
|
+
import RubyPlugin from 'vite-plugin-ruby'
|
|
3
3
|
import opal from 'vite-plugin-opal'
|
|
4
4
|
|
|
5
5
|
export default defineConfig({
|
|
6
6
|
plugins: [
|
|
7
7
|
RubyPlugin(),
|
|
8
8
|
opal({
|
|
9
|
-
loadPaths: ['
|
|
10
|
-
sourceMap: true
|
|
11
|
-
debug: process.env.NODE_ENV === 'development'
|
|
9
|
+
loadPaths: ['./<%= opal_dir %>'],
|
|
10
|
+
sourceMap: true
|
|
12
11
|
})
|
|
13
|
-
]
|
|
14
|
-
build: {
|
|
15
|
-
manifest: true,
|
|
16
|
-
rollupOptions: {
|
|
17
|
-
input: {
|
|
18
|
-
'application': './app/opal/application_loader.js'
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
12
|
+
]
|
|
22
13
|
})
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: opal-vite-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- stofu1234
|
|
@@ -16,6 +16,9 @@ dependencies:
|
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '0.3'
|
|
19
|
+
- - ">="
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 0.3.15
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -23,6 +26,9 @@ dependencies:
|
|
|
23
26
|
- - "~>"
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
28
|
version: '0.3'
|
|
29
|
+
- - ">="
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: 0.3.15
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: ostruct
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -138,7 +144,7 @@ files:
|
|
|
138
144
|
- lib/opal/vite/rails/version.rb
|
|
139
145
|
- lib/tasks/opal_vite.rake
|
|
140
146
|
- templates/application.rb.tt
|
|
141
|
-
- templates/
|
|
147
|
+
- templates/opal_entrypoint.js.tt
|
|
142
148
|
- templates/vite.config.ts.tt
|
|
143
149
|
homepage: https://stofu1234.github.io/opal-vite/
|
|
144
150
|
licenses:
|