Skip to content

Commit a80f286

Browse files
committed
feat: Add helpers to enable HMR when using @vitejs/plugin-react-refresh
When using HTML entrypoints this will be injected by the plugin, but for server-rendered templates it must be injected manually using the helper.
1 parent dd4ac90 commit a80f286

11 files changed

Lines changed: 120 additions & 42 deletions

File tree

docs/guide/hanami.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
[sourceCodeDir]: /config/#sourcecodedir
1515
[autoBuild]: /config/#autobuild
1616
[entrypoints]: /guide/development.html#entrypoints-⤵%EF%B8%8F
17-
[vite_client]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_hanami/lib/vite_hanami/tag_helpers.rb
18-
[vite_javascript]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_hanami/lib/vite_hanami/tag_helpers.rb
19-
[vite_typescript]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_hanami/lib/vite_hanami/tag_helpers.rb
20-
[vite_stylesheet]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_hanami/lib/vite_hanami/tag_helpers.rb
21-
[vite_asset_path]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_hanami/lib/vite_hanami/tag_helpers.rb
17+
[helpers]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_hanami/lib/vite_hanami/tag_helpers.rb
2218
[development]: /guide/development
2319
[vite_hanami]: https://github.com/ElMassimo/vite_ruby/tree/main/vite_hanami
2420
[hanami]: https://hanamirb.org/
@@ -36,10 +32,9 @@ As we saw in the [development] section, [entrypoints] will be [automatically det
3632
In order to link the JavaScript and CSS managed by Vite in your Hanami views or
3733
templates, you can use the following helpers:
3834

39-
- <kbd>[vite_client]</kbd>: Renders the Vite client to enable Hot Module Reload.
40-
- <kbd>[vite_javascript]</kbd>: Render a `<script>` tag referencing a JavaScript file.
41-
- <kbd>[vite_typescript]</kbd>: Render a `<script>` tag referencing a TypeScript file.
42-
- <kbd>[vite_stylesheet]</kbd>: Render a `<link>` tag referencing a CSS file.
35+
- <kbd>[vite_javascript][helpers]</kbd>: Renders a `<script>` tag referencing a JavaScript file
36+
- <kbd>[vite_typescript][helpers]</kbd>: Renders a `<script>` tag referencing a TypeScript file
37+
- <kbd>[vite_stylesheet][helpers]</kbd>: Renders a `<link>` tag referencing a CSS file
4338

4439
You can pass any options supported by <kbd>javascript</kbd> and <kbd>stylesheet</kbd>.
4540

@@ -54,16 +49,25 @@ You can pass any options supported by <kbd>javascript</kbd> and <kbd>stylesheet<
5449
</head>
5550
```
5651

57-
For other types of assets, you can use <kbd>[vite_asset_path]</kbd> and pass the resulting URI to the appropriate tag helper.
52+
For other types of assets, you can use <kbd>[vite_asset_path][helpers]</kbd> and pass the resulting URI to the appropriate tag helper.
5853

5954
```erb
6055
<img src="<%= vite_asset_path 'images/logo.svg' %>" />
6156
<link rel="prefetch" href="<%= vite_asset_path 'typography.css' %>" />
6257
```
6358

59+
### Enabling Hot Module Reload 🔥
60+
61+
Use the following helpers to enable HMR in development:
62+
63+
- <kbd>[vite_client][helpers]</kbd>: Renders the Vite client to enable Hot Module Reload
64+
- <kbd>[vite_react_refresh][helpers]</kbd>: Only when using `@vitejs/plugin-react-refresh`
65+
66+
They will only render if the dev server is running.
67+
6468
### Smart Output ✨
6569

66-
For convenience, <kbd>[vite_javascript]</kbd> will automatically inject tags for styles or entries imported within a script.
70+
For convenience, <kbd>[vite_javascript][helpers]</kbd> will automatically inject tags for styles or entries imported within a script.
6771

6872
```erb
6973
<%= vite_javascript 'application' %>

docs/guide/padrino.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
[sourceCodeDir]: /config/#sourcecodedir
1515
[autoBuild]: /config/#autobuild
1616
[entrypoints]: /guide/development.html#entrypoints-⤵%EF%B8%8F
17-
[vite_client_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_padrino/lib/vite_padrino/tag_helpers.rb
18-
[vite_javascript_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_padrino/lib/vite_padrino/tag_helpers.rb
19-
[vite_typescript_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_padrino/lib/vite_padrino/tag_helpers.rb
20-
[vite_stylesheet_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_padrino/lib/vite_padrino/tag_helpers.rb
21-
[vite_asset_path]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_padrino/lib/vite_padrino/tag_helpers.rb
17+
[helpers]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_padrino/lib/vite_padrino/tag_helpers.rb
2218
[development]: /guide/development
2319
[vite_padrino]: https://github.com/ElMassimo/vite_ruby/tree/main/vite_padrino
2420
[padrino]: https://padrinorb.com/
@@ -36,10 +32,9 @@ As we saw in the [development] section, [entrypoints] will be [automatically det
3632
In order to link the JavaScript and CSS managed by Vite in your Padrino views or
3733
templates, you can use the following helpers:
3834

39-
- <kbd>[vite_client_tag]</kbd>: Renders the Vite client to enable Hot Module Reload.
40-
- <kbd>[vite_javascript_tag]</kbd>: Render a `<script>` tag referencing a JavaScript file.
41-
- <kbd>[vite_typescript_tag]</kbd>: Render a `<script>` tag referencing a TypeScript file.
42-
- <kbd>[vite_stylesheet_tag]</kbd>: Render a `<link>` tag referencing a CSS file.
35+
- <kbd>[vite_javascript_tag][helpers]</kbd>: Renders a `<script>` tag referencing a JavaScript file
36+
- <kbd>[vite_typescript_tag][helpers]</kbd>: Renders a `<script>` tag referencing a TypeScript file
37+
- <kbd>[vite_stylesheet_tag][helpers]</kbd>: Renders a `<link>` tag referencing a CSS file
4338

4439
You can pass any options supported by <kbd>javascript</kbd> and <kbd>stylesheet</kbd>.
4540

@@ -52,16 +47,25 @@ You can pass any options supported by <kbd>javascript</kbd> and <kbd>stylesheet<
5247
= vite_typescript_tag 'application'
5348
```
5449

55-
For other types of assets, you can use <kbd>[vite_asset_path]</kbd> and pass the resulting URI to the appropriate tag helper.
50+
For other types of assets, you can use <kbd>[vite_asset_path][helpers]</kbd> and pass the resulting URI to the appropriate tag helper.
5651

5752
```haml
5853
%img{ src: vite_asset_path('images/logo.svg') }
5954
%link{ rel: 'prefetch', href: vite_asset_path('typography.css') }
6055
```
6156

57+
### Enabling Hot Module Reload 🔥
58+
59+
Use the following helpers to enable HMR in development:
60+
61+
- <kbd>[vite_client_tag][helpers]</kbd>: Renders the Vite client to enable Hot Module Reload
62+
- <kbd>[vite_react_refresh_tag][helpers]</kbd>: Only when using `@vitejs/plugin-react-refresh`
63+
64+
They will only render if the dev server is running.
65+
6266
### Smart Output ✨
6367

64-
For convenience, <kbd>[vite_javascript_tag]</kbd> will automatically inject tags for styles or entries imported within a script.
68+
For convenience, <kbd>[vite_javascript_tag][helpers]</kbd> will automatically inject tags for styles or entries imported within a script.
6569

6670
```haml
6771
= vite_javascript_tag 'application'

docs/guide/rails.md

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,7 @@
1414
[sourceCodeDir]: /config/#sourcecodedir
1515
[autoBuild]: /config/#autobuild
1616
[entrypoints]: /guide/development.html#entrypoints-⤵%EF%B8%8F
17-
[vite_client_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/tag_helpers.rb
18-
[vite_javascript_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/tag_helpers.rb
19-
[vite_typescript_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/tag_helpers.rb
20-
[vite_stylesheet_tag]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/tag_helpers.rb
21-
[vite_asset_path]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/tag_helpers.rb
17+
[helpers]: https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/tag_helpers.rb
2218
[development]: /guide/development
2319
[vite_rails]: https://github.com/ElMassimo/vite_ruby/tree/main/vite_rails
2420
[installed example]: https://github.com/ElMassimo/vite_ruby/tree/main/examples/rails
@@ -40,10 +36,9 @@ As we saw in the [development] section, [entrypoints] will be [automatically det
4036
In order to link the JavaScript and CSS managed by Vite in your Rails layouts or
4137
templates, you can using the following helpers:
4238

43-
- <kbd>[vite_client_tag]</kbd>: Renders the Vite client to enable Hot Module Reload.
44-
- <kbd>[vite_javascript_tag]</kbd>: Render a `<script>` tag referencing a JavaScript file.
45-
- <kbd>[vite_typescript_tag]</kbd>: Render a `<script>` tag referencing a TypeScript file.
46-
- <kbd>[vite_stylesheet_tag]</kbd>: Render a `<link>` tag referencing a CSS file.
39+
- <kbd>[vite_javascript_tag][helpers]</kbd>: Renders a `<script>` tag referencing a JavaScript file
40+
- <kbd>[vite_typescript_tag][helpers]</kbd>: Renders a `<script>` tag referencing a TypeScript file
41+
- <kbd>[vite_stylesheet_tag][helpers]</kbd>: Renders a `<link>` tag referencing a CSS file
4742

4843
You can pass any options supported by <kbd>javascript_include_tag</kbd> and <kbd>stylesheet_link_tag</kbd>.
4944

@@ -59,7 +54,7 @@ You can pass any options supported by <kbd>javascript_include_tag</kbd> and <kbd
5954
</head>
6055
```
6156

62-
For other types of assets, you can use <kbd>[vite_asset_path]</kbd> and pass the resulting URI to the appropriate tag helper.
57+
For other types of assets, you can use <kbd>[vite_asset_path][helpers]</kbd> and pass the resulting URI to the appropriate tag helper.
6358

6459
```erb
6560
<img src="<%= vite_asset_path 'images/logo.svg' %>" />
@@ -72,9 +67,26 @@ If using `.jsx`, `.tsx`, or any other extension, make sure to be explicit:
7267
<%= vite_javascript_tag 'application.tsx' %>
7368
```
7469

70+
### Enabling Hot Module Reload 🔥
71+
72+
Use the following helpers to enable HMR in development:
73+
74+
- <kbd>[vite_client_tag][helpers]</kbd>: Renders the Vite client to enable Hot Module Reload
75+
- <kbd>[vite_react_refresh_tag][helpers]</kbd>: Only when using `@vitejs/plugin-react-refresh`
76+
77+
They will only render if the dev server is running.
78+
79+
#### Hot Reload for Stimulus Controllers
80+
81+
If you are using [Stimulus], check out <kbd>[vite-plugin-stimulus-hmr]</kbd>.
82+
83+
You will no longer need to refresh the page when tweaking your controllers 😃
84+
85+
Comes installed by default in [this template][jumpstart].
86+
7587
### Smart Output ✨
7688

77-
For convenience, <kbd>[vite_javascript_tag]</kbd> will automatically inject tags for styles or entries imported within a script.
89+
For convenience, <kbd>[vite_javascript_tag][helpers]</kbd> will automatically inject tags for styles or entries imported within a script.
7890

7991
```erb
8092
<%= vite_javascript_tag 'application' %>
@@ -93,11 +105,3 @@ When running the development server, these tags are omitted, as Vite will load t
93105
```erb
94106
<script src="/vite/assets/application.js" type="module" crossorigin="anonymous"/>
95107
```
96-
97-
### Stimulus HMR 🔥
98-
99-
If you are using [Stimulus], check out <kbd>[vite-plugin-stimulus-hmr]</kbd>, which provides HMR for Stimulus controllers.
100-
101-
You will no longer need to refresh the page when tweaking your controllers 😃
102-
103-
Comes installed by default in [this template][jumpstart].

docs/guide/troubleshooting.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
[Using Heroku]: /guide/deployment#using-heroku
1414
[example app]: https://github.com/ElMassimo/vite_ruby/tree/main/examples/rails/vite.config.ts
1515
[windi]: /guide/plugins.html#windi-css
16+
[@vitejs/plugin-react-refresh]: https://www.npmjs.com/package/@vitejs/plugin-react-refresh
17+
[tag helpers]: /guide/development.html#tag-helpers-🏷
1618

1719
# Troubleshooting
1820

@@ -26,6 +28,19 @@ Verify that both <kbd>[vite]</kbd> and <kbd>[vite-plugin-ruby]</kbd> are in `dev
2628

2729
If you are using a non-standard setup, try configuring <kbd>[viteBinPath]</kbd>.
2830

31+
### Hot Module Refresh does not work for React
32+
33+
When using <kbd>[@vitejs/plugin-react-refresh]</kbd> in non-HTML entrypoints,
34+
you must explicitly [register the HMR plugin](https://github.com/vitejs/vite/issues/1984#issuecomment-778289660).
35+
36+
A [<kbd>vite_react_refresh_tag</kbd> helper][tag helpers] is provided for your convenience:
37+
38+
```erb
39+
<%= vite_client_tag %>
40+
<%= vite_react_refresh_tag %>
41+
<%= vite_javascript_tag 'application' %>
42+
```
43+
2944
### Making HMR work in Docker Compose
3045

3146
Using Vite.js with Docker Compose requires configuring [`VITE_RUBY_HOST`][host] in the services.

test/helper_test.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ def test_vite_client_tag
2727
}
2828
end
2929

30+
def test_vite_react_refresh_tag
31+
assert_nil vite_react_refresh_tag
32+
with_dev_server_running {
33+
assert_equal <<~HTML, vite_react_refresh_tag
34+
<script type="module">
35+
import RefreshRuntime from '/vite-production/@react-refresh'
36+
RefreshRuntime.injectIntoGlobalHook(window)
37+
window.$RefreshReg$ = () => {}
38+
window.$RefreshSig$ = () => (type) => type
39+
window.__vite_plugin_react_preamble_installed__ = true
40+
</script>
41+
HTML
42+
}
43+
end
44+
3045
def test_vite_asset_path
3146
assert_equal '/vite-production/assets/application.d9514acc.js', vite_asset_path('application.ts')
3247
assert_equal '/vite-production/assets/styles.0e53e684.css', vite_asset_path('styles.css')

vite_hanami/lib/vite_hanami/installation.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def setup_app_files
1616
# Allow @vite/client to hot reload changes in development
1717
security.content_security_policy(
1818
security.content_security_policy
19-
.sub('script-src', "script-src 'unsafe-eval'")
19+
.sub('script-src', "script-src 'unsafe-eval' 'unsafe-inline'")
2020
.sub('connect-src', "connect-src ws://\#{ ViteRuby.config.host_with_port }")
2121
)
2222
CSP

vite_hanami/lib/vite_hanami/tag_helpers.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ def vite_client
99
html.script(src: src, type: 'module')
1010
end
1111

12+
# Public: Renders a script tag to enable HMR with React Refresh.
13+
def vite_react_refresh
14+
tag = vite_manifest.react_refresh_preamble
15+
raw(tag) if tag
16+
end
17+
1218
# Public: Resolves the path for the specified Vite asset.
1319
#
1420
# Example:

vite_padrino/lib/vite_padrino/tag_helpers.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ def vite_client_tag
99
content_tag(:script, nil, src: src, type: 'module')
1010
end
1111

12+
# Public: Renders a script tag to enable HMR with React Refresh.
13+
def vite_react_refresh_tag
14+
vite_manifest.react_refresh_preamble&.html_safe
15+
end
16+
1217
# Public: Resolves the path for the specified Vite asset.
1318
#
1419
# Example:

vite_rails/lib/vite_rails/tag_helpers.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ def vite_client_tag
99
tag.script(src: src, type: 'module')
1010
end
1111

12+
# Public: Renders a script tag to enable HMR with React Refresh.
13+
def vite_react_refresh_tag
14+
vite_manifest.react_refresh_preamble&.html_safe
15+
end
16+
1217
# Public: Resolves the path for the specified Vite asset.
1318
#
1419
# Example:

vite_rails_legacy/lib/vite_rails_legacy/tag_helpers.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ def vite_client_tag
99
"<script#{ tag_options({ src: src, type: 'module' }, escape: true) }></script>".html_safe
1010
end
1111

12+
# Public: Renders a script tag to enable HMR with React Refresh.
13+
def vite_react_refresh_tag
14+
vite_manifest.react_refresh_preamble&.html_safe
15+
end
16+
1217
# Public: Resolves the path for the specified Vite asset.
1318
#
1419
# Example:

0 commit comments

Comments
 (0)