roda-vite 0.1.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 +7 -0
- data/CHANGELOG.md +0 -0
- data/LICENSE +21 -0
- data/README.md +0 -0
- data/bin/roda-vite +3 -0
- data/lib/roda/plugins/vite.rb +81 -0
- data/lib/roda-vite.rb +20 -0
- data/lib/tag_builder.rb +108 -0
- data/lib/version.rb +3 -0
- data/lib/vite_roda/lib/vite_roda/config.rb +32 -0
- data/lib/vite_roda/lib/vite_roda/installation.rb +151 -0
- data/lib/vite_roda/lib/vite_roda/tag_helpers.rb +125 -0
- data/lib/vite_roda/lib/vite_roda.rb +41 -0
- data/templates/config/roda-vite.json +15 -0
- data/templates/vite.config.ts +11 -0
- metadata +69 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 33001869926d3f0cf306e9152f9adde9f77cf445289905d6df44c5efd6f08217
|
4
|
+
data.tar.gz: 1fec4bd57cad226150384a8c3ccc76d5c54b6ad598023336f8acce6b1c647e47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2e9e0047c810b8449fe3edb764ea320698f45b17307e30d1eaac22445df319aedf9ca3a6ac24579ad24d1fd36785ad613be80ae738dc5b268c999c3416b511f8
|
7
|
+
data.tar.gz: e3ad7673a231b2ea14401ddf9507bba08d09c7c38c6082c60742b60f4eb183f73710cf363cc215e509f994eb4633cfa2c4a4825b4e922950d74beb18de7952ad
|
data/CHANGELOG.md
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Avi Feher Sternlieb
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/bin/roda-vite
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative '../../vite_roda/lib/vite_roda'
|
2
|
+
require_relative '../../tag_builder'
|
3
|
+
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
module Vite
|
7
|
+
|
8
|
+
def self.load_dependencies(app, opts=OPTS)
|
9
|
+
# app.plugin :render
|
10
|
+
# app.plugin :assets
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.configure(app, opts=OPTS)
|
14
|
+
# Can be skipped with config skipProxy: true or env VITE_RUBY_SKIP_PROXY="true"
|
15
|
+
proxy_dev_server(app)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Vite Ruby proxies the Vite dev server localhost:3036 at localhost:9292. I'm not sure
|
19
|
+
# why it does this, rather than just linking to localhost:3036, but it does, so this
|
20
|
+
# is added for backward-compatibility and to minimally change Vite Ruby's behavior
|
21
|
+
def self.proxy_dev_server(app)
|
22
|
+
app.use(ViteRuby::DevServerProxy, ssl_verify_none: true) if ViteRuby.run_proxy?
|
23
|
+
end
|
24
|
+
|
25
|
+
STYLESHEET_MATCHER = /\.(css|scss|sass|less|styl)$/
|
26
|
+
TYPESCRIPT_MATCHER = /\.(ts|tsx|mts|cts)$/
|
27
|
+
|
28
|
+
module InstanceMethods
|
29
|
+
|
30
|
+
include ViteRoda::TagHelpers
|
31
|
+
|
32
|
+
# This is inspired by Laravel's @vite([]) Blade directive
|
33
|
+
# Like its counterpart, it defaults to interpreting files as javascript
|
34
|
+
#
|
35
|
+
# It is meant to be used in views (e.g. layout.erb) to generate vite tags
|
36
|
+
# Accepts a single asset path, or an array of paths:
|
37
|
+
#
|
38
|
+
# <%= vite('resources/js/app.js') %>
|
39
|
+
# <%= vite(['resources/js/app.js', 'resources/css/app.css']) %>
|
40
|
+
|
41
|
+
=begin
|
42
|
+
def vite(asset_paths)
|
43
|
+
asset_paths = Array(asset_paths)
|
44
|
+
vite_hmr_tag = vite_client
|
45
|
+
|
46
|
+
asset_tags = asset_paths.map do |asset_path|
|
47
|
+
if STYLESHEET_MATCHER.match?(asset_path)
|
48
|
+
vite_stylesheet(asset_path)
|
49
|
+
elsif TYPESCRIPT_MATCHER.match?(asset_path)
|
50
|
+
vite_typescript(asset_path)
|
51
|
+
else
|
52
|
+
vite_javascript(asset_path)
|
53
|
+
end
|
54
|
+
end.join
|
55
|
+
|
56
|
+
vite_hmr_tag ? "#{vite_hmr_tag}#{asset_tags}" : asset_tags
|
57
|
+
end
|
58
|
+
=end
|
59
|
+
|
60
|
+
def vite(asset_paths)
|
61
|
+
asset_paths = Array(asset_paths)
|
62
|
+
tag_builder = TagBuilder.new(env)
|
63
|
+
|
64
|
+
asset_paths.each do |asset_path|
|
65
|
+
if STYLESHEET_MATCHER.match?(asset_path)
|
66
|
+
tag_builder.add_stylesheet(asset_path)
|
67
|
+
elsif TYPESCRIPT_MATCHER.match?(asset_path)
|
68
|
+
tag_builder.add_typescript(asset_path)
|
69
|
+
else
|
70
|
+
tag_builder.add_javascript(asset_path)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
tag_builder.tags!
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
register_plugin(:vite, Vite)
|
80
|
+
end
|
81
|
+
end
|
data/lib/roda-vite.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
def gem_installed?(name)
|
2
|
+
Gem::Specification.find_by_name(name)
|
3
|
+
true
|
4
|
+
rescue Gem::LoadError
|
5
|
+
false
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'vite_ruby/roda'
|
10
|
+
rescue LoadError => e
|
11
|
+
raise unless e.path == 'vite_ruby/roda'
|
12
|
+
if gem_installed?('vite_ruby')
|
13
|
+
raise "Missing dependency: vite_ruby-roda is required by roda-vite. Please add it to your Gemfile.\n" +
|
14
|
+
'Found vite_ruby, however roda-vite requires vite_ruby-roda. If vite_ruby is in your Gemfile, you may replace it.'
|
15
|
+
else
|
16
|
+
raise 'Missing dependency: vite_ruby-roda is required by roda-vite. Please add it to your Gemfile.'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
$LOAD_PATH.unshift(File.expand_path('vite_roda/lib', __dir__))
|
data/lib/tag_builder.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require_relative 'vite_roda/lib/vite_roda'
|
2
|
+
|
3
|
+
class TagBuilder
|
4
|
+
|
5
|
+
include ViteRoda::TagHelpers
|
6
|
+
|
7
|
+
Tag = Data.define(:type, :src)
|
8
|
+
|
9
|
+
# These are just to be backward compatible with Vite Ruby
|
10
|
+
attr_accessor :skip_preload_tags, :skip_style_tags, :crossorigin
|
11
|
+
|
12
|
+
def initialize(env, skip_preload_tags: false, skip_style_tags: false, crossorigin: "anonymous")
|
13
|
+
@env = env
|
14
|
+
@tags = []
|
15
|
+
|
16
|
+
@skip_preload_tags = skip_preload_tags
|
17
|
+
@skip_style_tags = skip_style_tags
|
18
|
+
@crossorigin = crossorigin
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_stylesheet(src)
|
22
|
+
src = resolve(src, type: :stylesheet)
|
23
|
+
add_resolved_stylesheet(src)
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_javascript(src)
|
27
|
+
add_script(src, type: :javascript)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_typescript(src)
|
31
|
+
add_script(src, type: :typescript)
|
32
|
+
end
|
33
|
+
|
34
|
+
# This method may have a side-effect of sending a
|
35
|
+
# 103 Early Hints status and Link header for preloading
|
36
|
+
def tags!
|
37
|
+
if dev_server_running?
|
38
|
+
vite_hmr_tag + load_tags
|
39
|
+
else
|
40
|
+
send_early_hints
|
41
|
+
preload_tags + load_tags
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def dev_server_running?
|
48
|
+
vite_manifest.dev_server_running?
|
49
|
+
end
|
50
|
+
|
51
|
+
def vite_hmr_tag
|
52
|
+
vite_client
|
53
|
+
end
|
54
|
+
|
55
|
+
def add_script(src, type:)
|
56
|
+
entries = vite_manifest.resolve_entries(src, type:)
|
57
|
+
entries.fetch(:scripts).each { |entry| add_resolved_javascript(entry) }
|
58
|
+
entries.fetch(:imports).each { |entry| add_resolved_javascript(entry) } unless @skip_preload_tags
|
59
|
+
entries.fetch(:stylesheets).each { |entry| add_resolved_stylesheet(entry) } unless @skip_style_tags
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_resolved_javascript(src)
|
63
|
+
@tags.push Tag[:js, src]
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_resolved_stylesheet(src)
|
67
|
+
@tags.push Tag[:css, src]
|
68
|
+
end
|
69
|
+
|
70
|
+
def resolve(path, type:)
|
71
|
+
vite_asset_path(path, type:)
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_tags
|
75
|
+
@tags.map do |tag|
|
76
|
+
case tag
|
77
|
+
in [:js, src] then %[<script type="module" src="#{src}" crossorigin="#{@crossorigin}"></script>]
|
78
|
+
in [:css, src] then %[<link rel="stylesheet" href="#{src}" />]
|
79
|
+
end
|
80
|
+
end.join
|
81
|
+
end
|
82
|
+
|
83
|
+
def preload_tags
|
84
|
+
@tags.map do |tag|
|
85
|
+
case tag
|
86
|
+
in [:js, src] then %[<link rel="modulepreload" href="#{src}" as="script" crossorigin="#{@crossorigin}">]
|
87
|
+
in [:css, src] then %[<link rel="preload" href="#{src}" as="style" />]
|
88
|
+
end
|
89
|
+
end.join
|
90
|
+
end
|
91
|
+
|
92
|
+
# Enables preloading, early hints are implemented in Puma and Falcon
|
93
|
+
# With puma, run with puma --early-hints
|
94
|
+
|
95
|
+
def send_early_hints
|
96
|
+
return unless @env['rack.early_hints']
|
97
|
+
|
98
|
+
early_hint_tags = @tags.map do |tag|
|
99
|
+
case tag
|
100
|
+
in [:js, src] then %[<#{src}>; rel=modulepreload; as=script; crossorigin=#{@crossorigin}]
|
101
|
+
in [:css, src] then %[<#{src}>; rel=preload; as=style]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@env['rack.early_hints'].call('Link' => early_hint_tags.join(', '))
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This is deliberately kept empty as it seems, for now, a better choice to explicitly set defaults
|
4
|
+
# in the config/vite.json file. This way the user can see what Vite Ruby defaults are being overriden
|
5
|
+
# and can expect the same behavior when taking their vite.json config to another framework supported
|
6
|
+
# by Vite Ruby. (The default vite.json added to a user's app on install lives in the templates/ directory.)
|
7
|
+
# However, this is kept here as a reminder that defaults can be configured here, if desired in the future.
|
8
|
+
# Neither Vite Hanami, nor Vite Padrino have this file or override defaults, however Vite Rails does,
|
9
|
+
# so for an example of what this can look like, see:
|
10
|
+
# https://github.com/ElMassimo/vite_ruby/blob/main/vite_rails/lib/vite_rails/config.rb
|
11
|
+
|
12
|
+
module ViteRoda::Config
|
13
|
+
private
|
14
|
+
|
15
|
+
# Override: Default values for a Roda application.
|
16
|
+
def config_defaults
|
17
|
+
|
18
|
+
# As of 5/18/25, the Vite Rails plugin checks Rails' asset host, assigning it to a
|
19
|
+
# variable which could be done by checking Roda's assets plugin, and sets:
|
20
|
+
#
|
21
|
+
# super(
|
22
|
+
# asset_host: asset_host,
|
23
|
+
# mode: env
|
24
|
+
# root: root || Dir.pwd,
|
25
|
+
# )
|
26
|
+
|
27
|
+
super
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
ViteRuby::Config.singleton_class.prepend(ViteRoda::Config)
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "vite_roda"
|
4
|
+
|
5
|
+
# If it is desired to instead extend the whole CLI, rather than just the install
|
6
|
+
# subcommand, write a cli.rb file instead of an installation.rb file. Vite Ruby
|
7
|
+
# first tries to load a framework specific cli.rb and then if that fails, loads
|
8
|
+
# installation.rb instead. Both Hanami and Padrino extensions just have an
|
9
|
+
# installation.rb file, but the Rails extension has a cli.rb file. To see the source
|
10
|
+
# code where this is loaded, see: https://github.com/ElMassimo/vite_ruby/blob/95c247a66d86f15ad9ce783acf92fef96646091b/vite_ruby/lib/vite_ruby/cli.rb#L20
|
11
|
+
# To see the reference installation.rb files, see reference/installation/vite_*.rb
|
12
|
+
|
13
|
+
|
14
|
+
# Internal: Extends the base installation script from Vite Ruby to work for a
|
15
|
+
# typical Roda app.
|
16
|
+
module ViteRoda::Installation
|
17
|
+
RODA_TEMPLATES = Pathname.new(File.expand_path("../../../../templates", __dir__))
|
18
|
+
|
19
|
+
# def call(**options)
|
20
|
+
# ensure_roda_plugin_added
|
21
|
+
# super
|
22
|
+
# end
|
23
|
+
|
24
|
+
def call(package_manager: nil, **)
|
25
|
+
|
26
|
+
ensure_roda_plugin_added
|
27
|
+
|
28
|
+
ENV["VITE_RUBY_PACKAGE_MANAGER"] ||= package_manager if package_manager
|
29
|
+
|
30
|
+
$stdout.sync = true
|
31
|
+
|
32
|
+
# Keep it minimal: Skip creating binstubs
|
33
|
+
# say "Creating binstub"
|
34
|
+
# ViteRuby.commands.install_binstubs
|
35
|
+
|
36
|
+
# Create vite.config.ts and config/vite.json
|
37
|
+
# say "Creating configuration files"
|
38
|
+
create_configuration_files
|
39
|
+
|
40
|
+
# Empty, skip creating app-specific sample files
|
41
|
+
# say "Installing sample files"
|
42
|
+
install_sample_files
|
43
|
+
|
44
|
+
# Only return the command to run, don't run it
|
45
|
+
js_command = install_js_dependencies
|
46
|
+
|
47
|
+
# say "Adding files to .gitignore"
|
48
|
+
# install_gitignore
|
49
|
+
|
50
|
+
# say "\nVite ⚡️ Ruby successfully installed! 🎉"
|
51
|
+
|
52
|
+
MESSAGE = <<~DOC
|
53
|
+
\e[2mIf you have your css in \e[36massets/css/app.css\e[0;2m, you'll want to add the following to your html:
|
54
|
+
|
55
|
+
\e[2m <head>\e[m
|
56
|
+
\e[32m+ <%= vite(['app.css']) %>\e[m
|
57
|
+
\e[2m </head>\e[m
|
58
|
+
|
59
|
+
\e[2mVite accepts an asset array including css, scss, javascript and typescript.
|
60
|
+
|
61
|
+
To install \e[36mnode_modules/\e[0;2m, run:
|
62
|
+
|
63
|
+
\e[0;1;36m #{js_command}\e[m
|
64
|
+
DOC
|
65
|
+
end
|
66
|
+
|
67
|
+
# Internal: Ensures the Vite plugin is loaded in app.rb
|
68
|
+
def ensure_roda_plugin_added
|
69
|
+
unless line_with_prefix_exists? root.join("app.rb"), "plugin :vite"
|
70
|
+
abort "Add plugin :vite to your app.rb before installing"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Using String#lstrip and String#start_with? is supposedly faster than using Regex as:
|
75
|
+
# File.readlines(file).any? { |line| line.match?(/^\s*plugin :vite/) } if File.exist?(file)
|
76
|
+
def line_with_prefix_exists?(file, string)
|
77
|
+
File.readlines(file).any? { |line| line.lstrip.start_with?(string) } if File.exist?(file)
|
78
|
+
end
|
79
|
+
|
80
|
+
# The two methods below are inteded for override, and overriden by Vite Hanami and Vite Padrino
|
81
|
+
|
82
|
+
# Override: Setup a typical apps/web Roda app to use Vite.
|
83
|
+
def setup_app_files
|
84
|
+
|
85
|
+
# DO: Initialize config/vite.json with recommended config from templates/config/roda-vite.json
|
86
|
+
|
87
|
+
# I kind of like the following from Vite Ruby but it requires defining a
|
88
|
+
# local copy_template methods which has RODA_TEMPLATES as the template constant
|
89
|
+
# copy_template "config/vite.json", to: config.config_path
|
90
|
+
|
91
|
+
cp RODA_TEMPLATES.join("config/roda-vite.json"), config.config_path
|
92
|
+
|
93
|
+
# Keep it minimal: Skip adding Rake tasks
|
94
|
+
# append root.join("Rakefile"), <<~RAKE
|
95
|
+
# require 'vite_roda'
|
96
|
+
# ViteRuby.install_tasks
|
97
|
+
# RAKE
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
# Override: Inject the vite client and sample script to the default HTML template.
|
102
|
+
def install_sample_files
|
103
|
+
# super
|
104
|
+
|
105
|
+
# Keep it minimal: Skip creating a sample javascript file
|
106
|
+
# cp RODA_TEMPLATES.join("entrypoints/application.js"), config.resolved_entrypoints_dir.join("application.js")
|
107
|
+
|
108
|
+
# Keep it minimal: Skip adding vite_tags into layout file
|
109
|
+
# inject_line_before root.join("views/layout.erb"), "</head>", <<-HTML
|
110
|
+
# <%= vite(['app.css', 'app.js']) %>
|
111
|
+
# HTML
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def install_js_packages(deps)
|
118
|
+
# Keep it minimal: Skip installing npm modules, prompting developer to do it
|
119
|
+
# Vite Ruby installs vite and vite-plugin-ruby for you, with the following line:
|
120
|
+
# Vite Roda opts out of this behavior for now, instead outputting the instructions:
|
121
|
+
# run_with_capture("#{config.package_manager} add -D #{deps}", stdin_data: "\n")
|
122
|
+
|
123
|
+
# Escape the ^ in version specifier for ZSH interop converting:
|
124
|
+
# npm add -D vite@^6.2.6 vite-plugin-ruby@^5.1.1
|
125
|
+
# npm add -D vite@\^6.2.6 vite-plugin-ruby@\^5.1.1
|
126
|
+
deps = deps.gsub('^', '\^')
|
127
|
+
"#{config.package_manager} add -D #{deps}"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Internal: Creates the Vite and vite-plugin-ruby configuration files.
|
131
|
+
def create_configuration_files
|
132
|
+
|
133
|
+
# This is because we're using a different vite.config.ts to restore defaults
|
134
|
+
# If those settings are able to be put in config/vite.json instead, which is preferable,
|
135
|
+
# then can go back to using the second one, which uses Vite Ruby's vite.config.ts
|
136
|
+
|
137
|
+
cp RODA_TEMPLATES.join("vite.config.ts"), root.join("vite.config.ts")
|
138
|
+
# copy_template "config/vite.config.ts", to: root.join("vite.config.ts")
|
139
|
+
|
140
|
+
# Keep it minimal: Skip creating Procfile.dev and adding Vite task
|
141
|
+
# append root.join("Procfile.dev"), "vite: bin/vite dev"
|
142
|
+
|
143
|
+
setup_app_files
|
144
|
+
ViteRuby.reload_with(config_path: config.config_path)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
puts "VITE RODA CLI"
|
150
|
+
|
151
|
+
ViteRuby::CLI::Install.prepend(ViteRoda::Installation)
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This is a Roda integration for Vite Ruby
|
4
|
+
#
|
5
|
+
# The Git repo for that project is hosted at: https://github.com/ElMassimo/vite_ruby
|
6
|
+
# And the documentation site is hosted at: https://vite-ruby.netlify.app/
|
7
|
+
#
|
8
|
+
# It is copied from the three other Vite Ruby extensions for Rails/Hanami/Padrino, as well
|
9
|
+
# as the legacy extensions, as faithfully as possible with minimal changes to make it work
|
10
|
+
|
11
|
+
# Public: Allows to render HTML tags for scripts and styles processed by Vite.
|
12
|
+
module ViteRoda::TagHelpers
|
13
|
+
# Public: Renders a script tag for vite/client to enable HMR in development.
|
14
|
+
def vite_client
|
15
|
+
return unless src = vite_manifest.vite_client_src
|
16
|
+
|
17
|
+
%Q[<script type="module" src="#{src}"></script>]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Public: Renders a script tag to enable HMR with React Refresh.
|
21
|
+
def vite_react_refresh
|
22
|
+
vite_manifest.react_refresh_preamble
|
23
|
+
end
|
24
|
+
|
25
|
+
# Public: Resolves the path for the specified Vite asset.
|
26
|
+
#
|
27
|
+
# Example:
|
28
|
+
# <%= vite_asset_path 'calendar.css' %> # => "/vite/assets/calendar-1016838bab065ae1e122.css"
|
29
|
+
def vite_asset_path(name, **options)
|
30
|
+
asset_path vite_manifest.path_for(name, **options)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Public: Renders a <script> tag for the specified Vite entrypoints.
|
34
|
+
def vite_javascript(*names,
|
35
|
+
type: "module",
|
36
|
+
asset_type: :javascript,
|
37
|
+
skip_preload_tags: false,
|
38
|
+
skip_style_tags: false,
|
39
|
+
crossorigin: "anonymous",
|
40
|
+
**options)
|
41
|
+
entries = vite_manifest.resolve_entries(*names, type: asset_type)
|
42
|
+
tags = javascript(*entries.fetch(:scripts), crossorigin: crossorigin, type: type, **options)
|
43
|
+
tags << vite_modulepreload(*entries.fetch(:imports), crossorigin: crossorigin) unless skip_preload_tags
|
44
|
+
tags << stylesheet(*entries.fetch(:stylesheets)) unless skip_style_tags
|
45
|
+
tags
|
46
|
+
end
|
47
|
+
|
48
|
+
# Public: Renders a <script> tag for the specified Vite entrypoints.
|
49
|
+
def vite_typescript(*names, **options)
|
50
|
+
vite_javascript(*names, asset_type: :typescript, **options)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Renders a <link> tag for the specified Vite entrypoints.
|
54
|
+
def vite_stylesheet(*names, **options)
|
55
|
+
style_paths = names.map { |name| vite_asset_path(name, type: :stylesheet) }
|
56
|
+
stylesheet(*style_paths, **options)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# This may eventually delegate to Roda's assets plugin
|
62
|
+
def asset_path(path)
|
63
|
+
# "/build/#{path}" # <- pubic/build/
|
64
|
+
path
|
65
|
+
end
|
66
|
+
|
67
|
+
# Internal: Returns the current manifest loaded by Vite Ruby.
|
68
|
+
def vite_manifest
|
69
|
+
ViteRuby.instance.manifest
|
70
|
+
end
|
71
|
+
|
72
|
+
# Internal: Renders a modulepreload link tag.
|
73
|
+
def vite_modulepreload(*sources, crossorigin:)
|
74
|
+
puts sources.size
|
75
|
+
sources.map do |source|
|
76
|
+
href = asset_path(source)
|
77
|
+
|
78
|
+
# Enables preloading, early hints are implemented in Puma and Falcon
|
79
|
+
# With puma, run with puma --early-hints
|
80
|
+
if early_hints = env['rack.early_hints']
|
81
|
+
puts 'early hints'
|
82
|
+
early_hints.call(
|
83
|
+
'Link' => %[<#{href}>; rel=modulepreload; as=script; crossorigin=#{crossorigin}]
|
84
|
+
)
|
85
|
+
else
|
86
|
+
puts 'no early hints'
|
87
|
+
end
|
88
|
+
|
89
|
+
puts href
|
90
|
+
modulepreload(href, crossorigin: crossorigin)
|
91
|
+
end.join
|
92
|
+
end
|
93
|
+
|
94
|
+
# Implement an interface for rendering javascript and stylesheet tags. Approximates
|
95
|
+
# the interfaces given by Rails/Hanami/Padrino and used by the other Vite extensions
|
96
|
+
def javascript(*sources, **options)
|
97
|
+
attributes = attributes(options)
|
98
|
+
sources.map do |source|
|
99
|
+
%Q[<script src="#{source}"#{attributes}></script>]
|
100
|
+
end.join
|
101
|
+
end
|
102
|
+
|
103
|
+
def stylesheet(*sources, **options)
|
104
|
+
attributes = attributes(options)
|
105
|
+
sources.map do |source|
|
106
|
+
%Q[<link rel="stylesheet" href="#{source}"#{attributes}>]
|
107
|
+
end.join
|
108
|
+
end
|
109
|
+
|
110
|
+
def modulepreload(*sources, **options)
|
111
|
+
attributes = attributes(options)
|
112
|
+
sources.map do |source|
|
113
|
+
%Q[<link rel="modulepreload" href="#{source}" as="script"#{attributes}>]
|
114
|
+
end.join
|
115
|
+
end
|
116
|
+
|
117
|
+
def attributes(hash)
|
118
|
+
# Boolean attribute must be handled with care. If an attribute is present,
|
119
|
+
# it is interpreted as true, so checked="false" is still true. When true,
|
120
|
+
# render just the attribute with no value, when false, omit the attribute entirely
|
121
|
+
options = hash.filter_map { |key, val| val == true ? key : %Q[#{key}="#{val}"] if val }.join(' ')
|
122
|
+
options = ' ' + options unless options.empty?
|
123
|
+
options
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViteRoda; end
|
4
|
+
|
5
|
+
require "vite_ruby-roda" # Patched "vite_ruby"
|
6
|
+
require_relative "vite_roda/tag_helpers"
|
7
|
+
require_relative "vite_roda/config"
|
8
|
+
|
9
|
+
# ViteRuby::COMPANION_LIBRARIES is a hash containing the companion
|
10
|
+
# libraries for Vite Ruby, and their target framework, defined at:
|
11
|
+
# https://github.com/ElMassimo/vite_ruby/blob/95c247a66d86f15ad9ce783acf92fef96646091b/vite_ruby/lib/vite_ruby.rb#L23
|
12
|
+
|
13
|
+
# It's required to autoload the cli extensions (e.g. the one at vite_roda/installation.rb)
|
14
|
+
# in ViteRuby::CLI::require_framework_libraries at:
|
15
|
+
# https://github.com/ElMassimo/vite_ruby/blob/95c247a66d86f15ad9ce783acf92fef96646091b/vite_ruby/lib/vite_ruby/cli.rb#L20
|
16
|
+
|
17
|
+
# And it is called in the bin/vite executable installed by Vite Ruby at line 10:
|
18
|
+
# https://github.com/ElMassimo/vite_ruby/blob/95c247a66d86f15ad9ce783acf92fef96646091b/vite_ruby/exe/vite#L10
|
19
|
+
|
20
|
+
|
21
|
+
# I believe this might need to match the name of the gem
|
22
|
+
ViteRuby::COMPANION_LIBRARIES['roda-vite'] = 'roda'
|
23
|
+
# ViteRuby::COMPANION_LIBRARIES['roda-vite'] = 'roda'
|
24
|
+
|
25
|
+
module ViteRoda
|
26
|
+
|
27
|
+
# # Internal: Called when the Rack app is available.
|
28
|
+
# def self.registered(app)
|
29
|
+
# if RACK_ENV != "production" && ViteRuby.run_proxy?
|
30
|
+
# app.use(ViteRuby::DevServerProxy, ssl_verify_none: true)
|
31
|
+
# end
|
32
|
+
# ViteRuby.instance.logger = app.logger
|
33
|
+
# included(app)
|
34
|
+
# end
|
35
|
+
|
36
|
+
# # Internal: Called when the module is registered in the Padrino app.
|
37
|
+
# def self.included(base)
|
38
|
+
# base.send :include, ViteRoda::TagHelpers
|
39
|
+
# end
|
40
|
+
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: roda-vite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Avi Sternlieb
|
8
|
+
bindir:
|
9
|
+
- bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: vite_ruby-roda
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
email:
|
28
|
+
- avifsternlieb@gmail.com
|
29
|
+
executables:
|
30
|
+
- roda-vite
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- CHANGELOG.md
|
35
|
+
- LICENSE
|
36
|
+
- README.md
|
37
|
+
- bin/roda-vite
|
38
|
+
- lib/roda-vite.rb
|
39
|
+
- lib/roda/plugins/vite.rb
|
40
|
+
- lib/tag_builder.rb
|
41
|
+
- lib/version.rb
|
42
|
+
- lib/vite_roda/lib/vite_roda.rb
|
43
|
+
- lib/vite_roda/lib/vite_roda/config.rb
|
44
|
+
- lib/vite_roda/lib/vite_roda/installation.rb
|
45
|
+
- lib/vite_roda/lib/vite_roda/tag_helpers.rb
|
46
|
+
- templates/config/roda-vite.json
|
47
|
+
- templates/vite.config.ts
|
48
|
+
homepage: https://github.com/avifs/roda-vite
|
49
|
+
licenses:
|
50
|
+
- MIT
|
51
|
+
metadata: {}
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.5'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubygems_version: 3.6.8
|
67
|
+
specification_version: 4
|
68
|
+
summary: A Roda plugin for Vite, leveraging Vite Ruby.
|
69
|
+
test_files: []
|