vite_ruby 3.9.1 → 4.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ class ViteRuby::Commands
9
9
 
10
10
  # Public: Defaults to production, and exits if the build fails.
11
11
  def build_from_task(*args)
12
- with_node_env(ENV.fetch("NODE_ENV", "production")) {
12
+ with_node_env(ENV.fetch('NODE_ENV', 'production')) {
13
13
  ensure_log_goes_to_stdout {
14
14
  build(*args) || exit!
15
15
  }
@@ -23,30 +23,52 @@ 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.ssr_output_dir, config.build_cache_dir, config.vite_cache_dir]
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
- $stdout.puts "Removed vite cache and output dirs:\n\t#{dirs.join("\n\t")}"
28
+ $stdout.puts "Removed vite cache and output dirs:\n\t#{ dirs.join("\n\t") }"
29
29
  end
30
30
 
31
- # Internal: Installs the binstub for the CLI in the appropriate path.
32
- def install_binstubs
33
- `bundle binstub vite_ruby --path #{config.root.join("bin")}`
34
- `bundle config --delete bin`
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
- # Internal: Checks if the npm version is 6 or lower.
38
- def legacy_npm_version?
39
- `npm --version`.to_i < 7 rescue false
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: Checks if the yarn version is 1.x.
43
- def legacy_yarn_version?
44
- `yarn --version`.to_i < 2 rescue false
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.
48
70
  def verify_install
49
- unless File.exist?(config.root.join("bin/vite"))
71
+ unless File.exist?(config.root.join('bin/vite'))
50
72
  warn <<~WARN
51
73
 
52
74
  vite binstub not found.
@@ -59,7 +81,7 @@ class ViteRuby::Commands
59
81
  unless config_path.exist?
60
82
  warn <<~WARN
61
83
 
62
- Configuration #{config_path} file for vite-plugin-ruby not found.
84
+ Configuration #{ config_path } file for vite-plugin-ruby not found.
63
85
  Make sure `bundle exec vite install` has run successfully before running dependent tasks.
64
86
  WARN
65
87
  exit!
@@ -68,24 +90,24 @@ class ViteRuby::Commands
68
90
 
69
91
  # Internal: Prints information about ViteRuby's environment.
70
92
  def print_info
71
- config.within_root do
72
- $stdout.puts "bin/vite present?: #{File.exist? "bin/vite"}"
93
+ Dir.chdir(config.root) do
94
+ $stdout.puts "bin/vite present?: #{ File.exist? 'bin/vite' }"
73
95
 
74
- $stdout.puts "vite_ruby: #{ViteRuby::VERSION}"
96
+ $stdout.puts "vite_ruby: #{ ViteRuby::VERSION }"
75
97
  ViteRuby.framework_libraries.each do |framework, library|
76
- $stdout.puts "#{library.name}: #{library.version}"
77
- $stdout.puts "#{framework}: #{Gem.loaded_specs[framework]&.version}"
98
+ $stdout.puts "#{ library.name }: #{ library.version }"
99
+ $stdout.puts "#{ framework }: #{ Gem.loaded_specs[framework]&.version }"
78
100
  end
79
101
 
80
- $stdout.puts "ruby: #{`ruby --version`}"
81
- $stdout.puts "node: #{`node --version`}"
82
-
83
- pkg = config.package_manager
84
- $stdout.puts "#{pkg}: #{`#{pkg} --version` rescue nil}"
102
+ $stdout.puts "node: #{ `node --version` }"
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`
88
- packages_msg = packages.include?("vite@") ? "installed packages:\n#{packages}" : "❌ Check that vite and vite-plugin-ruby have been added as development dependencies and installed."
110
+ packages_msg = packages.include?('vite@') ? "installed packages:\n#{ packages }" : '❌ Check that vite and vite-plugin-ruby have been added as development dependencies and installed.'
89
111
  $stdout.puts packages_msg
90
112
 
91
113
  ViteRuby::CompatibilityCheck.verify_plugin_version(config.root)
@@ -98,19 +120,42 @@ 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
- original = ENV["NODE_ENV"]
103
- ENV["NODE_ENV"] = env
147
+ original = ENV['NODE_ENV']
148
+ ENV['NODE_ENV'] = env
104
149
  yield
105
150
  ensure
106
- ENV["NODE_ENV"] = original
151
+ ENV['NODE_ENV'] = original
107
152
  end
108
153
 
109
154
  def ensure_log_goes_to_stdout
110
155
  old_logger, original_sync = logger, $stdout.sync
111
156
 
112
157
  $stdout.sync = true
113
- self.logger = Logger.new($stdout, formatter: proc { |_, _, progname, msg| (progname == "vite") ? msg : "#{msg}\n" })
158
+ self.logger = Logger.new($stdout, formatter: proc { |_, _, progname, msg| progname == 'vite' ? msg : "#{ msg }\n" })
114
159
  yield
115
160
  ensure
116
161
  self.logger, $stdout.sync = old_logger, original_sync
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
3
+ require 'json'
4
4
 
5
5
  # Internal: Verifies that the installed vite-plugin-ruby version is compatible
6
6
  # with the current version of vite_ruby.
@@ -11,9 +11,9 @@ module ViteRuby::CompatibilityCheck
11
11
  class << self
12
12
  # Public: Attempt to verify that the vite-plugin-ruby version is compatible.
13
13
  def verify_plugin_version(root)
14
- package = JSON.parse(root.join("package.json").read) rescue {}
15
- requirement = package.dig("devDependencies", "vite-plugin-ruby") ||
16
- package.dig("dependencies", "vite-plugin-ruby")
14
+ package = JSON.parse(root.join('package.json').read) rescue {}
15
+ requirement = package.dig('devDependencies', 'vite-plugin-ruby') ||
16
+ package.dig('dependencies', 'vite-plugin-ruby')
17
17
 
18
18
  raise_unless_satisfied(requirement, ViteRuby::DEFAULT_PLUGIN_VERSION)
19
19
  end
@@ -22,9 +22,9 @@ module ViteRuby::CompatibilityCheck
22
22
  def raise_unless_satisfied(npm_req, ruby_req)
23
23
  unless compatible_plugin?(npm_req, ruby_req)
24
24
  raise ArgumentError, <<~ERROR
25
- vite-plugin-ruby@#{npm_req} might not be compatible with vite_ruby-#{ViteRuby::VERSION}
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/#skipcompatibilitycheck
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
 
@@ -37,12 +37,12 @@ module ViteRuby::CompatibilityCheck
37
37
  # requirement.
38
38
  def compatible_plugin?(npm_req, ruby_req)
39
39
  npm_req, ruby_req = [npm_req, ruby_req]
40
- .map { |req| Gem::Requirement.new(req.sub("^", "~>")) }
40
+ .map { |req| Gem::Requirement.new(req.sub('^', '~>')) }
41
41
 
42
42
  current_version = npm_req.requirements.first.second
43
43
 
44
44
  ruby_req.satisfied_by?(current_version)
45
- rescue
45
+ rescue StandardError
46
46
  true
47
47
  end
48
48
  end
@@ -1,36 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json"
3
+ require 'json'
4
4
 
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
- https ? "https" : "http"
9
+ https ? 'https' : 'http'
14
10
  end
15
11
 
16
12
  def host_with_port
17
- "#{host}:#{port}"
13
+ "#{ host }:#{ port }"
18
14
  end
19
15
 
20
- # Internal: Path to the manifest files generated by Vite and vite-plugin-ruby.
21
- def known_manifest_paths
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 to the manifest files generated by Vite and vite-plugin-ruby.
32
- def manifest_paths
33
- known_manifest_paths.select(&:exist?)
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.
@@ -45,7 +35,7 @@ class ViteRuby::Config
45
35
 
46
36
  # Internal: The directory where Vite stores its processing cache.
47
37
  def vite_cache_dir
48
- root.join("node_modules/.vite")
38
+ root.join('node_modules/.vite')
49
39
  end
50
40
 
51
41
  # Public: The directory that Vite uses as root.
@@ -55,63 +45,46 @@ class ViteRuby::Config
55
45
 
56
46
  # Public: Loads an optional config/vite.rb file that can modify ViteRuby.env
57
47
  def load_ruby_config
58
- rb_config_path = File.expand_path(config_path.sub(/.json$/, ".rb"), root)
48
+ rb_config_path = File.expand_path(config_path.sub(/.json$/, '.rb'), root)
59
49
  load rb_config_path if File.exist?(rb_config_path)
60
50
  end
61
51
 
62
52
  # Public: Sets additional environment variables for vite-plugin-ruby.
63
- def to_env(env_vars = ViteRuby.env)
53
+ def to_env
64
54
  CONFIGURABLE_WITH_ENV.each_with_object({}) do |option, env|
65
55
  unless (value = @config[option]).nil?
66
- env["#{ViteRuby::ENV_PREFIX}_#{option.upcase}"] = value.to_s
56
+ env["#{ ViteRuby::ENV_PREFIX }_#{ option.upcase }"] = value.to_s
67
57
  end
68
- end.merge(env_vars)
58
+ end.merge(ViteRuby.env)
69
59
  end
70
60
 
71
61
  # Internal: Files and directories that should be watched for changes.
72
62
  def watched_paths
73
63
  [
74
64
  *(watch_additional_paths + additional_entrypoints).reject { |dir|
75
- dir.start_with?("~/") || dir.start_with?(source_code_dir)
65
+ dir.start_with?('~/') || dir.start_with?(source_code_dir)
76
66
  },
77
- "#{source_code_dir}/**/*",
78
- config_path.sub(/.json$/, ".{rb,json}"),
67
+ "#{ source_code_dir }/**/*",
68
+ config_path.sub(/.json$/, '.{rb,json}'),
79
69
  *DEFAULT_WATCHED_PATHS,
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
91
76
  # as environment variables which are always strings.
92
77
  def coerce_values(config)
93
- config["mode"] = config["mode"].to_s
94
- config["port"] = config["port"].to_i
95
- config["root"] = root = Pathname.new(config["root"])
96
- config["build_cache_dir"] = root.join(config["build_cache_dir"])
97
- config["ssr_output_dir"] = root.join(config["ssr_output_dir"])
98
- coerce_booleans(config, "auto_build", "hide_build_console_output", "https", "skip_compatibility_check", "skip_proxy")
99
- config["package_manager"] ||= detect_package_manager(root)
78
+ config['mode'] = config['mode'].to_s
79
+ config['port'] = config['port'].to_i
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.
103
86
  def coerce_booleans(config, *names)
104
- truthy = [true, "true"]
105
- names.each { |name| config[name] = truthy.include?(config[name]) }
106
- end
107
-
108
- def detect_package_manager(root)
109
- return "npm" if root.join("package-lock.json").exist?
110
- return "pnpm" if root.join("pnpm-lock.yaml").exist?
111
- return "bun" if root.join("bun.lockb").exist?
112
- return "yarn" if root.join("yarn.lock").exist?
113
-
114
- "npm"
87
+ names.each { |name| config[name] = [true, 'true'].include?(config[name]) }
115
88
  end
116
89
 
117
90
  def initialize(attrs)
@@ -125,8 +98,8 @@ private
125
98
  # Public: Returns the project configuration for Vite.
126
99
  def resolve_config(**attrs)
127
100
  config = config_defaults.merge(attrs.transform_keys(&:to_s))
128
- file_path = File.join(config["root"], config["config_path"])
129
- file_config = config_from_file(file_path, mode: config["mode"])
101
+ file_path = File.join(config['root'], config['config_path'])
102
+ file_config = config_from_file(file_path, mode: config['mode'])
130
103
  new DEFAULT_CONFIG.merge(file_config).merge(config_from_env).merge(config)
131
104
  end
132
105
 
@@ -134,21 +107,21 @@ private
134
107
 
135
108
  # Internal: Converts camelCase to snake_case.
136
109
  SNAKE_CASE = ->(camel_cased_word) {
137
- camel_cased_word.to_s.gsub("::", "/")
110
+ camel_cased_word.to_s.gsub(/::/, '/')
138
111
  .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
139
112
  .gsub(/([a-z\d])([A-Z])/, '\1_\2')
140
- .tr("-", "_")
113
+ .tr('-', '_')
141
114
  .downcase
142
115
  }
143
116
 
144
117
  # Internal: Default values for a Ruby application.
145
- def config_defaults(asset_host: nil, mode: ENV.fetch("RACK_ENV", "development"), root: Dir.pwd)
118
+ def config_defaults(asset_host: nil, mode: ENV.fetch('RACK_ENV', 'development'), root: Dir.pwd)
146
119
  {
147
- "asset_host" => option_from_env("asset_host") || asset_host,
148
- "config_path" => option_from_env("config_path") || DEFAULT_CONFIG.fetch("config_path"),
149
- "mode" => option_from_env("mode") || mode,
150
- "root" => option_from_env("root") || root,
151
- }.select { |_, value| value }
120
+ 'asset_host' => option_from_env('asset_host') || asset_host,
121
+ 'config_path' => option_from_env('config_path') || DEFAULT_CONFIG.fetch('config_path'),
122
+ 'mode' => option_from_env('mode') || mode,
123
+ 'root' => option_from_env('root') || root,
124
+ }
152
125
  end
153
126
 
154
127
  # Internal: Used to load a JSON file from the specified path.
@@ -162,7 +135,7 @@ private
162
135
 
163
136
  # Internal: Retrieves a configuration option from environment variables.
164
137
  def option_from_env(name)
165
- ViteRuby.env["#{ViteRuby::ENV_PREFIX}_#{name.upcase}"]
138
+ ViteRuby.env["#{ ViteRuby::ENV_PREFIX }_#{ name.upcase }"]
166
139
  end
167
140
 
168
141
  # Internal: Extracts the configuration options provided as env vars.
@@ -177,16 +150,16 @@ private
177
150
  # Internal: Loads the configuration options provided in a JSON file.
178
151
  def config_from_file(path, mode:)
179
152
  multi_env_config = load_json(path)
180
- multi_env_config.fetch("all", {})
153
+ multi_env_config.fetch('all', {})
181
154
  .merge(multi_env_config.fetch(mode, {}))
182
155
  rescue Errno::ENOENT => error
183
- $stderr << "Check that your vite.json configuration file is available in the load path:\n\n\t#{error.message}\n\n"
156
+ $stderr << "Check that your vite.json configuration file is available in the load path:\n\n\t#{ error.message }\n\n"
184
157
  {}
185
158
  end
186
159
  end
187
160
 
188
161
  # Internal: Shared configuration with the Vite plugin for Ruby.
189
- DEFAULT_CONFIG = load_json("#{__dir__}/../../default.vite.json").freeze
162
+ DEFAULT_CONFIG = load_json("#{ __dir__ }/../../default.vite.json").freeze
190
163
 
191
164
  # Internal: Configuration options that can not be provided as env vars.
192
165
  NOT_CONFIGURABLE_WITH_ENV = %w[additional_entrypoints watch_additional_paths].freeze
@@ -196,15 +169,12 @@ private
196
169
 
197
170
  # Internal: If any of these files is modified the build won't be skipped.
198
171
  DEFAULT_WATCHED_PATHS = %w[
199
- bun.lockb
200
172
  package-lock.json
201
173
  package.json
202
174
  pnpm-lock.yaml
203
175
  postcss.config.js
204
176
  tailwind.config.js
205
177
  vite.config.js
206
- vite.config.mjs
207
- vite.config.mts
208
178
  vite.config.ts
209
179
  windi.config.ts
210
180
  yarn.lock
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rack/proxy"
3
+ require 'rack/proxy'
4
4
 
5
5
  # Public: Allows to relay asset requests to the Vite development server.
6
6
  class ViteRuby::DevServerProxy < Rack::Proxy
7
7
  HOST_WITH_PORT_REGEX = %r{^(.+?)(:\d+)/}
8
- VITE_DEPENDENCY_PREFIX = "/@"
8
+ VITE_DEPENDENCY_PREFIX = '/@'
9
9
 
10
10
  def initialize(app = nil, options = {})
11
11
  @vite_ruby = options.delete(:vite_ruby) || ViteRuby.instance
12
- options[:streaming] = false if config.mode == "test" && !options.key?(:streaming)
12
+ options[:streaming] = false if config.mode == 'test' && !options.key?(:streaming)
13
13
  super
14
14
  end
15
15
 
@@ -17,7 +17,7 @@ class ViteRuby::DevServerProxy < Rack::Proxy
17
17
  def perform_request(env)
18
18
  if vite_should_handle?(env) && dev_server_running?
19
19
  forward_to_vite_dev_server(env)
20
- super
20
+ super(env)
21
21
  else
22
22
  @app.call(env)
23
23
  end
@@ -30,47 +30,41 @@ private
30
30
  def_delegators :@vite_ruby, :config, :dev_server_running?
31
31
 
32
32
  def rewrite_uri_for_vite(env)
33
- uri = env.fetch("REQUEST_URI") { [env["PATH_INFO"], env["QUERY_STRING"]].reject { |str| str.to_s.strip.empty? }.join("?") }
34
- env["PATH_INFO"], env["QUERY_STRING"] = (env["REQUEST_URI"] = normalize_uri(uri)).split("?")
33
+ uri = env.fetch('REQUEST_URI') { [env['PATH_INFO'], env['QUERY_STRING']].reject { |str| str.to_s.strip.empty? }.join('?') }
34
+ env['PATH_INFO'], env['QUERY_STRING'] = (env['REQUEST_URI'] = normalize_uri(uri)).split('?')
35
35
  end
36
36
 
37
37
  def normalize_uri(uri)
38
38
  uri
39
- .sub(HOST_WITH_PORT_REGEX, "/") # Hanami adds the host and port.
40
- .sub(".ts.js", ".ts") # Hanami's javascript helper always adds the extension.
41
- .sub(/\.(sass|scss|styl|stylus|less|pcss|postcss)\.css$/, '.\1') # Rails' stylesheet_link_tag always adds the extension.
39
+ .sub(HOST_WITH_PORT_REGEX, '/') # Hanami adds the host and port.
40
+ .sub('.ts.js', '.ts') # Hanami's javascript helper always adds the extension.
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)
45
45
  rewrite_uri_for_vite(env)
46
- env["QUERY_STRING"] ||= ""
47
- env["HTTP_HOST"] = env["HTTP_X_FORWARDED_HOST"] = config.host
48
- env["HTTP_X_FORWARDED_SERVER"] = config.host_with_port
49
- env["HTTP_PORT"] = env["HTTP_X_FORWARDED_PORT"] = config.port.to_s
50
- env["HTTP_X_FORWARDED_PROTO"] = env["HTTP_X_FORWARDED_SCHEME"] = config.protocol
51
- env["HTTPS"] = env["HTTP_X_FORWARDED_SSL"] = "off" unless config.https
52
- env["SCRIPT_NAME"] = ""
46
+ env['QUERY_STRING'] ||= ''
47
+ env['HTTP_HOST'] = env['HTTP_X_FORWARDED_HOST'] = config.host
48
+ env['HTTP_X_FORWARDED_SERVER'] = config.host_with_port
49
+ env['HTTP_PORT'] = env['HTTP_X_FORWARDED_PORT'] = config.port.to_s
50
+ env['HTTP_X_FORWARDED_PROTO'] = env['HTTP_X_FORWARDED_SCHEME'] = config.protocol
51
+ env['HTTPS'] = env['HTTP_X_FORWARDED_SSL'] = 'off' unless config.https
52
+ env['SCRIPT_NAME'] = ''
53
53
  end
54
54
 
55
55
  def vite_should_handle?(env)
56
- path = normalize_uri(env["PATH_INFO"])
57
- return true if path.start_with?(vite_url_prefix) # Vite asset
58
-
59
- true if file_in_vite_root?(path) # Fallback if Vite can serve the file
56
+ path = normalize_uri(env['PATH_INFO'])
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
59
+ return true if file_in_vite_root?(path) # Fallback if Vite can serve the file
60
60
  end
61
61
 
62
- # NOTE: When using an empty 'public_output_dir', we need to rely on a
63
- # filesystem check to check whether Vite should serve the request.
64
62
  def file_in_vite_root?(path)
65
- path.include?(".") && # Check for extension, avoid filesystem if possible.
66
- config.vite_root_dir.join(path.start_with?("/") ? path[1..] : path).file?
63
+ path.include?('.') && # Check for extension, avoid filesystem if possible.
64
+ config.vite_root_dir.join(path.start_with?('/') ? path[1..-1] : path).file?
67
65
  end
68
66
 
69
- # NOTE: Vite is configured to use 'public_output_dir' as the base, which can
70
- # be customized by the user in development to not match any of the routes.
71
- #
72
- # If the path starts with that prefix, it will be redirected to Vite.
73
- def vite_url_prefix
74
- @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 }/"
75
69
  end
76
70
  end
@@ -3,7 +3,7 @@
3
3
  # Internal: Provides common functionality for errors.
4
4
  class ViteRuby::Error < StandardError
5
5
  def message
6
- super.sub(":troubleshooting:", <<~MSG)
6
+ super.sub(':troubleshooting:', <<~MSG)
7
7
  Visit the Troubleshooting guide for more information:
8
8
  https://vite-ruby.netlify.app/guide/troubleshooting.html#troubleshooting
9
9
  MSG
data/lib/vite_ruby/io.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "open3"
3
+ require 'open3'
4
4
 
5
5
  # Public: Builds on top of Ruby I/O open3 providing a friendlier experience.
6
6
  module ViteRuby::IO
7
7
  class << self
8
8
  # Internal: A modified version of capture3 that can continuosly print stdout.
9
9
  # NOTE: Streaming output provides a better UX when running bin/vite build.
10
- def capture(*cmd, with_output: $stdout.method(:puts), stdin_data: "", **opts)
10
+ def capture(*cmd, with_output: $stdout.method(:puts), stdin_data: '', **opts)
11
11
  return Open3.capture3(*cmd, **opts) unless with_output
12
12
 
13
13
  Open3.popen3(*cmd, **opts) { |stdin, stdout, stderr, wait_threads|
@@ -15,13 +15,13 @@ module ViteRuby::IO
15
15
  stdin.close
16
16
  out = Thread.new { read_lines(stdout, &with_output) }
17
17
  err = Thread.new { stderr.read }
18
- [out.value, err.value.to_s, wait_threads.value]
18
+ [out.value, err.value, wait_threads.value]
19
19
  }
20
20
  end
21
21
 
22
22
  # Internal: Reads and yield every line in the stream. Returns the full content.
23
23
  def read_lines(io)
24
- buffer = +""
24
+ buffer = +''
25
25
  while line = io.gets
26
26
  buffer << line
27
27
  yield line