opal-vite-rails 0.2.13
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 +7 -0
- data/README.md +320 -0
- data/lib/opal/vite/rails/engine.rb +50 -0
- data/lib/opal/vite/rails/generators/install_generator.rb +97 -0
- data/lib/opal/vite/rails/helper.rb +59 -0
- data/lib/opal/vite/rails/manifest.rb +60 -0
- data/lib/opal/vite/rails/version.rb +7 -0
- data/lib/opal-vite-rails.rb +31 -0
- data/lib/tasks/opal_vite.rake +65 -0
- data/templates/application.rb.tt +28 -0
- data/templates/application_loader.js.tt +4 -0
- data/templates/vite.config.ts.tt +22 -0
- metadata +152 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 14d0a172031cb97c3e8edeea1aef19764cc7784aa7371f837fe7bbbd34d8bbdf
|
|
4
|
+
data.tar.gz: 32eff08bd3c3b40e2034147ad061c404d6a4357d8fa47d1bc16834a386a7bb5d
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c786a60aed283b7ce493a024b4aa2e766a64b6fc8f2c65086268e7d474600a9a3917c8cb8c712a327fd54ccd7a78d0d48c768c8695bb9da3a133a4624b8192f7
|
|
7
|
+
data.tar.gz: c243690b8eb9d5ab4eadf840106158a2b9bdc3767dfee6b7d58ee00c6088b28bcd49927be774f36f62f331a77888cffd149e5da6ffe9b5df7831f6da7fd9f52b
|
data/README.md
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Opal-Vite-Rails
|
|
2
|
+
|
|
3
|
+
Seamless integration of [Opal](https://opalrb.com/) (Ruby to JavaScript compiler) with [Vite](https://vitejs.dev/) in Rails applications. Write Ruby code that runs in the browser with the fast development experience of Vite.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Ruby in the Browser**: Write Ruby code that compiles to JavaScript
|
|
8
|
+
- ✅ **Vite Integration**: Fast HMR (Hot Module Replacement) during development
|
|
9
|
+
- ✅ **Rails Integration**: Seamless integration with Rails views and asset pipeline
|
|
10
|
+
- ✅ **Source Maps**: Debug Ruby code directly in browser DevTools
|
|
11
|
+
- ✅ **Production Ready**: Optimized builds with manifest-based asset resolution
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Ruby >= 3.0
|
|
16
|
+
- Rails >= 7.0
|
|
17
|
+
- Node.js >= 18.0
|
|
18
|
+
- Opal >= 1.8
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Add to your Gemfile:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
gem 'opal-vite-rails'
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Install the gem:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bundle install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Run the generator:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
rails generate opal_vite:install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This will:
|
|
41
|
+
- Create `app/opal/` directory for your Ruby code
|
|
42
|
+
- Generate `app/opal/application.rb` entry point
|
|
43
|
+
- Configure Vite with the Opal plugin
|
|
44
|
+
- Create an example controller and view
|
|
45
|
+
- Add necessary routes
|
|
46
|
+
|
|
47
|
+
Install JavaScript dependencies:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm install vite-plugin-opal
|
|
51
|
+
# or
|
|
52
|
+
pnpm install vite-plugin-opal
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage
|
|
56
|
+
|
|
57
|
+
### Development Mode
|
|
58
|
+
|
|
59
|
+
Start the Vite development server in one terminal:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bin/vite dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Start Rails in another terminal:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
rails server
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Visit `http://localhost:3000/opal_demo` to see Opal in action!
|
|
72
|
+
|
|
73
|
+
### Writing Opal Code
|
|
74
|
+
|
|
75
|
+
Create Ruby files in `app/opal/`:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
# app/opal/hello.rb
|
|
79
|
+
require 'native'
|
|
80
|
+
|
|
81
|
+
puts "Hello from Ruby running in the browser!"
|
|
82
|
+
|
|
83
|
+
# Use JavaScript via backticks
|
|
84
|
+
`
|
|
85
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
86
|
+
console.log('DOM is ready!');
|
|
87
|
+
|
|
88
|
+
const element = document.getElementById('my-element');
|
|
89
|
+
if (element) {
|
|
90
|
+
element.textContent = 'Updated by Ruby!';
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
`
|
|
94
|
+
|
|
95
|
+
# Or use the Native module for cleaner JS interop
|
|
96
|
+
class MyComponent
|
|
97
|
+
def initialize(element_id)
|
|
98
|
+
@element = Native(`document.getElementById(#{element_id})`)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def update(text)
|
|
102
|
+
@element[:textContent] = text
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
MyComponent.new('my-element').update('Hello from Ruby!')
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Using in Views
|
|
110
|
+
|
|
111
|
+
Add Opal JavaScript to your views with the helper:
|
|
112
|
+
|
|
113
|
+
```erb
|
|
114
|
+
<!-- app/views/welcome/index.html.erb -->
|
|
115
|
+
<div id="my-element">Loading...</div>
|
|
116
|
+
|
|
117
|
+
<%= opal_javascript_tag "hello" %>
|
|
118
|
+
```
|
|
119
|
+
|
|
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
|
|
123
|
+
|
|
124
|
+
### View Helpers
|
|
125
|
+
|
|
126
|
+
#### `opal_javascript_tag`
|
|
127
|
+
|
|
128
|
+
Loads an Opal JavaScript bundle:
|
|
129
|
+
|
|
130
|
+
```erb
|
|
131
|
+
<%= opal_javascript_tag "application" %>
|
|
132
|
+
<%= opal_javascript_tag "application", defer: true %>
|
|
133
|
+
<%= opal_javascript_tag "application", type: "module" %>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### `opal_asset_path`
|
|
137
|
+
|
|
138
|
+
Gets the path to an Opal asset:
|
|
139
|
+
|
|
140
|
+
```erb
|
|
141
|
+
<script src="<%= opal_asset_path('application.js') %>"></script>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### `vite_running?`
|
|
145
|
+
|
|
146
|
+
Checks if Vite dev server is running:
|
|
147
|
+
|
|
148
|
+
```erb
|
|
149
|
+
<% if vite_running? %>
|
|
150
|
+
<p>Development mode with HMR enabled</p>
|
|
151
|
+
<% else %>
|
|
152
|
+
<p>Production mode</p>
|
|
153
|
+
<% end %>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Requiring Other Files
|
|
157
|
+
|
|
158
|
+
Organize your code with `require`:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
# app/opal/lib/calculator.rb
|
|
162
|
+
class Calculator
|
|
163
|
+
def add(a, b)
|
|
164
|
+
a + b
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# app/opal/application.rb
|
|
169
|
+
require 'lib/calculator'
|
|
170
|
+
|
|
171
|
+
calc = Calculator.new
|
|
172
|
+
puts calc.add(5, 3) # => 8
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Production Deployment
|
|
176
|
+
|
|
177
|
+
Compile Opal assets:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
rake opal_vite:compile
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
This runs Vite build and creates optimized bundles in `public/vite/`.
|
|
184
|
+
|
|
185
|
+
The compile task is automatically added to `rake assets:precompile`, so it runs during deployment on platforms like Heroku.
|
|
186
|
+
|
|
187
|
+
## Rake Tasks
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Compile Opal assets for production
|
|
191
|
+
rake opal_vite:compile
|
|
192
|
+
|
|
193
|
+
# Clean compiled assets
|
|
194
|
+
rake opal_vite:clean
|
|
195
|
+
|
|
196
|
+
# Show configuration info
|
|
197
|
+
rake opal_vite:info
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Configuration
|
|
201
|
+
|
|
202
|
+
Configure in `config/application.rb` or environment files:
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
# config/application.rb
|
|
206
|
+
config.opal_vite.source_path = "app/opal" # Default
|
|
207
|
+
config.opal_vite.public_output_path = "vite" # Default
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Project Structure
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
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
|
|
219
|
+
├── controllers/
|
|
220
|
+
└── views/
|
|
221
|
+
|
|
222
|
+
vite.config.ts # Vite config with opal plugin
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## How It Works
|
|
226
|
+
|
|
227
|
+
1. **Development**:
|
|
228
|
+
- Vite dev server watches `.rb` files
|
|
229
|
+
- When a `.rb` file changes, Opal compiles it to JavaScript
|
|
230
|
+
- HMR updates the browser instantly
|
|
231
|
+
- Source maps allow debugging Ruby code in DevTools
|
|
232
|
+
|
|
233
|
+
2. **Production**:
|
|
234
|
+
- `rake opal_vite:compile` builds optimized JavaScript bundles
|
|
235
|
+
- Manifest file maps logical names to hashed filenames
|
|
236
|
+
- Rails helpers load assets from the manifest
|
|
237
|
+
|
|
238
|
+
## Advanced Usage
|
|
239
|
+
|
|
240
|
+
### Custom Vite Configuration
|
|
241
|
+
|
|
242
|
+
Customize `vite.config.ts`:
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
import { defineConfig } from 'vite'
|
|
246
|
+
import RubyPlugin from 'vite_ruby/plugins/ruby'
|
|
247
|
+
import opal from 'vite-plugin-opal'
|
|
248
|
+
|
|
249
|
+
export default defineConfig({
|
|
250
|
+
plugins: [
|
|
251
|
+
RubyPlugin(),
|
|
252
|
+
opal({
|
|
253
|
+
loadPaths: ['./app/opal', './lib/opal'],
|
|
254
|
+
sourceMap: true,
|
|
255
|
+
debug: process.env.NODE_ENV === 'development'
|
|
256
|
+
})
|
|
257
|
+
],
|
|
258
|
+
// Your custom Vite config...
|
|
259
|
+
})
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Using Opal Standard Library
|
|
263
|
+
|
|
264
|
+
Opal includes a standard library with Ruby core classes:
|
|
265
|
+
|
|
266
|
+
```ruby
|
|
267
|
+
require 'native' # JavaScript interop
|
|
268
|
+
require 'promise' # Promise support
|
|
269
|
+
require 'json' # JSON parsing
|
|
270
|
+
require 'set' # Set class
|
|
271
|
+
require 'ostruct' # OpenStruct
|
|
272
|
+
# ... and more
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Troubleshooting
|
|
276
|
+
|
|
277
|
+
### HMR not working
|
|
278
|
+
|
|
279
|
+
Make sure:
|
|
280
|
+
1. Vite dev server is running (`bin/vite dev`)
|
|
281
|
+
2. You're using the JavaScript loader pattern (`.rb` files imported via `.js` loaders)
|
|
282
|
+
3. Rails is configured to proxy to Vite in development
|
|
283
|
+
|
|
284
|
+
### Assets not loading in production
|
|
285
|
+
|
|
286
|
+
Run the compile task before deployment:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
RAILS_ENV=production rake opal_vite:compile
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Source maps not showing Ruby code
|
|
293
|
+
|
|
294
|
+
Ensure `sourceMap: true` in `vite.config.ts`:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
opal({
|
|
298
|
+
sourceMap: true,
|
|
299
|
+
// ...
|
|
300
|
+
})
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Examples
|
|
304
|
+
|
|
305
|
+
See the [examples/rails-app](../../examples/rails-app) directory for a complete working example.
|
|
306
|
+
|
|
307
|
+
## Contributing
|
|
308
|
+
|
|
309
|
+
Bug reports and pull requests are welcome on GitHub.
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
The gem is available as open source under the terms of the MIT License.
|
|
314
|
+
|
|
315
|
+
## See Also
|
|
316
|
+
|
|
317
|
+
- [Opal](https://opalrb.com/) - Ruby to JavaScript compiler
|
|
318
|
+
- [Vite](https://vitejs.dev/) - Next generation frontend tooling
|
|
319
|
+
- [vite_ruby](https://vite-ruby.netlify.app/) - Vite integration for Ruby
|
|
320
|
+
- [vite-plugin-opal](../../packages/vite-plugin-opal) - Vite plugin for Opal
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require "rails/engine"
|
|
2
|
+
|
|
3
|
+
module Opal
|
|
4
|
+
module Vite
|
|
5
|
+
module Rails
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
isolate_namespace Opal::Vite::Rails
|
|
8
|
+
|
|
9
|
+
config.opal_vite = ActiveSupport::OrderedOptions.new
|
|
10
|
+
|
|
11
|
+
initializer "opal_vite.set_configs" do |app|
|
|
12
|
+
# Set default configuration from app config
|
|
13
|
+
if app.config.opal_vite.source_path
|
|
14
|
+
Opal::Vite::Rails.config.source_path = app.config.opal_vite.source_path
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
if app.config.opal_vite.public_output_path
|
|
18
|
+
Opal::Vite::Rails.config.public_output_path = app.config.opal_vite.public_output_path
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Set manifest path from ViteRails
|
|
22
|
+
if defined?(ViteRuby)
|
|
23
|
+
Opal::Vite::Rails.config.manifest_path = ViteRuby.manifest_path
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
initializer "opal_vite.view_helpers" do
|
|
28
|
+
ActiveSupport.on_load(:action_view) do
|
|
29
|
+
include Opal::Vite::Rails::Helper
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
initializer "opal_vite.assets" do |app|
|
|
34
|
+
# Add Opal source path to asset paths
|
|
35
|
+
if app.config.respond_to?(:assets)
|
|
36
|
+
app.config.assets.paths << ::Rails.root.join(Opal::Vite::Rails.config.source_path)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
rake_tasks do
|
|
41
|
+
load "tasks/opal_vite.rake"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
generators do
|
|
45
|
+
require_relative "generators/install_generator"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require "rails/generators/base"
|
|
2
|
+
|
|
3
|
+
module Opal
|
|
4
|
+
module Vite
|
|
5
|
+
module Rails
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < ::Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path("../../../../../templates", __dir__)
|
|
9
|
+
|
|
10
|
+
desc "Install Opal-Vite in your Rails application"
|
|
11
|
+
|
|
12
|
+
def check_vite_rails
|
|
13
|
+
unless defined?(ViteRuby)
|
|
14
|
+
say "ViteRails is not installed. Installing it first...", :yellow
|
|
15
|
+
run "bundle add vite_rails"
|
|
16
|
+
run "bundle exec vite install"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create_opal_directory
|
|
21
|
+
empty_directory "app/opal"
|
|
22
|
+
create_file "app/opal/.keep"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def create_application_rb
|
|
26
|
+
template "application.rb.tt", "app/opal/application.rb"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def create_vite_config
|
|
30
|
+
if File.exist?("vite.config.ts")
|
|
31
|
+
inject_into_file "vite.config.ts", after: "import { defineConfig } from 'vite'\n" do
|
|
32
|
+
"import opal from 'vite-plugin-opal'\n"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
inject_into_file "vite.config.ts", after: "plugins: [\n" do
|
|
36
|
+
" opal({\n" \
|
|
37
|
+
" loadPaths: ['./app/opal'],\n" \
|
|
38
|
+
" sourceMap: true\n" \
|
|
39
|
+
" }),\n"
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
template "vite.config.ts.tt", "vite.config.ts"
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def create_package_json_entry
|
|
47
|
+
if File.exist?("package.json")
|
|
48
|
+
say "Adding vite-plugin-opal to package.json...", :green
|
|
49
|
+
say "Run: npm install vite-plugin-opal", :yellow
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_example_view
|
|
54
|
+
create_file "app/views/opal_demo/index.html.erb", <<~ERB
|
|
55
|
+
<h1>Opal + Vite + Rails Demo</h1>
|
|
56
|
+
|
|
57
|
+
<div id="opal-content">
|
|
58
|
+
<p>Check your browser console to see Opal output!</p>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<%= opal_javascript_tag "application" %>
|
|
62
|
+
ERB
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_route
|
|
66
|
+
route "get '/opal_demo', to: 'opal_demo#index'"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def create_controller
|
|
70
|
+
create_file "app/controllers/opal_demo_controller.rb", <<~RUBY
|
|
71
|
+
class OpalDemoController < ApplicationController
|
|
72
|
+
def index
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
RUBY
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def show_post_install_message
|
|
79
|
+
say "\n" + "="*60, :green
|
|
80
|
+
say "Opal-Vite installed successfully!", :green
|
|
81
|
+
say "="*60, :green
|
|
82
|
+
say "\nNext steps:", :yellow
|
|
83
|
+
say " 1. Install JavaScript dependencies:", :cyan
|
|
84
|
+
say " npm install vite-plugin-opal"
|
|
85
|
+
say "\n 2. Start Vite dev server:", :cyan
|
|
86
|
+
say " bin/vite dev"
|
|
87
|
+
say "\n 3. Start Rails server:", :cyan
|
|
88
|
+
say " rails server"
|
|
89
|
+
say "\n 4. Visit:", :cyan
|
|
90
|
+
say " http://localhost:3000/opal_demo"
|
|
91
|
+
say "\n" + "="*60, :green
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Opal
|
|
2
|
+
module Vite
|
|
3
|
+
module Rails
|
|
4
|
+
module Helper
|
|
5
|
+
# Generate script tag for Opal JavaScript
|
|
6
|
+
#
|
|
7
|
+
# Usage in views:
|
|
8
|
+
# <%= opal_javascript_tag "application" %>
|
|
9
|
+
#
|
|
10
|
+
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
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Generate multiple script tags for Opal JavaScript files
|
|
22
|
+
#
|
|
23
|
+
# Usage:
|
|
24
|
+
# <%= opal_javascript_tags "application", "components/widget" %>
|
|
25
|
+
#
|
|
26
|
+
def opal_javascript_tags(*names, **options)
|
|
27
|
+
safe_join(names.map { |name| opal_javascript_tag(name, **options) }, "\n")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Check if Vite dev server is running
|
|
31
|
+
def vite_running?
|
|
32
|
+
defined?(ViteRuby) && ViteRuby.instance.dev_server_running?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Get asset path from Vite manifest
|
|
36
|
+
def opal_asset_path(name)
|
|
37
|
+
if defined?(ViteRuby)
|
|
38
|
+
ViteRuby.manifest.lookup(name).to_s
|
|
39
|
+
else
|
|
40
|
+
# Fallback to standard asset path
|
|
41
|
+
"/#{Opal::Vite::Rails.config.public_output_path}/#{name}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Include Opal runtime
|
|
46
|
+
# This is automatically included when using opal_javascript_tag,
|
|
47
|
+
# but can be called explicitly if needed
|
|
48
|
+
def opal_runtime_tag(**options)
|
|
49
|
+
if vite_running?
|
|
50
|
+
vite_javascript_tag("@opal-runtime", **options)
|
|
51
|
+
else
|
|
52
|
+
asset_path = opal_asset_path("opal-runtime.js")
|
|
53
|
+
javascript_include_tag(asset_path, **options)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
module Opal
|
|
4
|
+
module Vite
|
|
5
|
+
module Rails
|
|
6
|
+
class Manifest
|
|
7
|
+
def initialize(manifest_path = nil)
|
|
8
|
+
@manifest_path = manifest_path || default_manifest_path
|
|
9
|
+
@data = load_manifest
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def lookup(name)
|
|
13
|
+
# Try exact match first
|
|
14
|
+
entry = @data[name]
|
|
15
|
+
return entry if entry
|
|
16
|
+
|
|
17
|
+
# Try with .rb extension
|
|
18
|
+
entry = @data["#{name}.rb"]
|
|
19
|
+
return entry if entry
|
|
20
|
+
|
|
21
|
+
# Try without extension
|
|
22
|
+
name_without_ext = name.sub(/\.(rb|js)$/, '')
|
|
23
|
+
entry = @data[name_without_ext]
|
|
24
|
+
return entry if entry
|
|
25
|
+
|
|
26
|
+
# Not found
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def [](name)
|
|
31
|
+
entry = lookup(name)
|
|
32
|
+
entry && entry['file']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def reload!
|
|
36
|
+
@data = load_manifest
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def default_manifest_path
|
|
42
|
+
if defined?(::Rails)
|
|
43
|
+
::Rails.public_path.join('vite', 'manifest.json')
|
|
44
|
+
else
|
|
45
|
+
'public/vite/manifest.json'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def load_manifest
|
|
50
|
+
return {} unless File.exist?(@manifest_path)
|
|
51
|
+
|
|
52
|
+
JSON.parse(File.read(@manifest_path))
|
|
53
|
+
rescue JSON::ParserError => e
|
|
54
|
+
warn "Failed to parse Vite manifest at #{@manifest_path}: #{e.message}"
|
|
55
|
+
{}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "opal-vite"
|
|
2
|
+
require "rails"
|
|
3
|
+
require "vite_rails"
|
|
4
|
+
|
|
5
|
+
require_relative "opal/vite/rails/version"
|
|
6
|
+
require_relative "opal/vite/rails/engine"
|
|
7
|
+
require_relative "opal/vite/rails/helper"
|
|
8
|
+
require_relative "opal/vite/rails/manifest"
|
|
9
|
+
|
|
10
|
+
module Opal
|
|
11
|
+
module Vite
|
|
12
|
+
module Rails
|
|
13
|
+
class Error < StandardError; end
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
attr_accessor :config
|
|
17
|
+
|
|
18
|
+
def configure
|
|
19
|
+
yield(config) if block_given?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
@config = OpenStruct.new(
|
|
24
|
+
# Default configuration
|
|
25
|
+
source_path: "app/opal",
|
|
26
|
+
public_output_path: "vite-opal",
|
|
27
|
+
manifest_path: nil # Will be set by ViteRails
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
namespace :opal_vite do
|
|
2
|
+
desc "Compile Opal assets for production"
|
|
3
|
+
task compile: :environment do
|
|
4
|
+
require "opal/vite/rails"
|
|
5
|
+
|
|
6
|
+
puts "Compiling Opal assets..."
|
|
7
|
+
|
|
8
|
+
# Ensure Vite is installed
|
|
9
|
+
unless system("which vite > /dev/null 2>&1")
|
|
10
|
+
puts "Error: Vite is not installed. Run 'npm install' first."
|
|
11
|
+
exit 1
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Run Vite build
|
|
15
|
+
puts "Running Vite build..."
|
|
16
|
+
system("npm run build") || system("npx vite build")
|
|
17
|
+
|
|
18
|
+
puts "✅ Opal assets compiled successfully!"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc "Clean compiled Opal assets"
|
|
22
|
+
task clean: :environment do
|
|
23
|
+
require "opal/vite/rails"
|
|
24
|
+
|
|
25
|
+
puts "Cleaning Opal assets..."
|
|
26
|
+
|
|
27
|
+
vite_dir = Rails.public_path.join("vite")
|
|
28
|
+
if vite_dir.exist?
|
|
29
|
+
FileUtils.rm_rf(vite_dir)
|
|
30
|
+
puts "✅ Cleaned #{vite_dir}"
|
|
31
|
+
else
|
|
32
|
+
puts "No compiled assets found"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
desc "Show Opal-Vite configuration"
|
|
37
|
+
task info: :environment do
|
|
38
|
+
require "opal/vite/rails"
|
|
39
|
+
|
|
40
|
+
puts "\n" + "="*60
|
|
41
|
+
puts "Opal-Vite Rails Configuration"
|
|
42
|
+
puts "="*60
|
|
43
|
+
|
|
44
|
+
puts "\nOpal-Vite version: #{Opal::Vite::VERSION}"
|
|
45
|
+
puts "Rails root: #{Rails.root}"
|
|
46
|
+
puts "Vite manifest: #{Rails.public_path.join('vite', 'manifest.json')}"
|
|
47
|
+
puts "Opal source directory: #{Rails.root.join('app', 'opal')}"
|
|
48
|
+
|
|
49
|
+
if defined?(ViteRuby)
|
|
50
|
+
puts "\nViteRuby: Installed ✅"
|
|
51
|
+
puts "Vite dev server: #{ViteRuby.config.host}:#{ViteRuby.config.port}"
|
|
52
|
+
else
|
|
53
|
+
puts "\nViteRuby: Not installed ⚠️"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
puts "\n" + "="*60
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Add compile task to assets:precompile
|
|
61
|
+
if Rake::Task.task_defined?("assets:precompile")
|
|
62
|
+
Rake::Task["assets:precompile"].enhance do
|
|
63
|
+
Rake::Task["opal_vite:compile"].invoke
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Opal application entry point
|
|
2
|
+
# This file is compiled to JavaScript and loaded in your Rails views
|
|
3
|
+
|
|
4
|
+
puts "🚀 Opal application loaded!"
|
|
5
|
+
puts "RUBY_VERSION: #{RUBY_VERSION}"
|
|
6
|
+
puts "RUBY_PLATFORM: #{RUBY_PLATFORM}"
|
|
7
|
+
|
|
8
|
+
# Example: DOM manipulation
|
|
9
|
+
require 'native'
|
|
10
|
+
|
|
11
|
+
# Wait for DOM to load
|
|
12
|
+
`
|
|
13
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
14
|
+
console.log('✅ Opal is running in Rails!');
|
|
15
|
+
|
|
16
|
+
// Example: Add content to the page
|
|
17
|
+
const content = document.getElementById('opal-content');
|
|
18
|
+
if (content) {
|
|
19
|
+
const p = document.createElement('p');
|
|
20
|
+
p.textContent = 'This content was added by Ruby code running in the browser!';
|
|
21
|
+
p.style.color = '#CC342D';
|
|
22
|
+
p.style.fontWeight = 'bold';
|
|
23
|
+
content.appendChild(p);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
puts "✅ Opal application initialized"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import RubyPlugin from 'vite_ruby/plugins/ruby'
|
|
3
|
+
import opal from 'vite-plugin-opal'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [
|
|
7
|
+
RubyPlugin(),
|
|
8
|
+
opal({
|
|
9
|
+
loadPaths: ['./app/opal'],
|
|
10
|
+
sourceMap: true,
|
|
11
|
+
debug: process.env.NODE_ENV === 'development'
|
|
12
|
+
})
|
|
13
|
+
],
|
|
14
|
+
build: {
|
|
15
|
+
manifest: true,
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
input: {
|
|
18
|
+
'application': './app/opal/application_loader.js'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
metadata
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: opal-vite-rails
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.13
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- stofu1234
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: opal-vite
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.2.13
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.2.13
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: railties
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 6.0.0
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 6.0.0
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: actionview
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 6.0.0
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 6.0.0
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: vite_rails
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '3.0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: bundler
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '2.0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2.0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: rake
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '13.0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '13.0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rspec
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '3.12'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '3.12'
|
|
110
|
+
description: Seamlessly integrate Opal (Ruby to JavaScript compiler) with Rails using
|
|
111
|
+
Vite for fast development
|
|
112
|
+
email:
|
|
113
|
+
- ''
|
|
114
|
+
executables: []
|
|
115
|
+
extensions: []
|
|
116
|
+
extra_rdoc_files: []
|
|
117
|
+
files:
|
|
118
|
+
- README.md
|
|
119
|
+
- lib/opal-vite-rails.rb
|
|
120
|
+
- lib/opal/vite/rails/engine.rb
|
|
121
|
+
- lib/opal/vite/rails/generators/install_generator.rb
|
|
122
|
+
- lib/opal/vite/rails/helper.rb
|
|
123
|
+
- lib/opal/vite/rails/manifest.rb
|
|
124
|
+
- lib/opal/vite/rails/version.rb
|
|
125
|
+
- lib/tasks/opal_vite.rake
|
|
126
|
+
- templates/application.rb.tt
|
|
127
|
+
- templates/application_loader.js.tt
|
|
128
|
+
- templates/vite.config.ts.tt
|
|
129
|
+
homepage: https://stofu1234.github.io/opal-vite/
|
|
130
|
+
licenses:
|
|
131
|
+
- MIT
|
|
132
|
+
metadata:
|
|
133
|
+
homepage_uri: https://stofu1234.github.io/opal-vite/
|
|
134
|
+
source_code_uri: https://stofu1234.github.io/opal-vite/
|
|
135
|
+
rdoc_options: []
|
|
136
|
+
require_paths:
|
|
137
|
+
- lib
|
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
|
+
requirements:
|
|
140
|
+
- - ">="
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: 2.7.0
|
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
|
+
requirements:
|
|
145
|
+
- - ">="
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: '0'
|
|
148
|
+
requirements: []
|
|
149
|
+
rubygems_version: 3.6.9
|
|
150
|
+
specification_version: 4
|
|
151
|
+
summary: Rails integration for Opal with Vite
|
|
152
|
+
test_files: []
|