opal-vite-rails 0.3.13 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb4b027bd6a9af93d8ca80700e7fcadb26251b792e3b0df8f43f72492d680717
4
- data.tar.gz: 509ab21889bf6c849f0775c051ac6ae98474977fd37fb6251a71d47fce2894f4
3
+ metadata.gz: 5ef10da23927e3793b0aa7d4730e9007800bf70ab430b05ee9ddc550a81af197
4
+ data.tar.gz: d06c1b304ebf7e7985b74d89f352fa0ec6f08edba9a0726ed1a407733329bd02
5
5
  SHA512:
6
- metadata.gz: c598f18eba197fc1cd9c94f6a21c40997cf05dd4626e6f23f29a5de6d28022891784d7a492e668c0f7542d75a0600c19f09999d6eeb5ec2884e40ce70c0c18be
7
- data.tar.gz: c4eaef2d98bdf29e2c7d09310cac16a72e37c655f1d8e35605e68e190c788710b2975fb709290454a0dce68fade9199cf1ae52350bf8dbb539e4b4dd3dc3f7eb
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
- - Create `app/opal/` directory for your Ruby code
42
- - Generate `app/opal/application.rb` entry point
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
- The helper automatically handles development vs production modes:
121
- - **Development**: Loads from Vite dev server with HMR
122
- - **Production**: Loads precompiled assets from manifest
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
- ├── opal/
215
- │ ├── application.rb # Entry point
216
- │ ├── application_loader.js # JS loader (required for Vite)
217
- │ └── lib/
218
- │ └── my_module.rb # Your Ruby modules
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 # Vite config with opal plugin
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 'vite_ruby/plugins/ruby'
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. You're using the JavaScript loader pattern (`.rb` files imported via `.js` loaders)
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
- def create_opal_directory
21
- empty_directory "app/opal"
22
- create_file "app/opal/.keep"
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
- def create_application_rb
26
- template "application.rb.tt", "app/opal/application.rb"
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: ['./app/opal'],\n" \
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 "application" %>
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 JavaScript
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
- if vite_running?
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
@@ -50,16 +47,17 @@ module Opal
50
47
  end
51
48
  end
52
49
 
53
- # Include Opal runtime
54
- # This is automatically included when using opal_javascript_tag,
55
- # but can be called explicitly if needed
56
- def opal_runtime_tag(**options)
57
- if vite_running?
58
- vite_javascript_tag("@opal-runtime", **options)
59
- else
60
- asset_path = opal_asset_path("opal-runtime.js")
61
- javascript_include_tag(asset_path, **options)
62
- end
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
63
61
  end
64
62
  end
65
63
  end
@@ -1,7 +1,7 @@
1
1
  module Opal
2
2
  module Vite
3
3
  module Rails
4
- VERSION = "0.3.13"
4
+ VERSION = "0.3.14"
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,6 @@
1
+ // Vite entrypoint for the Opal application.
2
+ // Load it in a view with: <%%= opal_javascript_tag "opal" %>
3
+ //
4
+ // The compiled Ruby imports the Opal runtime itself, so nothing else is
5
+ // needed here.
6
+ import '<%= opal_import_path %>'
@@ -1,22 +1,13 @@
1
1
  import { defineConfig } from 'vite'
2
- import RubyPlugin from 'vite_ruby/plugins/ruby'
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: ['./app/opal'],
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.13
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/application_loader.js.tt
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:
@@ -1,4 +0,0 @@
1
- // Loader for Opal application
2
- // This file imports the Ruby code so Vite can process it
3
-
4
- import './application.rb'