vite_ruby 3.9.0 → 4.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -400
- data/README.md +1 -1
- data/default.vite.json +2 -7
- data/exe/vite +0 -2
- data/lib/tasks/vite.rake +12 -49
- data/lib/vite_ruby/build.rb +16 -46
- data/lib/vite_ruby/builder.rb +26 -21
- data/lib/vite_ruby/cli/build.rb +0 -2
- data/lib/vite_ruby/cli/install.rb +19 -24
- data/lib/vite_ruby/cli/upgrade_packages.rb +2 -1
- data/lib/vite_ruby/cli/vite.rb +4 -19
- data/lib/vite_ruby/cli.rb +0 -13
- data/lib/vite_ruby/commands.rb +61 -16
- data/lib/vite_ruby/compatibility_check.rb +1 -1
- data/lib/vite_ruby/config.rb +12 -41
- data/lib/vite_ruby/dev_server_proxy.rb +5 -10
- data/lib/vite_ruby/io.rb +1 -1
- data/lib/vite_ruby/manifest.rb +17 -29
- data/lib/vite_ruby/missing_entrypoint_error.rb +13 -21
- data/lib/vite_ruby/runner.rb +10 -18
- data/lib/vite_ruby/version.rb +3 -3
- data/lib/vite_ruby.rb +11 -26
- metadata +10 -31
- data/lib/vite_ruby/cli/ssr.rb +0 -27
data/lib/vite_ruby/builder.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'json'
|
3
4
|
require 'digest/sha1'
|
4
5
|
|
5
6
|
# Public: Keeps track of watched files and triggers builds as needed.
|
@@ -11,13 +12,9 @@ class ViteRuby::Builder
|
|
11
12
|
# Public: Checks if the watched files have changed since the last compilation,
|
12
13
|
# and triggers a Vite build if any files have changed.
|
13
14
|
def build(*args)
|
14
|
-
last_build = last_build_metadata
|
15
|
-
|
16
|
-
|
17
|
-
stdout, stderr, status = build_with_vite(*args)
|
18
|
-
log_build_result(stdout, stderr, status)
|
19
|
-
record_build_metadata(last_build, errors: stderr, success: status.success?)
|
20
|
-
status.success?
|
15
|
+
last_build = last_build_metadata
|
16
|
+
if args.delete('--force') || last_build.stale?
|
17
|
+
build_with_vite(*args).tap { |success| record_build_metadata(success, last_build) }
|
21
18
|
elsif last_build.success
|
22
19
|
logger.debug "Skipping vite build. Watched files have not changed since the last build at #{ last_build.timestamp }"
|
23
20
|
true
|
@@ -28,8 +25,8 @@ class ViteRuby::Builder
|
|
28
25
|
end
|
29
26
|
|
30
27
|
# Internal: Reads the result of the last compilation from disk.
|
31
|
-
def last_build_metadata
|
32
|
-
ViteRuby::Build.from_previous(
|
28
|
+
def last_build_metadata
|
29
|
+
ViteRuby::Build.from_previous(last_build_attrs, watched_files_digest)
|
33
30
|
end
|
34
31
|
|
35
32
|
private
|
@@ -38,35 +35,44 @@ private
|
|
38
35
|
|
39
36
|
def_delegators :@vite_ruby, :config, :logger, :run
|
40
37
|
|
38
|
+
# Internal: Reads metadata recorded on the last build, if it exists.
|
39
|
+
def last_build_attrs
|
40
|
+
last_build_path.exist? ? JSON.parse(last_build_path.read.to_s) : {}
|
41
|
+
rescue JSON::JSONError, Errno::ENOENT, Errno::ENOTDIR
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
|
41
45
|
# Internal: Writes a digest of the watched files to disk for future checks.
|
42
|
-
def record_build_metadata(
|
46
|
+
def record_build_metadata(success, build)
|
43
47
|
config.build_cache_dir.mkpath
|
44
|
-
build.with_result(
|
48
|
+
last_build_path.write build.with_result(success).to_json
|
45
49
|
end
|
46
50
|
|
47
51
|
# Internal: The file path where metadata of the last build is stored.
|
48
|
-
def last_build_path
|
49
|
-
config.build_cache_dir.join("last
|
52
|
+
def last_build_path
|
53
|
+
config.build_cache_dir.join("last-build-#{ config.mode }.json")
|
50
54
|
end
|
51
55
|
|
52
56
|
# Internal: Returns a digest of all the watched files, allowing to detect
|
53
57
|
# changes, and skip Vite builds if no files have changed.
|
54
58
|
def watched_files_digest
|
55
|
-
|
56
|
-
|
57
|
-
config.within_root do
|
59
|
+
Dir.chdir File.expand_path(config.root) do
|
58
60
|
files = Dir[*config.watched_paths].reject { |f| File.directory?(f) }
|
59
61
|
file_ids = files.sort.map { |f| "#{ File.basename(f) }/#{ Digest::SHA1.file(f).hexdigest }" }
|
60
|
-
|
61
|
-
@last_digest = Digest::SHA1.hexdigest(file_ids.join('/'))
|
62
|
+
Digest::SHA1.hexdigest(file_ids.join('/'))
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
65
66
|
# Public: Initiates a Vite build command to generate assets.
|
67
|
+
#
|
68
|
+
# Returns true if the build is successful, or false if it failed.
|
66
69
|
def build_with_vite(*args)
|
67
70
|
logger.info 'Building with Vite ⚡️'
|
68
71
|
|
69
|
-
run(['build', *args])
|
72
|
+
stdout, stderr, status = run(['build', *args])
|
73
|
+
log_build_result(stdout, stderr.to_s, status)
|
74
|
+
|
75
|
+
status.success?
|
70
76
|
end
|
71
77
|
|
72
78
|
# Internal: Outputs the build results.
|
@@ -75,10 +81,9 @@ private
|
|
75
81
|
def log_build_result(_stdout, stderr, status)
|
76
82
|
if status.success?
|
77
83
|
logger.info "Build with Vite complete: #{ config.build_output_dir }"
|
78
|
-
logger.error stderr unless stderr.empty?
|
84
|
+
logger.error stderr.to_s unless stderr.empty?
|
79
85
|
else
|
80
86
|
logger.error stderr
|
81
|
-
logger.error status
|
82
87
|
logger.error 'Build with Vite failed! ❌'
|
83
88
|
logger.error '❌ Check that vite and vite-plugin-ruby are in devDependencies and have been installed. ' if stderr.include?('ERR! canceled')
|
84
89
|
end
|
data/lib/vite_ruby/cli/build.rb
CHANGED
@@ -5,10 +5,8 @@ class ViteRuby::CLI::Build < ViteRuby::CLI::Vite
|
|
5
5
|
|
6
6
|
desc 'Bundle all entrypoints using Vite.'
|
7
7
|
shared_options
|
8
|
-
option(:ssr, desc: 'Build the SSR entrypoint instead', type: :boolean)
|
9
8
|
option(:force, desc: 'Force the build even if assets have not changed', type: :boolean)
|
10
9
|
option(:watch, desc: 'Start the Rollup watcher and rebuild on files changes', type: :boolean)
|
11
|
-
option(:profile, desc: 'Gather performance metrics from the build ', type: :boolean)
|
12
10
|
|
13
11
|
def call(**options)
|
14
12
|
super { |args| ViteRuby.commands.build_from_task(*args) }
|
@@ -1,16 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'stringio'
|
4
|
-
require 'json'
|
5
4
|
|
6
5
|
class ViteRuby::CLI::Install < Dry::CLI::Command
|
7
6
|
desc 'Performs the initial configuration setup to get started with Vite Ruby.'
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
def call(package_manager: nil, **)
|
12
|
-
ENV['VITE_RUBY_PACKAGE_MANAGER'] ||= package_manager if package_manager
|
13
|
-
|
8
|
+
def call(**)
|
14
9
|
$stdout.sync = true
|
15
10
|
|
16
11
|
say 'Creating binstub'
|
@@ -84,20 +79,9 @@ private
|
|
84
79
|
# Internal: Installs vite and vite-plugin-ruby at the project level.
|
85
80
|
def install_js_dependencies
|
86
81
|
package_json = root.join('package.json')
|
87
|
-
unless package_json.exist?
|
88
|
-
|
89
|
-
|
90
|
-
"private": true,
|
91
|
-
"type": "module"
|
92
|
-
}
|
93
|
-
JSON
|
94
|
-
end
|
95
|
-
|
96
|
-
if (JSON.parse(package_json.read)['type'] != 'module' rescue nil)
|
97
|
-
FileUtils.mv root.join('vite.config.ts'), root.join('vite.config.mts'), force: true, verbose: true
|
98
|
-
end
|
99
|
-
|
100
|
-
install_js_packages js_dependencies.join(' ')
|
82
|
+
write(package_json, '{}') unless package_json.exist?
|
83
|
+
deps = js_dependencies.join(' ')
|
84
|
+
run_with_capture("#{ npm_install } -D #{ deps }", stdin_data: "\n")
|
101
85
|
end
|
102
86
|
|
103
87
|
# Internal: Adds compilation output dirs to git ignore.
|
@@ -107,7 +91,9 @@ private
|
|
107
91
|
append(gitignore_file, <<~GITIGNORE)
|
108
92
|
|
109
93
|
# Vite Ruby
|
110
|
-
/public/vite
|
94
|
+
/public/vite
|
95
|
+
/public/vite-dev
|
96
|
+
/public/vite-test
|
111
97
|
node_modules
|
112
98
|
# Vite uses dotenv and suggests to ignore local-only env files. See
|
113
99
|
# https://vitejs.dev/guide/env-and-mode.html#env-files
|
@@ -127,12 +113,16 @@ private
|
|
127
113
|
def run_with_capture(*args, **options)
|
128
114
|
Dir.chdir(root) do
|
129
115
|
_, stderr, status = ViteRuby::IO.capture(*args, **options)
|
130
|
-
say(stderr) unless status.success? || stderr.empty?
|
116
|
+
say(stderr) unless status.success? || stderr.to_s.empty?
|
131
117
|
end
|
132
118
|
end
|
133
119
|
|
134
|
-
|
135
|
-
|
120
|
+
# Internal: Support all popular package managers.
|
121
|
+
def npm_install
|
122
|
+
return 'yarn add' if root.join('yarn.lock').exist?
|
123
|
+
return 'pnpm install' if root.join('pnpm-lock.yaml').exist?
|
124
|
+
|
125
|
+
'npm install'
|
136
126
|
end
|
137
127
|
|
138
128
|
# Internal: Avoid printing warning about missing vite.json, we will create one.
|
@@ -144,3 +134,8 @@ private
|
|
144
134
|
$stderr = old_stderr
|
145
135
|
end
|
146
136
|
end
|
137
|
+
|
138
|
+
# NOTE: This allows framework-specific variants to extend the installation.
|
139
|
+
ViteRuby.framework_libraries.each do |_framework, library|
|
140
|
+
require "#{ library.name.tr('-', '/') }/installation"
|
141
|
+
end
|
data/lib/vite_ruby/cli/vite.rb
CHANGED
@@ -3,33 +3,18 @@
|
|
3
3
|
class ViteRuby::CLI::Vite < Dry::CLI::Command
|
4
4
|
CURRENT_ENV = ENV['RACK_ENV'] || ENV['RAILS_ENV']
|
5
5
|
|
6
|
-
def self.
|
6
|
+
def self.shared_options
|
7
7
|
option(:mode, default: self::DEFAULT_ENV, values: %w[development production test], aliases: ['m'], desc: 'The build mode for Vite')
|
8
|
-
option(:
|
8
|
+
option(:clobber, desc: 'Clear cache and previous builds', type: :boolean, aliases: %w[clean clear])
|
9
|
+
option(:debug, desc: 'Run Vite in verbose mode, printing all debugging output', aliases: ['verbose'], type: :boolean)
|
9
10
|
option(:inspect, desc: 'Run Vite in a debugging session with node --inspect-brk', aliases: ['inspect-brk'], type: :boolean)
|
10
11
|
option(:trace_deprecation, desc: 'Run Vite in debugging mode with node --trace-deprecation', aliases: ['trace-deprecation'], type: :boolean)
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
executable_options
|
15
|
-
option(:debug, desc: 'Run Vite in verbose mode, printing all debugging output', aliases: ['verbose'], type: :boolean)
|
16
|
-
option(:clobber, desc: 'Clear cache and previous builds', type: :boolean, aliases: %w[clean clear])
|
17
|
-
end
|
18
|
-
|
19
|
-
def call(mode:, args: [], clobber: false, node_options: nil, inspect: nil, trace_deprecation: nil, **boolean_opts)
|
14
|
+
def call(mode:, args: [], clobber: false, **boolean_opts)
|
20
15
|
ViteRuby.env['VITE_RUBY_MODE'] = mode
|
21
16
|
ViteRuby.commands.clobber if clobber
|
22
|
-
|
23
|
-
node_options = [
|
24
|
-
node_options,
|
25
|
-
('--inspect-brk' if inspect),
|
26
|
-
('--trace-deprecation' if trace_deprecation),
|
27
|
-
].compact.join(' ')
|
28
|
-
|
29
|
-
args << %(--node-options="#{ node_options }") unless node_options.empty?
|
30
|
-
|
31
17
|
boolean_opts.map { |name, value| args << "--#{ name }" if value }
|
32
|
-
|
33
18
|
yield(args)
|
34
19
|
end
|
35
20
|
end
|
data/lib/vite_ruby/cli.rb
CHANGED
@@ -11,20 +11,7 @@ class ViteRuby::CLI
|
|
11
11
|
register 'clobber', Clobber, aliases: %w[clean clear]
|
12
12
|
register 'dev', Dev, aliases: %w[d serve]
|
13
13
|
register 'install', Install
|
14
|
-
register 'ssr', SSR
|
15
14
|
register 'version', Version, aliases: ['v', '-v', '--version', 'info']
|
16
15
|
register 'upgrade', Upgrade, aliases: ['update']
|
17
16
|
register 'upgrade_packages', UpgradePackages, aliases: ['update_packages']
|
18
|
-
|
19
|
-
# Internal: Allows framework-specific variants to extend the CLI.
|
20
|
-
def self.require_framework_libraries(path = 'cli')
|
21
|
-
ViteRuby.framework_libraries.each do |_framework, library|
|
22
|
-
require [library.name.tr('-', '/').to_s, path].compact.join('/')
|
23
|
-
end
|
24
|
-
rescue LoadError
|
25
|
-
require_framework_libraries 'installation' unless path == 'installation'
|
26
|
-
end
|
27
17
|
end
|
28
|
-
|
29
|
-
# NOTE: This allows framework-specific variants to extend the CLI.
|
30
|
-
ViteRuby::CLI.require_framework_libraries('cli')
|
data/lib/vite_ruby/commands.rb
CHANGED
@@ -23,25 +23,47 @@ class ViteRuby::Commands
|
|
23
23
|
|
24
24
|
# Public: Removes all build cache and previously compiled assets.
|
25
25
|
def clobber
|
26
|
-
dirs = [config.build_output_dir, config.
|
26
|
+
dirs = [config.build_output_dir, config.build_cache_dir, config.vite_cache_dir]
|
27
27
|
dirs.each { |dir| dir.rmtree if dir.exist? }
|
28
28
|
$stdout.puts "Removed vite cache and output dirs:\n\t#{ dirs.join("\n\t") }"
|
29
29
|
end
|
30
30
|
|
31
|
-
#
|
32
|
-
def
|
33
|
-
|
34
|
-
|
31
|
+
# Public: Receives arguments from a rake task.
|
32
|
+
def clean_from_task(args)
|
33
|
+
ensure_log_goes_to_stdout {
|
34
|
+
clean(keep_up_to: Integer(args.keep || 2), age_in_seconds: Integer(args.age || 3600))
|
35
|
+
}
|
35
36
|
end
|
36
37
|
|
37
|
-
#
|
38
|
-
|
39
|
-
|
38
|
+
# Public: Cleanup old assets in the output directory.
|
39
|
+
#
|
40
|
+
# keep_up_to - Max amount of backups to preserve.
|
41
|
+
# age_in_seconds - Amount of time to look back in order to preserve them.
|
42
|
+
#
|
43
|
+
# NOTE: By default keeps the last version, or 2 if created in the past hour.
|
44
|
+
#
|
45
|
+
# Examples:
|
46
|
+
# To force only 1 backup to be kept: clean(1, 0)
|
47
|
+
# To only keep files created within the last 10 minutes: clean(0, 600)
|
48
|
+
def clean(keep_up_to: 2, age_in_seconds: 3600)
|
49
|
+
return false unless may_clean?
|
50
|
+
|
51
|
+
versions
|
52
|
+
.each_with_index
|
53
|
+
.drop_while { |(mtime, _), index|
|
54
|
+
max_age = [0, Time.now - Time.at(mtime)].max
|
55
|
+
max_age < age_in_seconds || index < keep_up_to
|
56
|
+
}
|
57
|
+
.each do |(_, files), _|
|
58
|
+
clean_files(files)
|
59
|
+
end
|
60
|
+
true
|
40
61
|
end
|
41
62
|
|
42
|
-
# Internal:
|
43
|
-
def
|
44
|
-
`
|
63
|
+
# Internal: Installs the binstub for the CLI in the appropriate path.
|
64
|
+
def install_binstubs
|
65
|
+
`bundle binstub vite_ruby --path #{ config.root.join('bin') }`
|
66
|
+
`bundle config --delete bin`
|
45
67
|
end
|
46
68
|
|
47
69
|
# Internal: Verifies if ViteRuby is properly installed.
|
@@ -68,7 +90,7 @@ class ViteRuby::Commands
|
|
68
90
|
|
69
91
|
# Internal: Prints information about ViteRuby's environment.
|
70
92
|
def print_info
|
71
|
-
config.
|
93
|
+
Dir.chdir(config.root) do
|
72
94
|
$stdout.puts "bin/vite present?: #{ File.exist? 'bin/vite' }"
|
73
95
|
|
74
96
|
$stdout.puts "vite_ruby: #{ ViteRuby::VERSION }"
|
@@ -77,11 +99,11 @@ class ViteRuby::Commands
|
|
77
99
|
$stdout.puts "#{ framework }: #{ Gem.loaded_specs[framework]&.version }"
|
78
100
|
end
|
79
101
|
|
80
|
-
$stdout.puts "ruby: #{ `ruby --version` }"
|
81
102
|
$stdout.puts "node: #{ `node --version` }"
|
82
|
-
|
83
|
-
|
84
|
-
$stdout.puts "
|
103
|
+
$stdout.puts "npm: #{ `npm --version` }"
|
104
|
+
$stdout.puts "yarn: #{ `yarn --version` rescue nil }"
|
105
|
+
$stdout.puts "pnpm: #{ `pnpm --version` rescue nil }"
|
106
|
+
$stdout.puts "ruby: #{ `ruby --version` }"
|
85
107
|
|
86
108
|
$stdout.puts "\n"
|
87
109
|
packages = `npm ls vite vite-plugin-ruby`
|
@@ -98,6 +120,29 @@ private
|
|
98
120
|
|
99
121
|
def_delegators :@vite_ruby, :config, :builder, :manifest, :logger, :logger=
|
100
122
|
|
123
|
+
def may_clean?
|
124
|
+
config.build_output_dir.exist? && config.manifest_path.exist?
|
125
|
+
end
|
126
|
+
|
127
|
+
def clean_files(files)
|
128
|
+
files.select { |file| File.file?(file) }.each do |file|
|
129
|
+
File.delete(file)
|
130
|
+
logger.info("Removed #{ file }")
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def versions
|
135
|
+
all_files = Dir.glob("#{ config.build_output_dir }/**/*")
|
136
|
+
entries = all_files - [config.manifest_path] - current_version_files
|
137
|
+
entries.reject { |file| File.directory?(file) }
|
138
|
+
.group_by { |file| File.mtime(file).utc.to_i }
|
139
|
+
.sort.reverse
|
140
|
+
end
|
141
|
+
|
142
|
+
def current_version_files
|
143
|
+
Dir.glob(manifest.refresh.values.map { |value| config.build_output_dir.join("#{ value['file'] }*") })
|
144
|
+
end
|
145
|
+
|
101
146
|
def with_node_env(env)
|
102
147
|
original = ENV['NODE_ENV']
|
103
148
|
ENV['NODE_ENV'] = env
|
@@ -24,7 +24,7 @@ module ViteRuby::CompatibilityCheck
|
|
24
24
|
raise ArgumentError, <<~ERROR
|
25
25
|
vite-plugin-ruby@#{ npm_req } might not be compatible with vite_ruby-#{ ViteRuby::VERSION }
|
26
26
|
|
27
|
-
You may disable this check if needed: https://vite-ruby.netlify.app/config/#
|
27
|
+
You may disable this check if needed: https://vite-ruby.netlify.app/config/#skipCompatibilityCheck
|
28
28
|
|
29
29
|
You may upgrade both by running:
|
30
30
|
|
data/lib/vite_ruby/config.rb
CHANGED
@@ -5,10 +5,6 @@ require 'json'
|
|
5
5
|
# Public: Allows to resolve configuration sourced from `config/vite.json` and
|
6
6
|
# environment variables, combining them with the default options.
|
7
7
|
class ViteRuby::Config
|
8
|
-
def origin
|
9
|
-
"#{ protocol }://#{ host_with_port }"
|
10
|
-
end
|
11
|
-
|
12
8
|
def protocol
|
13
9
|
https ? 'https' : 'http'
|
14
10
|
end
|
@@ -17,20 +13,14 @@ class ViteRuby::Config
|
|
17
13
|
"#{ host }:#{ port }"
|
18
14
|
end
|
19
15
|
|
20
|
-
# Internal: Path
|
21
|
-
def
|
22
|
-
|
23
|
-
# NOTE: Generated by Vite when `manifest: true`, which vite-plugin-ruby enables.
|
24
|
-
build_output_dir.join('.vite/manifest.json'),
|
25
|
-
|
26
|
-
# NOTE: Path where vite-plugin-ruby outputs the assets manifest file.
|
27
|
-
build_output_dir.join('.vite/manifest-assets.json'),
|
28
|
-
]
|
16
|
+
# Internal: Path where Vite outputs the manifest file.
|
17
|
+
def manifest_path
|
18
|
+
build_output_dir.join('manifest.json')
|
29
19
|
end
|
30
20
|
|
31
|
-
# Internal: Path
|
32
|
-
def
|
33
|
-
|
21
|
+
# Internal: Path where vite-plugin-ruby outputs the assets manifest file.
|
22
|
+
def assets_manifest_path
|
23
|
+
build_output_dir.join('manifest-assets.json')
|
34
24
|
end
|
35
25
|
|
36
26
|
# Public: The directory where Vite will store the built assets.
|
@@ -60,12 +50,12 @@ class ViteRuby::Config
|
|
60
50
|
end
|
61
51
|
|
62
52
|
# Public: Sets additional environment variables for vite-plugin-ruby.
|
63
|
-
def to_env
|
53
|
+
def to_env
|
64
54
|
CONFIGURABLE_WITH_ENV.each_with_object({}) do |option, env|
|
65
55
|
unless (value = @config[option]).nil?
|
66
56
|
env["#{ ViteRuby::ENV_PREFIX }_#{ option.upcase }"] = value.to_s
|
67
57
|
end
|
68
|
-
end.merge(
|
58
|
+
end.merge(ViteRuby.env)
|
69
59
|
end
|
70
60
|
|
71
61
|
# Internal: Files and directories that should be watched for changes.
|
@@ -80,11 +70,6 @@ class ViteRuby::Config
|
|
80
70
|
].freeze
|
81
71
|
end
|
82
72
|
|
83
|
-
# Internal: Changes the current directory to the root dir.
|
84
|
-
def within_root(&block)
|
85
|
-
Dir.chdir(File.expand_path(root), &block)
|
86
|
-
end
|
87
|
-
|
88
73
|
private
|
89
74
|
|
90
75
|
# Internal: Coerces all the configuration values, in case they were passed
|
@@ -92,11 +77,9 @@ private
|
|
92
77
|
def coerce_values(config)
|
93
78
|
config['mode'] = config['mode'].to_s
|
94
79
|
config['port'] = config['port'].to_i
|
95
|
-
config['root'] =
|
96
|
-
config['build_cache_dir'] = root.join(config['build_cache_dir'])
|
97
|
-
config
|
98
|
-
coerce_booleans(config, 'auto_build', 'hide_build_console_output', 'https', 'skip_compatibility_check', 'skip_proxy')
|
99
|
-
config['package_manager'] ||= detect_package_manager(root)
|
80
|
+
config['root'] = Pathname.new(config['root'])
|
81
|
+
config['build_cache_dir'] = config['root'].join(config['build_cache_dir'])
|
82
|
+
coerce_booleans(config, 'auto_build', 'hide_build_console_output', 'https', 'skip_compatibility_check')
|
100
83
|
end
|
101
84
|
|
102
85
|
# Internal: Coerces configuration options to boolean.
|
@@ -104,15 +87,6 @@ private
|
|
104
87
|
names.each { |name| config[name] = [true, 'true'].include?(config[name]) }
|
105
88
|
end
|
106
89
|
|
107
|
-
def detect_package_manager(root)
|
108
|
-
return 'npm' if root.join('package-lock.json').exist?
|
109
|
-
return 'pnpm' if root.join('pnpm-lock.yaml').exist?
|
110
|
-
return 'bun' if root.join('bun.lockb').exist?
|
111
|
-
return 'yarn' if root.join('yarn.lock').exist?
|
112
|
-
|
113
|
-
'npm'
|
114
|
-
end
|
115
|
-
|
116
90
|
def initialize(attrs)
|
117
91
|
@config = attrs.tap { |config| coerce_values(config) }.freeze
|
118
92
|
ViteRuby::CompatibilityCheck.verify_plugin_version(root) unless skip_compatibility_check
|
@@ -147,7 +121,7 @@ private
|
|
147
121
|
'config_path' => option_from_env('config_path') || DEFAULT_CONFIG.fetch('config_path'),
|
148
122
|
'mode' => option_from_env('mode') || mode,
|
149
123
|
'root' => option_from_env('root') || root,
|
150
|
-
}
|
124
|
+
}
|
151
125
|
end
|
152
126
|
|
153
127
|
# Internal: Used to load a JSON file from the specified path.
|
@@ -195,15 +169,12 @@ private
|
|
195
169
|
|
196
170
|
# Internal: If any of these files is modified the build won't be skipped.
|
197
171
|
DEFAULT_WATCHED_PATHS = %w[
|
198
|
-
bun.lockb
|
199
172
|
package-lock.json
|
200
173
|
package.json
|
201
174
|
pnpm-lock.yaml
|
202
175
|
postcss.config.js
|
203
176
|
tailwind.config.js
|
204
177
|
vite.config.js
|
205
|
-
vite.config.mjs
|
206
|
-
vite.config.mts
|
207
178
|
vite.config.ts
|
208
179
|
windi.config.ts
|
209
180
|
yarn.lock
|
@@ -38,7 +38,7 @@ private
|
|
38
38
|
uri
|
39
39
|
.sub(HOST_WITH_PORT_REGEX, '/') # Hanami adds the host and port.
|
40
40
|
.sub('.ts.js', '.ts') # Hanami's javascript helper always adds the extension.
|
41
|
-
.sub(
|
41
|
+
.sub(/(\.(?!min|module)\w+)\.css$/, '\1') # Rails' stylesheet_link_tag always adds the extension.
|
42
42
|
end
|
43
43
|
|
44
44
|
def forward_to_vite_dev_server(env)
|
@@ -54,22 +54,17 @@ private
|
|
54
54
|
|
55
55
|
def vite_should_handle?(env)
|
56
56
|
path = normalize_uri(env['PATH_INFO'])
|
57
|
-
return true if path.start_with?(
|
57
|
+
return true if path.start_with?(vite_asset_url_prefix) # Vite asset
|
58
|
+
return true if path.start_with?(VITE_DEPENDENCY_PREFIX) # Packages and imports
|
58
59
|
return true if file_in_vite_root?(path) # Fallback if Vite can serve the file
|
59
60
|
end
|
60
61
|
|
61
|
-
# NOTE: When using an empty 'public_output_dir', we need to rely on a
|
62
|
-
# filesystem check to check whether Vite should serve the request.
|
63
62
|
def file_in_vite_root?(path)
|
64
63
|
path.include?('.') && # Check for extension, avoid filesystem if possible.
|
65
64
|
config.vite_root_dir.join(path.start_with?('/') ? path[1..-1] : path).file?
|
66
65
|
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
#
|
71
|
-
# If the path starts with that prefix, it will be redirected to Vite.
|
72
|
-
def vite_url_prefix
|
73
|
-
@vite_url_prefix ||= config.public_output_dir.empty? ? VITE_DEPENDENCY_PREFIX : "/#{ config.public_output_dir }/"
|
67
|
+
def vite_asset_url_prefix
|
68
|
+
@vite_asset_url_prefix ||= config.public_output_dir.empty? ? "\0" : "/#{ config.public_output_dir }/"
|
74
69
|
end
|
75
70
|
end
|
data/lib/vite_ruby/io.rb
CHANGED
data/lib/vite_ruby/manifest.rb
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
# lookup_entrypoint('calendar', type: :javascript)
|
8
8
|
# => { "file" => "/vite/assets/calendar-1016838bab065ae1e314.js", "imports" => [] }
|
9
9
|
#
|
10
|
-
# NOTE: Using
|
10
|
+
# NOTE: Using "autoBuild": true` in `config/vite.json` file will trigger a build
|
11
11
|
# on demand as needed, before performing any lookup.
|
12
12
|
class ViteRuby::Manifest
|
13
13
|
def initialize(vite_ruby)
|
@@ -22,16 +22,15 @@ class ViteRuby::Manifest
|
|
22
22
|
lookup!(name, **options).fetch('file')
|
23
23
|
end
|
24
24
|
|
25
|
-
# Public: Returns
|
25
|
+
# Public: Returns entries, imported modules, and stylesheets for the specified
|
26
26
|
# entrypoint files.
|
27
27
|
def resolve_entries(*names, **options)
|
28
28
|
entries = names.map { |name| lookup!(name, **options) }
|
29
|
-
script_paths = entries.map { |entry| entry.fetch('file') }
|
30
29
|
|
31
30
|
imports = dev_server_running? ? [] : entries.flat_map { |entry| entry['imports'] }.compact.uniq
|
32
31
|
{
|
33
|
-
|
34
|
-
imports: imports.map
|
32
|
+
main: entries.map(&TO_ENTRY),
|
33
|
+
imports: imports.map(&TO_ENTRY).uniq,
|
35
34
|
stylesheets: dev_server_running? ? [] : (entries + imports).flat_map { |entry| entry['css'] }.compact.uniq,
|
36
35
|
}
|
37
36
|
end
|
@@ -51,27 +50,21 @@ class ViteRuby::Manifest
|
|
51
50
|
if dev_server_running?
|
52
51
|
<<~REACT_REFRESH
|
53
52
|
<script type="module">
|
54
|
-
#{
|
53
|
+
import RefreshRuntime from '#{ prefix_asset_with_host('@react-refresh') }'
|
54
|
+
RefreshRuntime.injectIntoGlobalHook(window)
|
55
|
+
window.$RefreshReg$ = () => {}
|
56
|
+
window.$RefreshSig$ = () => (type) => type
|
57
|
+
window.__vite_plugin_react_preamble_installed__ = true
|
55
58
|
</script>
|
56
59
|
REACT_REFRESH
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
60
|
-
# Public: Source script for the React Refresh plugin.
|
61
|
-
def react_preamble_code
|
62
|
-
if dev_server_running?
|
63
|
-
<<~REACT_PREAMBLE_CODE
|
64
|
-
import RefreshRuntime from '#{ prefix_asset_with_host('@react-refresh') }'
|
65
|
-
RefreshRuntime.injectIntoGlobalHook(window)
|
66
|
-
window.$RefreshReg$ = () => {}
|
67
|
-
window.$RefreshSig$ = () => (type) => type
|
68
|
-
window.__vite_plugin_react_preamble_installed__ = true
|
69
|
-
REACT_PREAMBLE_CODE
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
63
|
protected
|
74
64
|
|
65
|
+
# Internal: Returns a [src, attrs] entry.
|
66
|
+
TO_ENTRY = ->(entry) { [entry.fetch('file'), entry.slice('integrity').symbolize_keys] }
|
67
|
+
|
75
68
|
# Internal: Strict version of lookup.
|
76
69
|
#
|
77
70
|
# Returns a relative path for the asset, or raises an error if not found.
|
@@ -87,7 +80,7 @@ protected
|
|
87
80
|
# manifest.lookup('calendar.js')
|
88
81
|
# => { "file" => "/vite/assets/calendar-1016838bab065ae1e122.js", "imports" => [] }
|
89
82
|
def lookup(name, **options)
|
90
|
-
@build_mutex.synchronize { builder.build
|
83
|
+
@build_mutex.synchronize { builder.build } if should_build?
|
91
84
|
|
92
85
|
find_manifest_entry resolve_entry_name(name, **options)
|
93
86
|
end
|
@@ -128,24 +121,19 @@ private
|
|
128
121
|
|
129
122
|
# Internal: Loads and merges the manifest files, resolving the asset paths.
|
130
123
|
def load_manifest
|
131
|
-
files = config.
|
124
|
+
files = [config.manifest_path, config.assets_manifest_path].select(&:exist?)
|
132
125
|
files.map { |path| JSON.parse(path.read) }.inject({}, &:merge).tap(&method(:resolve_references))
|
133
126
|
end
|
134
127
|
|
135
128
|
# Internal: Scopes an asset to the output folder in public, as a path.
|
136
129
|
def prefix_vite_asset(path)
|
137
|
-
File.join(
|
130
|
+
File.join("/#{ config.public_output_dir }", path)
|
138
131
|
end
|
139
132
|
|
140
133
|
# Internal: Prefixes an asset with the `asset_host` for tags that do not use
|
141
134
|
# the framework tag helpers.
|
142
135
|
def prefix_asset_with_host(path)
|
143
|
-
File.join(
|
144
|
-
end
|
145
|
-
|
146
|
-
# Internal: The origin of assets managed by Vite.
|
147
|
-
def vite_asset_origin
|
148
|
-
config.origin if dev_server_running? && config.skip_proxy
|
136
|
+
File.join(config.asset_host || '/', config.public_output_dir, path)
|
149
137
|
end
|
150
138
|
|
151
139
|
# Internal: Resolves the paths that reference a manifest entry.
|
@@ -212,7 +200,7 @@ private
|
|
212
200
|
|
213
201
|
# Internal: Raises a detailed message when an entry is missing in the manifest.
|
214
202
|
def missing_entry_error(name, **options)
|
215
|
-
raise ViteRuby::MissingEntrypointError.new(
|
203
|
+
raise ViteRuby::MissingEntrypointError, OpenStruct.new(
|
216
204
|
file_name: resolve_entry_name(name, **options),
|
217
205
|
last_build: builder.last_build_metadata,
|
218
206
|
manifest: @manifest,
|