opal-rails 2.0.4 → 3.0.0
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/.github/workflows/build.yml +39 -4
- data/.gitignore +2 -0
- data/Appraisals +20 -21
- data/CHANGELOG.md +30 -0
- data/Gemfile +2 -2
- data/PORTING.md +140 -0
- data/README.md +150 -87
- data/Rakefile +16 -2
- data/app/helpers/opal_helper.rb +9 -28
- data/bin/sandbox +3 -2
- data/bin/sandbox-setup +2 -0
- data/gemfiles/{rails_7_0_opal_1_0.gemfile → rails_7_0_opal_1_8.gemfile} +2 -2
- data/gemfiles/{rails_7_0_opal_1_3.gemfile → rails_7_0_opal_master.gemfile} +2 -2
- data/gemfiles/{rails_6_0_opal_1_0.gemfile → rails_8_0_opal_1_8.gemfile} +3 -3
- data/gemfiles/rails_8_0_opal_master.gemfile +10 -0
- data/gemfiles/{rails_6_1_opal_1_0.gemfile → rails_8_1_opal_1_8.gemfile} +3 -3
- data/gemfiles/rails_8_1_opal_master.gemfile +10 -0
- data/lib/generators/opal/assets/assets_generator.rb +11 -1
- data/lib/generators/opal/assets/templates/{javascript.js.rb → asset.rb.tt} +3 -6
- data/lib/generators/opal/install/install_generator.rb +160 -9
- data/lib/generators/opal/install/templates/{application.js.rb → application.rb} +4 -4
- data/lib/generators/opal/install/templates/dev.tt +8 -0
- data/lib/generators/opal/install/templates/{initializer.rb → initializer.rb.tt} +8 -0
- data/lib/opal/rails/builder_runner.rb +126 -0
- data/lib/opal/rails/engine.rb +11 -9
- data/lib/opal/rails/entrypoints_resolver.rb +81 -0
- data/lib/opal/rails/errors.rb +11 -0
- data/lib/opal/rails/file_watcher.rb +58 -0
- data/lib/opal/rails/haml6_filter.rb +6 -6
- data/lib/opal/rails/haml_filter.rb +3 -6
- data/lib/opal/rails/legacy_upgrade_warning.rb +95 -0
- data/lib/opal/rails/outputs_manifest.rb +82 -0
- data/lib/opal/rails/path_setup.rb +28 -0
- data/lib/opal/rails/task_hooks.rb +49 -0
- data/lib/opal/rails/version.rb +1 -1
- data/lib/opal/rails/watch_runner.rb +173 -0
- data/lib/opal/rails.rb +7 -0
- data/lib/tasks/opal.rake +48 -0
- data/opal-rails.gemspec +23 -14
- data/spec/end_to_end/full_lifecycle_spec.rb +377 -0
- data/spec/helpers/opal_helper_spec.rb +27 -34
- data/spec/integration/source_map_spec.rb +6 -8
- data/spec/opal/assets_generator_spec.rb +31 -0
- data/spec/opal/install_generator_spec.rb +140 -0
- data/spec/opal/rails/build_task_spec.rb +116 -0
- data/spec/opal/rails/builder_runner_spec.rb +151 -0
- data/spec/opal/rails/clobber_task_spec.rb +55 -0
- data/spec/opal/rails/entrypoints_resolver_spec.rb +50 -0
- data/spec/opal/rails/haml_filter_spec.rb +41 -0
- data/spec/opal/rails/legacy_upgrade_warning_spec.rb +94 -0
- data/spec/opal/rails/outputs_manifest_spec.rb +44 -0
- data/spec/opal/rails/path_setup_spec.rb +71 -0
- data/spec/opal/rails/task_hooks_spec.rb +61 -0
- data/spec/opal/rails/watch_runner_spec.rb +283 -0
- data/spec/opal/rails/watch_task_spec.rb +23 -0
- data/spec/spec_helper.rb +16 -7
- data/spec/support/browser_support_spec.rb +36 -0
- data/spec/support/capybara.rb +61 -0
- data/spec/support/reset_assets_cache.rb +9 -1
- data/spec/support/test_app.rb +23 -2
- data/test_apps/app/application_controller.rb +23 -32
- data/test_apps/app/assets/builds/.keep +0 -0
- data/test_apps/app/assets/config/manifest.js +3 -1
- data/test_apps/app/assets/images/.keep +0 -0
- data/test_apps/app/opal/application.rb +5 -0
- data/test_apps/app/{assets/javascripts/source_map_example.js.rb → opal/source_map_example.rb} +1 -2
- data/test_apps/app/opal/with_assignments.js.rb +8 -0
- data/test_apps/rails.rb +19 -5
- metadata +196 -50
- data/gemfiles/rails_6_0_opal_1_1.gemfile +0 -9
- data/gemfiles/rails_6_0_opal_1_3.gemfile +0 -10
- data/gemfiles/rails_6_0_opal_1_7.gemfile +0 -10
- data/gemfiles/rails_6_1_opal_1_1.gemfile +0 -9
- data/gemfiles/rails_6_1_opal_1_3.gemfile +0 -10
- data/gemfiles/rails_6_1_opal_1_7.gemfile +0 -10
- data/gemfiles/rails_7_0_opal_1_7.gemfile +0 -10
- data/lib/opal/rails/haml5_filter.rb +0 -28
- data/test_apps/app/assets/javascripts/application.js.rb +0 -7
- data/test_apps/app/assets/javascripts/bar.rb +0 -3
- data/test_apps/app/assets/javascripts/foo.js.rb +0 -3
data/README.md
CHANGED
|
@@ -8,12 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
_Rails bindings for [Opal](http://opalrb.com). ([Changelog](https://github.com/opal/opal-rails/blob/master/CHANGELOG.md))_
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
If you want to integrate Opal via Webpack please refer to [opal-webpack-loader](https://github.com/isomorfeus/opal-webpack-loader#installation) installation instructions.
|
|
14
|
-
|
|
15
|
-
ℹ️ Webpack and ES6 modules are not yet officially supported, but we're working on it thanks to the awesome work done in _opal-webpack-loader_.
|
|
16
|
-
|
|
11
|
+
If you are upgrading an existing app, see [`PORTING.md`](PORTING.md) for a focused 2.x -> 3.x migration guide.
|
|
17
12
|
|
|
18
13
|
## Installation
|
|
19
14
|
|
|
@@ -23,12 +18,35 @@ In your `Gemfile`
|
|
|
23
18
|
gem 'opal-rails'
|
|
24
19
|
```
|
|
25
20
|
|
|
26
|
-
|
|
21
|
+
`opal-rails` is tested against Rails 7.0, 8.0, and 8.1 with Opal 1.8 and Opal master (`2.0dev`) on Ruby 3.2 and 4.0. It requires Opal 1.7.0+ for the builder/watch dependency APIs it uses. Rails 6.x is no longer supported, Rails 7.1/7.2 do not have dedicated appraisal coverage, and Rails 8 requires Ruby 3.2+.
|
|
22
|
+
|
|
23
|
+
Run the `opal:install` Rails generator to create a build-based Opal setup:
|
|
27
24
|
|
|
28
25
|
```
|
|
29
26
|
bin/rails g opal:install
|
|
30
27
|
```
|
|
31
28
|
|
|
29
|
+
The generator now creates:
|
|
30
|
+
|
|
31
|
+
- `app/opal/application.rb` for greenfield apps, or reuses `app/assets/opal` when migrating an older layout
|
|
32
|
+
- `config/initializers/opal.rb` with build-oriented defaults
|
|
33
|
+
- `app/assets/builds/.keep`
|
|
34
|
+
- a `Procfile.dev` entry for `opal: bin/rails opal:watch`
|
|
35
|
+
- a `bin/dev` launcher when the app does not already have one
|
|
36
|
+
- for Sprockets apps, `app/assets/config/manifest.js` links for `app/assets/builds`
|
|
37
|
+
- for Sprockets test environments, `config.assets.debug = true` in `config/environments/test.rb` so rebuilt assets win over stale checked-in digests
|
|
38
|
+
|
|
39
|
+
For already-installed 2.x apps, do not treat `bin/rails g opal:install` as a drop-in migration step. Follow [`PORTING.md`](PORTING.md) instead, and pin `opal-rails` to the `2.0` series until you are ready to port the app deliberately.
|
|
40
|
+
|
|
41
|
+
`bin/dev` is a small Foreman launcher for `Procfile.dev`; the generated script installs the `foreman` gem if it is missing and then starts both Rails and `opal:watch` together.
|
|
42
|
+
|
|
43
|
+
If the generator finds an existing multi-entrypoint Opal source root, it keeps that layout intact, configures `config.opal.entrypoints = :all`, and avoids inserting a default `javascript_include_tag "application"` when no `application.rb` entrypoint exists.
|
|
44
|
+
|
|
45
|
+
If the host app already has a non-Opal `application.js`, the generator keeps `app/opal/application.rb` as the source file but configures the built logical asset name as `opal` so the two pipelines do not collide.
|
|
46
|
+
|
|
47
|
+
It no longer depends on `opal-sprockets` or a Sprockets-specific helper loader at runtime.
|
|
48
|
+
The `opal:assets` generator now writes plain `.rb` files into the active Opal source root instead of generating `app/assets/javascripts/*.js.rb` files.
|
|
49
|
+
|
|
32
50
|
|
|
33
51
|
### Configuration
|
|
34
52
|
|
|
@@ -51,6 +69,99 @@ end
|
|
|
51
69
|
|
|
52
70
|
Check out the full list of the available configuration options at: [lib/opal/config.rb](https://github.com/opal/opal/blob/master/lib/opal/config.rb).
|
|
53
71
|
|
|
72
|
+
### Build-based assets
|
|
73
|
+
|
|
74
|
+
`opal-rails` now also exposes an explicit build task for modern Rails-style asset generation.
|
|
75
|
+
|
|
76
|
+
The host Rails app is still responsible for choosing an asset server such as Propshaft or Sprockets to serve the built files from `app/assets/builds`.
|
|
77
|
+
|
|
78
|
+
Current build-oriented config keys are:
|
|
79
|
+
|
|
80
|
+
```ruby
|
|
81
|
+
Rails.application.configure do
|
|
82
|
+
config.opal.source_path = Rails.root.join('app/opal')
|
|
83
|
+
config.opal.entrypoints_path = config.opal.source_path
|
|
84
|
+
config.opal.build_path = Rails.root.join('app/assets/builds')
|
|
85
|
+
config.opal.entrypoints = { 'application' => 'application.rb' }
|
|
86
|
+
config.opal.append_paths = []
|
|
87
|
+
config.opal.use_gems = []
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For mixed-stack apps that already use another `application.js`, use an explicit logical name for the Opal output instead of colliding with the existing asset:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
Rails.application.configure do
|
|
95
|
+
config.opal.source_path = Rails.root.join('app/opal')
|
|
96
|
+
config.opal.entrypoints_path = config.opal.source_path
|
|
97
|
+
config.opal.entrypoints = { 'opal' => 'application.rb' }
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
With that in place, you can build Opal entrypoints into browser-ready assets with:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bin/rails opal:build
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`opal-rails` also hooks `opal:build` into `assets:precompile` automatically, and into `test:prepare` / `spec:prepare` when those tasks exist in the host app.
|
|
108
|
+
|
|
109
|
+
And clean only Opal-owned build outputs with:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
bin/rails opal:clobber
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
To rebuild entrypoints while you develop, run:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
bin/rails opal:watch
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This writes `*.js` outputs, optional `*.js.map` files, and an Opal-owned manifest into `app/assets/builds`.
|
|
122
|
+
|
|
123
|
+
`opal:clobber` uses that manifest to remove only Opal-tracked outputs, leaving unrelated assets in `app/assets/builds` alone.
|
|
124
|
+
|
|
125
|
+
`opal:watch` uses the `listen` gem, tracks Opal/core and app dependency files, rebuilds affected entrypoints for known file changes, and falls back to a full rebuild when files are added or removed.
|
|
126
|
+
|
|
127
|
+
Any directories listed in `config.opal.append_paths` are also part of that watch scope, so shared templates or support files can trigger rebuilds too.
|
|
128
|
+
|
|
129
|
+
Include the built entrypoint in your layout with the normal Rails helper:
|
|
130
|
+
|
|
131
|
+
```erb
|
|
132
|
+
<%= javascript_include_tag "application", "data-turbo-track": "reload" %>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Boot code should live in the built Opal entrypoint itself rather than in a helper-side loader shim.
|
|
136
|
+
|
|
137
|
+
If you are migrating an app that already keeps frontend Ruby under `app/assets/opal`, set `config.opal.source_path` and `config.opal.entrypoints_path` to that directory instead. If your asset server would otherwise expose raw files from that directory, exclude it in the host app configuration yourself. For example, Propshaft apps can add `config.assets.excluded_paths << Rails.root.join('app/assets/opal')`. Apps using the default `app/opal` layout do not need this.
|
|
138
|
+
|
|
139
|
+
For the default `app/opal` layout, `opal-rails` also ignores that source root in Rails autoloaders so frontend Opal files are not treated as application constants.
|
|
140
|
+
|
|
141
|
+
If you want one built asset per top-level Opal file, you can opt into bulk entrypoint discovery:
|
|
142
|
+
|
|
143
|
+
```ruby
|
|
144
|
+
Rails.application.configure do
|
|
145
|
+
config.opal.source_path = Rails.root.join('app/assets/opal')
|
|
146
|
+
config.opal.entrypoints_path = config.opal.source_path
|
|
147
|
+
config.opal.entrypoints = :all
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
In `:all` mode, `opal-rails` compiles each top-level `*.rb` file in `entrypoints_path` to a same-name asset in `app/assets/builds`, ignores nested support files, and prunes stale Opal-owned outputs when an entrypoint file disappears.
|
|
152
|
+
|
|
153
|
+
The install generator will choose that `:all` configuration automatically for migration-friendly layouts that already have multiple top-level Opal entrypoints.
|
|
154
|
+
|
|
155
|
+
If you want to generate a controller-specific Opal file, use:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
bin/rails g opal:assets dashboard
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This now creates `app/opal/dashboard.rb` by default, or `app/assets/opal/dashboard.rb` for migration-friendly layouts.
|
|
162
|
+
|
|
163
|
+
The bundled test app and integration suite prebuild assets from `app/opal` into `app/assets/builds` instead of relying on `app/assets/javascripts/*.js.rb` request-time compilation.
|
|
164
|
+
|
|
54
165
|
#### For template assigns
|
|
55
166
|
|
|
56
167
|
You may optionally add configuration for rendering assigns when using the template handler from actions:
|
|
@@ -80,7 +191,7 @@ This example assumes Rails 7 and having followed the [Installation](#installatio
|
|
|
80
191
|
|
|
81
192
|
1- Delete `app/javascript/application.js`
|
|
82
193
|
|
|
83
|
-
2- Enable the following lines in the generated `app/
|
|
194
|
+
2- Enable the following lines in the generated `app/opal/application.rb` below `require "opal"`:
|
|
84
195
|
|
|
85
196
|
```ruby
|
|
86
197
|
puts "hello world!"
|
|
@@ -96,9 +207,11 @@ end
|
|
|
96
207
|
|
|
97
208
|
5- Clear `app/views/welcomes/index.html.erb` (empty its content)
|
|
98
209
|
|
|
99
|
-
6- Run `rails
|
|
210
|
+
6- Run `bin/rails opal:build`
|
|
211
|
+
|
|
212
|
+
7- Run `rails s`
|
|
100
213
|
|
|
101
|
-
|
|
214
|
+
8- Visit `http://localhost:3000/welcomes`
|
|
102
215
|
|
|
103
216
|
In the browser webpage, you should see:
|
|
104
217
|
|
|
@@ -106,79 +219,22 @@ In the browser webpage, you should see:
|
|
|
106
219
|
|
|
107
220
|
Also, you should see `hello world!` in the browser console.
|
|
108
221
|
|
|
109
|
-
####
|
|
222
|
+
#### Migrating older Sprockets-style apps
|
|
110
223
|
|
|
111
|
-
|
|
224
|
+
Older `opal-rails` apps often used `app/assets/javascripts/application.js.rb`, `manifest.js`, and request-time Sprockets compilation.
|
|
112
225
|
|
|
113
|
-
|
|
114
|
-
2. Replace the Sprockets directives with plain requires
|
|
226
|
+
See [`PORTING.md`](PORTING.md) for the full 2.x -> 3.x checklist.
|
|
115
227
|
|
|
116
|
-
|
|
117
|
-
# Require the opal runtime and core library
|
|
118
|
-
require 'opal'
|
|
228
|
+
The build-first migration path is:
|
|
119
229
|
|
|
120
|
-
|
|
121
|
-
|
|
230
|
+
1. move the Opal entrypoint to `app/opal/application.rb` or keep `app/assets/opal/application.rb` for migration-friendly layouts;
|
|
231
|
+
2. configure `config.opal.source_path`, `config.opal.entrypoints_path`, and `config.opal.entrypoints` in `config/initializers/opal.rb`;
|
|
232
|
+
3. build with `bin/rails opal:build` and watch with `bin/rails opal:watch`;
|
|
233
|
+
4. include the built asset with the normal `javascript_include_tag` helper.
|
|
122
234
|
|
|
123
|
-
|
|
124
|
-
require 'turbolinks'
|
|
235
|
+
The documented path no longer relies on Sprockets directives such as `require_tree` or on helper-level Opal loader injection.
|
|
125
236
|
|
|
126
|
-
|
|
127
|
-
require_tree '.'
|
|
128
|
-
|
|
129
|
-
puts "hello world!"
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
#### A more extensive Rails 5 example
|
|
133
|
-
|
|
134
|
-
```ruby
|
|
135
|
-
require 'opal'
|
|
136
|
-
require 'opal_ujs'
|
|
137
|
-
require 'turbolinks'
|
|
138
|
-
require_tree '.' # a Ruby equivalent of the require_tree Sprockets directive is available
|
|
139
|
-
|
|
140
|
-
# ---- YOUR FANCY RUBY CODE HERE ----
|
|
141
|
-
#
|
|
142
|
-
# Examples:
|
|
143
|
-
|
|
144
|
-
# == Print something in the browser's console
|
|
145
|
-
puts "Hello world!"
|
|
146
|
-
pp hello: :world
|
|
147
|
-
require 'console'
|
|
148
|
-
$console.log %w[Hello world!]
|
|
149
|
-
|
|
150
|
-
# == Use Native to wrap native JS objects, $$ is preconfigured to wrap `window`
|
|
151
|
-
require 'native'
|
|
152
|
-
$$.alert "Hello world!"
|
|
153
|
-
|
|
154
|
-
# == Do some DOM manipulation with jQuery
|
|
155
|
-
require 'opal-jquery'
|
|
156
|
-
Document.ready? do
|
|
157
|
-
Element.find('body').html = '<h1>Hello world!</h1>'
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# == Or access the DOM api directly
|
|
161
|
-
$$[:document].addEventListener(:DOMContentLoaded, -> {
|
|
162
|
-
$$[:document].querySelector('body')[:innerHTML] = '<h1>Hello world!</h1>'
|
|
163
|
-
})
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
### Using Sprockets directives and `application.js`
|
|
169
|
-
|
|
170
|
-
If you want to use `application.js` (instead of `application.js.rb`) and keep using Sprockets directives, you'll need to load the Opal files you require via Sprockets manually, e.g.:
|
|
171
|
-
|
|
172
|
-
```js
|
|
173
|
-
//= require opal
|
|
174
|
-
//= require rails_ujs
|
|
175
|
-
//= require turbolinks
|
|
176
|
-
//= require_tree .
|
|
177
|
-
//= require app
|
|
178
|
-
|
|
179
|
-
Opal.require('opal');
|
|
180
|
-
Opal.require('app');
|
|
181
|
-
```
|
|
237
|
+
If the host app itself still uses Sprockets during migration, it can keep the minimal manifest entries needed to serve the built files, but `opal-rails` itself no longer requires `opal-sprockets` to compile or boot Opal assets.
|
|
182
238
|
|
|
183
239
|
|
|
184
240
|
### As a template
|
|
@@ -209,7 +265,7 @@ post.find('.comments').html = comments_html
|
|
|
209
265
|
|
|
210
266
|
By default `opal-rails`, will NOT forward any instance and local variable you'll pass to the template.
|
|
211
267
|
|
|
212
|
-
This behavior can be enabled by setting `Rails.application.config.opal.assigns_in_templates` to `true` in `config/initializers/
|
|
268
|
+
This behavior can be enabled by setting `Rails.application.config.opal.assigns_in_templates` to `true` in `config/initializers/opal.rb`:
|
|
213
269
|
|
|
214
270
|
```ruby
|
|
215
271
|
Rails.application.configure do
|
|
@@ -223,7 +279,7 @@ end
|
|
|
223
279
|
|
|
224
280
|
### As a Haml filter (optional)
|
|
225
281
|
|
|
226
|
-
|
|
282
|
+
Require `haml-rails` separately if you want to use Haml. `opal-rails` supports the optional `:opal` Haml filter on Haml 6 and newer only!
|
|
227
283
|
|
|
228
284
|
```haml
|
|
229
285
|
-# app/views/posts/show.html.haml
|
|
@@ -267,7 +323,7 @@ _Upcoming as `opal-minitest-rails`_
|
|
|
267
323
|
|
|
268
324
|
### Shared templates
|
|
269
325
|
|
|
270
|
-
As long as the templates are inside
|
|
326
|
+
As long as the templates are inside an Opal load path, you should be able to require them.
|
|
271
327
|
|
|
272
328
|
Let's say we have this template `app/views/shared/test.haml`:
|
|
273
329
|
|
|
@@ -277,17 +333,17 @@ Let's say we have this template `app/views/shared/test.haml`:
|
|
|
277
333
|
= @bar
|
|
278
334
|
```
|
|
279
335
|
|
|
280
|
-
We need to make sure Opal can see and compile that template.
|
|
336
|
+
We need to make sure Opal can see and compile that template. Add the path to `config.opal.append_paths`:
|
|
281
337
|
|
|
282
338
|
```ruby
|
|
283
339
|
# config/initializers/opal.rb
|
|
284
|
-
Rails.application.config.
|
|
340
|
+
Rails.application.config.opal.append_paths << Rails.root.join('app', 'views', 'shared')
|
|
285
341
|
```
|
|
286
342
|
|
|
287
343
|
Now, somewhere in `application.rb` you need to require that template, and you can just run it through `Template`:
|
|
288
344
|
|
|
289
345
|
```ruby
|
|
290
|
-
# app/
|
|
346
|
+
# app/opal/application.rb
|
|
291
347
|
require 'opal'
|
|
292
348
|
require 'opal-haml'
|
|
293
349
|
require 'test'
|
|
@@ -302,14 +358,16 @@ template.render(self)
|
|
|
302
358
|
|
|
303
359
|
### Using Ruby gems from Opal
|
|
304
360
|
|
|
305
|
-
|
|
361
|
+
Add gems to the Opal load path from `config/initializers/opal.rb`.
|
|
306
362
|
|
|
307
363
|
Example:
|
|
308
364
|
|
|
309
365
|
```ruby
|
|
310
|
-
|
|
366
|
+
Rails.application.config.opal.use_gems << 'cannonbol'
|
|
311
367
|
```
|
|
312
368
|
|
|
369
|
+
Both `opal:build` and `opal:watch` apply `config.opal.use_gems` and `config.opal.append_paths` when creating builders, so the same load-path behavior is used in direct builds, watch-mode rebuilds, and precompile hooks.
|
|
370
|
+
|
|
313
371
|
|
|
314
372
|
## Contributing
|
|
315
373
|
|
|
@@ -320,6 +378,10 @@ bin/setup
|
|
|
320
378
|
bin/rake
|
|
321
379
|
```
|
|
322
380
|
|
|
381
|
+
`bin/rake` now runs the non-JS and browser-driven specs in separate RSpec phases so each browser pass starts from a fresh process.
|
|
382
|
+
|
|
383
|
+
Browser-driven specs auto-detect a usable local Chrome/Chromium binary, including Fedora's headless Chromium shell path when it is installed but not on `PATH`, and only skip when no supported browser binary can be found.
|
|
384
|
+
|
|
323
385
|
Inspect the test app:
|
|
324
386
|
|
|
325
387
|
```
|
|
@@ -330,8 +392,9 @@ bin/rackup
|
|
|
330
392
|
Tinker with a sandbox app:
|
|
331
393
|
|
|
332
394
|
```
|
|
333
|
-
bin/sandbox #
|
|
334
|
-
bin/rails s #
|
|
395
|
+
bin/sandbox # re-creates the app, installs opal-rails, and runs an initial opal:build
|
|
396
|
+
bin/rails s # starts the sandbox app server
|
|
397
|
+
# or run bin/rails opal:watch in another shell while you edit Opal source files
|
|
335
398
|
# visit localhost:3000
|
|
336
399
|
```
|
|
337
400
|
|
data/Rakefile
CHANGED
|
@@ -10,6 +10,20 @@ Bundler::GemHelper.install_tasks
|
|
|
10
10
|
# TEST
|
|
11
11
|
|
|
12
12
|
require 'rspec/core/rake_task'
|
|
13
|
-
RSpec::Core::RakeTask.new :rspec
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
RSpec::Core::RakeTask.new('spec:non_js') do |task|
|
|
15
|
+
task.rspec_opts = '--tag ~js --tag ~e2e'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
RSpec::Core::RakeTask.new('spec:js') do |task|
|
|
19
|
+
task.rspec_opts = '--tag js'
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
RSpec::Core::RakeTask.new('spec:e2e') do |task|
|
|
23
|
+
task.rspec_opts = '--tag e2e'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
task spec: ['spec:non_js', 'spec:js']
|
|
27
|
+
task rspec: :spec
|
|
28
|
+
|
|
29
|
+
task default: :spec
|
data/app/helpers/opal_helper.rb
CHANGED
|
@@ -1,34 +1,15 @@
|
|
|
1
|
-
require 'opal/sprockets'
|
|
2
|
-
|
|
3
1
|
module OpalHelper
|
|
4
|
-
def opal_tag(
|
|
5
|
-
|
|
2
|
+
def opal_tag(opal_code_or_options = nil, html_options = {}, &block)
|
|
3
|
+
if block_given?
|
|
4
|
+
html_options = opal_code_or_options if opal_code_or_options.is_a?(Hash)
|
|
5
|
+
opal_code_or_options = capture(&block)
|
|
6
|
+
end
|
|
7
|
+
|
|
6
8
|
compiler_options = Opal::Config.compiler_options.merge(requirable: false)
|
|
7
|
-
compiler = Opal::Compiler.new(
|
|
9
|
+
compiler = Opal::Compiler.new(opal_code_or_options, compiler_options)
|
|
8
10
|
js_code = compiler.compile
|
|
9
|
-
javascript_tag
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def javascript_include_tag(*sources)
|
|
13
|
-
options = sources.extract_options!.symbolize_keys
|
|
14
|
-
debug = options[:debug] != false
|
|
15
|
-
skip_loader = options.delete(:skip_opal_loader)
|
|
16
|
-
force_opal_loader_tag = options.delete(:force_opal_loader_tag) || debug
|
|
17
|
-
|
|
18
|
-
return super(*sources, options) if skip_loader && !force_opal_loader_tag
|
|
19
|
-
|
|
20
|
-
script_tags = "".html_safe
|
|
21
|
-
sources.each do |source|
|
|
22
|
-
load_asset_code = Opal::Sprockets.load_asset(source)
|
|
23
|
-
loading_code = "if(window.Opal && Opal.modules[#{source.to_json}]){#{load_asset_code}}"
|
|
24
|
-
|
|
25
|
-
if force_opal_loader_tag
|
|
26
|
-
script_tags << super(source, options)
|
|
27
|
-
script_tags << "\n".html_safe + javascript_tag(loading_code)
|
|
28
|
-
else
|
|
29
|
-
script_tags << super(source, options.merge(onload: loading_code))
|
|
30
|
-
end
|
|
11
|
+
javascript_tag html_options do
|
|
12
|
+
js_code.html_safe
|
|
31
13
|
end
|
|
32
|
-
script_tags
|
|
33
14
|
end
|
|
34
15
|
end
|
data/bin/sandbox
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
IFS=$'\n\t'
|
|
5
|
+
|
|
3
6
|
gem_name="$(ruby -rpathname -e"puts Pathname(ARGV.first).join('../..').expand_path.glob('*.gemspec').first.basename('.gemspec')" -- $0)"
|
|
4
7
|
|
|
5
8
|
# Stay away from the bundler env of the containing extension.
|
|
@@ -28,7 +31,6 @@ gem '$gem_name', path: '..'
|
|
|
28
31
|
RUBY
|
|
29
32
|
|
|
30
33
|
unbundled bundle install --gemfile Gemfile
|
|
31
|
-
unbundled bin/rails webpacker:install
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
cd .. # Back to the project root.
|
|
@@ -36,4 +38,3 @@ bin/sandbox-setup # Run any custom setup.
|
|
|
36
38
|
|
|
37
39
|
echo
|
|
38
40
|
echo "🚀 Sandbox app successfully created for $gem_name!"
|
|
39
|
-
|
data/bin/sandbox-setup
CHANGED
|
@@ -2,6 +2,16 @@ class Opal::AssetsGenerator < ::Rails::Generators::NamedBase
|
|
|
2
2
|
source_root File.expand_path('templates', __dir__)
|
|
3
3
|
|
|
4
4
|
def copy_opal
|
|
5
|
-
template '
|
|
5
|
+
template 'asset.rb.tt', File.join(opal_source_path, class_path, "#{file_name}.rb")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def opal_source_path
|
|
11
|
+
destination_directory_exist?('app/assets/opal') ? 'app/assets/opal' : 'app/opal'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def destination_directory_exist?(relative_path)
|
|
15
|
+
File.directory?(File.join(destination_root, relative_path))
|
|
6
16
|
end
|
|
7
17
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
# Place
|
|
2
|
-
#
|
|
3
|
-
# You can use Opal in this file: http://opalrb.com/
|
|
4
|
-
#
|
|
1
|
+
# Place controller-specific Opal code here.
|
|
2
|
+
# Require this file from `app/opal/application.rb` or another configured entrypoint.
|
|
5
3
|
#
|
|
6
4
|
# Here's an example view class for your controller:
|
|
7
5
|
#
|
|
@@ -25,7 +23,6 @@ class <%= class_name %>View
|
|
|
25
23
|
puts "Hello! (You just clicked on a link: #{event.current_target.text})"
|
|
26
24
|
end
|
|
27
25
|
|
|
28
|
-
|
|
29
26
|
private
|
|
30
27
|
|
|
31
28
|
attr_reader :selector, :element
|
|
@@ -37,7 +34,7 @@ class <%= class_name %>View
|
|
|
37
34
|
# Element.find("#{@selector} #{selector}")
|
|
38
35
|
# end
|
|
39
36
|
|
|
40
|
-
# Register events on document
|
|
37
|
+
# Register events on document so page-level handlers stay centralized.
|
|
41
38
|
def on(event, selector = nil, &block)
|
|
42
39
|
Element[`document`].on(event, selector, &block)
|
|
43
40
|
end
|