vite_rails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +34 -0
- data/LICENSE.txt +21 -0
- data/README.md +64 -0
- data/lib/install/binstubs.rb +6 -0
- data/lib/install/template.rb +62 -0
- data/lib/vite_rails.rb +91 -0
- data/lib/vite_rails/builder.rb +113 -0
- data/lib/vite_rails/commands.rb +68 -0
- data/lib/vite_rails/config.rb +106 -0
- data/lib/vite_rails/dev_server.rb +23 -0
- data/lib/vite_rails/dev_server_proxy.rb +47 -0
- data/lib/vite_rails/engine.rb +40 -0
- data/lib/vite_rails/helper.rb +41 -0
- data/lib/vite_rails/manifest.rb +134 -0
- data/lib/vite_rails/runner.rb +56 -0
- data/lib/vite_rails/version.rb +5 -0
- data/package.json +28 -0
- data/package/default.vite.json +15 -0
- data/test/builder_test.rb +72 -0
- data/test/command_test.rb +35 -0
- data/test/configuration_test.rb +80 -0
- data/test/dev_server_runner_test.rb +83 -0
- data/test/dev_server_test.rb +39 -0
- data/test/engine_rake_tasks_test.rb +42 -0
- data/test/helper_test.rb +138 -0
- data/test/manifest_test.rb +75 -0
- data/test/mode_test.rb +21 -0
- data/test/mounted_app/Rakefile +6 -0
- data/test/mounted_app/test/dummy/Rakefile +5 -0
- data/test/mounted_app/test/dummy/bin/rails +5 -0
- data/test/mounted_app/test/dummy/bin/rake +5 -0
- data/test/mounted_app/test/dummy/config.ru +7 -0
- data/test/mounted_app/test/dummy/config/application.rb +12 -0
- data/test/mounted_app/test/dummy/config/environment.rb +5 -0
- data/test/mounted_app/test/dummy/config/vite.json +20 -0
- data/test/mounted_app/test/dummy/package.json +7 -0
- data/test/rake_tasks_test.rb +74 -0
- data/test/test_app/Rakefile +5 -0
- data/test/test_app/app/javascript/entrypoints/application.js +10 -0
- data/test/test_app/app/javascript/entrypoints/multi_entry.css +4 -0
- data/test/test_app/app/javascript/entrypoints/multi_entry.js +4 -0
- data/test/test_app/bin/vite +17 -0
- data/test/test_app/config.ru +7 -0
- data/test/test_app/config/application.rb +13 -0
- data/test/test_app/config/environment.rb +6 -0
- data/test/test_app/config/vite.json +20 -0
- data/test/test_app/config/vite_public_root.yml +20 -0
- data/test/test_app/package.json +13 -0
- data/test/test_app/public/vite/manifest.json +36 -0
- data/test/test_app/some.config.js +0 -0
- data/test/test_app/yarn.lock +11 -0
- data/test/test_helper.rb +34 -0
- data/test/vite_runner_test.rb +59 -0
- data/test/webpacker_test.rb +15 -0
- metadata +234 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Public: Allows to resolve configuration sourced from `config/vite.json` and
|
4
|
+
# environment variables, combining them with the default options.
|
5
|
+
class ViteRails::Config
|
6
|
+
delegate :as_json, :inspect, to: :@config
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config.tap { coerce_values(config) }.freeze
|
10
|
+
|
11
|
+
config.each_key do |option|
|
12
|
+
define_singleton_method(option) { @config[option] }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def protocol
|
17
|
+
https ? 'https' : 'http'
|
18
|
+
end
|
19
|
+
|
20
|
+
def host_with_port
|
21
|
+
"#{ host }:#{ port }"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Internal: Path where Vite outputs the manifest file.
|
25
|
+
def manifest_path
|
26
|
+
build_output_dir.join('manifest.json')
|
27
|
+
end
|
28
|
+
|
29
|
+
# Public: The directory where Vite will store the built assets.
|
30
|
+
def build_output_dir
|
31
|
+
public_dir.join(public_output_dir)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# Internal: Coerces all the configuration values, in case they were passed
|
37
|
+
# as environment variables which are always strings.
|
38
|
+
def coerce_values(config)
|
39
|
+
coerce_booleans(config, 'auto_build', 'https')
|
40
|
+
coerce_paths(config, 'assets_dir', 'build_cache_dir', 'config_path', 'public_dir', 'source_code_dir', 'public_output_dir', 'root')
|
41
|
+
config['port'] = config['port'].to_i
|
42
|
+
config['root'] ||= Rails.root
|
43
|
+
end
|
44
|
+
|
45
|
+
# Internal: Coerces configuration options to boolean.
|
46
|
+
def coerce_booleans(config, *names)
|
47
|
+
names.each { |name| config[name] = [true, 'true'].include?(config[name]) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Internal: Converts configuration options to pathname.
|
51
|
+
def coerce_paths(config, *names)
|
52
|
+
names.each { |name| config[name] = Pathname.new(config[name]) unless config[name].nil? }
|
53
|
+
end
|
54
|
+
|
55
|
+
class << self
|
56
|
+
# Public: Returns the project configuration for Vite.
|
57
|
+
def resolve_config
|
58
|
+
new DEFAULT_CONFIG.merge(config_from_file).merge(config_from_env)
|
59
|
+
rescue Errno::ENOENT => error
|
60
|
+
warn "Check that your vite.json configuration file is available in the load path. #{ error.message }"
|
61
|
+
new DEFAULT_CONFIG.merge(config_from_env)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# Internal: Used to load a JSON file from the specified path.
|
67
|
+
def load_json(path)
|
68
|
+
JSON.parse(File.read(File.expand_path(path))).deep_transform_keys(&:underscore)
|
69
|
+
rescue => error
|
70
|
+
(require 'pry-byebug';binding.pry;);
|
71
|
+
end
|
72
|
+
|
73
|
+
# Internal: Retrieves a configuration option from environment variables.
|
74
|
+
def config_option_from_env(name)
|
75
|
+
ENV["#{ ViteRails::ENV_PREFIX }_#{ name.upcase }"]
|
76
|
+
end
|
77
|
+
|
78
|
+
# Internal: Extracts the configuration options provided as env vars.
|
79
|
+
def config_from_env
|
80
|
+
CONFIGURABLE_WITH_ENV.each_with_object({}) do |key, env_vars|
|
81
|
+
if value = config_option_from_env(key)
|
82
|
+
env_vars[key] = value
|
83
|
+
end
|
84
|
+
end.merge(mode: vite_mode)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Internal: The mode Vite should run on.
|
88
|
+
def vite_mode
|
89
|
+
config_option_from_env('mode') || Rails.env.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
# Internal: Loads the configuration options provided in a JSON file.
|
93
|
+
def config_from_file
|
94
|
+
path = config_option_from_env('config_path') || DEFAULT_CONFIG.fetch('config_path')
|
95
|
+
multi_env_config = load_json(path)
|
96
|
+
multi_env_config.fetch('all', {})
|
97
|
+
.merge(multi_env_config.fetch(vite_mode, {}))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Internal: Shared configuration with the Vite plugin for Ruby.
|
102
|
+
DEFAULT_CONFIG = load_json("#{ __dir__ }/../../package/default.vite.json").freeze
|
103
|
+
|
104
|
+
# Internal: Configuration options that can be provided as env vars.
|
105
|
+
CONFIGURABLE_WITH_ENV = (DEFAULT_CONFIG.keys + ['root']).freeze
|
106
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Public: Allows to verify if a Vite development server is already running.
|
4
|
+
class ViteRails::DevServer
|
5
|
+
# Public: Configure dev server connection timeout (in seconds).
|
6
|
+
# Example:
|
7
|
+
# ViteRails.dev_server.connect_timeout = 1
|
8
|
+
cattr_accessor(:connect_timeout) { 0.01 }
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
# Public: Returns true if the Vite development server is reachable.
|
15
|
+
def running?
|
16
|
+
Socket.tcp(host, port, connect_timeout: connect_timeout).close
|
17
|
+
true
|
18
|
+
rescue StandardError
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
delegate :host, :port, to: :@config
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rack/proxy'
|
4
|
+
|
5
|
+
# Public: Allows to relay asset requests to the Vite development server.
|
6
|
+
class ViteRails::DevServerProxy < Rack::Proxy
|
7
|
+
VITE_DEPENDENCY_PREFIX = '/@'
|
8
|
+
|
9
|
+
def initialize(app = nil, options = {})
|
10
|
+
@vite_rails = options.delete(:vite_rails) || ViteRails.instance
|
11
|
+
options[:streaming] = false if Rails.env.test? && !options.key?(:streaming)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
# Rack: Intercept asset requests and send them to the Vite server.
|
16
|
+
def perform_request(env)
|
17
|
+
if vite_should_handle?(env['REQUEST_URI']) && dev_server.running?
|
18
|
+
env['REQUEST_URI'] = env['REQUEST_URI']
|
19
|
+
.sub(vite_asset_url_prefix, '/')
|
20
|
+
.sub('.ts.js', '.ts') # Patch: Rails helpers always append the extension.
|
21
|
+
env['PATH_INFO'], env['QUERY_STRING'] = env['REQUEST_URI'].split('?')
|
22
|
+
|
23
|
+
env['HTTP_HOST'] = env['HTTP_X_FORWARDED_HOST'] = config.host
|
24
|
+
env['HTTP_X_FORWARDED_SERVER'] = config.host_with_port
|
25
|
+
env['HTTP_PORT'] = env['HTTP_X_FORWARDED_PORT'] = config.port.to_s
|
26
|
+
env['HTTP_X_FORWARDED_PROTO'] = env['HTTP_X_FORWARDED_SCHEME'] = config.protocol
|
27
|
+
env['HTTPS'] = env['HTTP_X_FORWARDED_SSL'] = 'off' unless config.https
|
28
|
+
env['SCRIPT_NAME'] = ''
|
29
|
+
super(env)
|
30
|
+
else
|
31
|
+
@app.call(env)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
delegate :config, :dev_server, to: :@vite_rails
|
38
|
+
|
39
|
+
def vite_should_handle?(url)
|
40
|
+
url.start_with?(vite_asset_url_prefix) || url.start_with?(VITE_DEPENDENCY_PREFIX) ||
|
41
|
+
url.include?('?t=') # Direct Hot Reload
|
42
|
+
end
|
43
|
+
|
44
|
+
def vite_asset_url_prefix
|
45
|
+
@vite_asset_url_prefix ||= "/#{ config.public_output_dir }/"
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/railtie'
|
4
|
+
|
5
|
+
class ViteRails::Engine < Rails::Engine
|
6
|
+
initializer 'vite_rails.proxy' do |app|
|
7
|
+
app.middleware.insert_before 0, ViteRails::DevServerProxy, ssl_verify_none: true if ViteRails.run_proxy?
|
8
|
+
end
|
9
|
+
|
10
|
+
initializer 'vite_rails.helper' do
|
11
|
+
ActiveSupport.on_load(:action_controller) do
|
12
|
+
ActionController::Base.helper(ViteRails::Helper)
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveSupport.on_load(:action_view) do
|
16
|
+
include ViteRails::Helper
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
initializer 'vite_rails.logger' do
|
21
|
+
config.after_initialize do
|
22
|
+
ViteRails.logger = if ::Rails.logger.respond_to?(:tagged)
|
23
|
+
::Rails.logger
|
24
|
+
else
|
25
|
+
ActiveSupport::TaggedLogging.new(::Rails.logger)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
initializer 'vite_rails.bootstrap' do
|
31
|
+
if defined?(Rails::Server) || defined?(Rails::Console)
|
32
|
+
ViteRails.bootstrap
|
33
|
+
if defined?(Spring)
|
34
|
+
require 'spring/watcher'
|
35
|
+
Spring.after_fork { ViteRails.bootstrap }
|
36
|
+
Spring.watch(ViteRails.config.config_path)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Public: Allows to render HTML tags for scripts and styles processed by Vite.
|
4
|
+
module ViteRails::Helper
|
5
|
+
# Public: Returns the current Vite Rails instance.
|
6
|
+
def current_vite_instance
|
7
|
+
ViteRails.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
# Public: Computes the relative path for the specified given Vite asset.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# <%= vite_asset_path 'calendar.css' %> # => "/vite/assets/calendar-1016838bab065ae1e122.css"
|
14
|
+
def vite_asset_path(name, **options)
|
15
|
+
current_vite_instance.manifest.lookup!(name, **options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Public: Renders a <script> tag for the specified Vite entrypoints.
|
19
|
+
def vite_javascript_tag(*names, type: 'module', **options)
|
20
|
+
javascript_include_tag(*sources_from_vite_manifest_entrypoints(names, type: :javascript), type: type, **options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Renders a <script> tag for the specified Vite entrypoints.
|
24
|
+
#
|
25
|
+
# NOTE: Because TypeScript is not a valid target in browsers, we only specify
|
26
|
+
# the ts file when running the Vite development server.
|
27
|
+
def vite_typescript_tag(*names, type: 'module', **options)
|
28
|
+
javascript_include_tag(*sources_from_vite_manifest_entrypoints(names, type: :typescript), type: type, **options)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Renders a <link> tag for the specified Vite entrypoints.
|
32
|
+
def vite_stylesheet_tag(*names, **options)
|
33
|
+
stylesheet_link_tag(*sources_from_vite_manifest_entrypoints(names, type: :stylesheet), **options)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def sources_from_vite_manifest_entrypoints(names, type:)
|
39
|
+
names.flat_map { |name| vite_asset_path(name, type: type) }.uniq
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Public: Registry for accessing resources managed by Vite, using a generated
|
4
|
+
# manifest file which maps entrypoint names to file paths.
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
# lookup_entrypoint('calendar', type: :javascript)
|
8
|
+
# => "/vite/assets/calendar-1016838bab065ae1e314.js"
|
9
|
+
#
|
10
|
+
# NOTE: Using "autoBuild": true` in `config/vite.json` file will trigger a build
|
11
|
+
# on demand as needed, before performing any lookup.
|
12
|
+
class ViteRails::Manifest
|
13
|
+
class MissingEntryError < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(vite_rails)
|
17
|
+
@vite_rails = vite_rails
|
18
|
+
end
|
19
|
+
|
20
|
+
# Public: Strict version of lookup.
|
21
|
+
#
|
22
|
+
# Returns a relative path for the asset, or raises an error if not found.
|
23
|
+
def lookup!(*args, **options)
|
24
|
+
lookup(*args, **options) || missing_entry_error(*args, **options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Public: Computes the path for a given Vite asset using manifest.json.
|
28
|
+
#
|
29
|
+
# Returns a relative path, or nil if the asset is not found.
|
30
|
+
#
|
31
|
+
# Example:
|
32
|
+
# ViteRails.manifest.lookup('calendar.js') # => "/vite/assets/calendar-1016838bab065ae1e122.js"
|
33
|
+
def lookup(name, type:)
|
34
|
+
build if should_build?
|
35
|
+
|
36
|
+
find_manifest_entry(with_file_extension(name, type))
|
37
|
+
end
|
38
|
+
|
39
|
+
# Public: Refreshes the cached mappings by reading the updated manifest.
|
40
|
+
def refresh
|
41
|
+
@manifest = load_manifest
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
delegate :config, :builder, :dev_server, to: :@vite_rails
|
47
|
+
|
48
|
+
# Public: Returns true if the Vite development server is running.
|
49
|
+
def dev_server_running?
|
50
|
+
ViteRails.run_proxy? && dev_server.running?
|
51
|
+
end
|
52
|
+
|
53
|
+
# NOTE: Auto compilation is convenient when running tests, when the developer
|
54
|
+
# won't focus on the frontend, or when running the Vite server is not desired.
|
55
|
+
def should_build?
|
56
|
+
config.auto_build && !dev_server_running?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Finds the specified entry in the manifest.
|
60
|
+
def find_manifest_entry(name)
|
61
|
+
if dev_server_running?
|
62
|
+
"/#{ config.public_output_dir.join(name.to_s) }"
|
63
|
+
elsif file = manifest.dig(name.to_s, 'file')
|
64
|
+
"/#{ config.public_output_dir.join(file) }"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Internal: Performs a Vite build.
|
69
|
+
def build
|
70
|
+
ViteRails.logger.tagged('Vite') { builder.build }
|
71
|
+
end
|
72
|
+
|
73
|
+
# Internal: The parsed data from manifest.json.
|
74
|
+
#
|
75
|
+
# NOTE: When using build-on-demand in development and testing, the manifest
|
76
|
+
# is reloaded automatically before each lookup, to ensure it's always fresh.
|
77
|
+
def manifest
|
78
|
+
return refresh if config.auto_build
|
79
|
+
|
80
|
+
@manifest ||= load_manifest
|
81
|
+
end
|
82
|
+
|
83
|
+
# Internal: Returns a Hash with the entries in the manifest.json.
|
84
|
+
def load_manifest
|
85
|
+
if config.manifest_path.exist?
|
86
|
+
JSON.parse(config.manifest_path.read)
|
87
|
+
else
|
88
|
+
{}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Internal: Adds a file extension to the file name, unless it already has one.
|
93
|
+
def with_file_extension(name, entry_type)
|
94
|
+
return name unless File.extname(name.to_s).empty?
|
95
|
+
|
96
|
+
"#{ name }.#{ extension_for_type(entry_type) }"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Internal: Allows to receive :javascript and :stylesheet as :type in helpers.
|
100
|
+
def extension_for_type(entry_type)
|
101
|
+
case entry_type
|
102
|
+
when :javascript then 'js'
|
103
|
+
when :stylesheet then 'css'
|
104
|
+
when :typescript then dev_server_running? ? 'ts' : 'js'
|
105
|
+
else entry_type.to_s
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Internal: Raises a detailed message when an entry is missing in the manifest.
|
110
|
+
def missing_entry_error(name, type: nil, **_options)
|
111
|
+
file_name = with_file_extension(name, type)
|
112
|
+
raise ViteRails::Manifest::MissingEntryError, <<~MSG
|
113
|
+
Vite Rails can't find #{ file_name } in #{ config.manifest_path }.
|
114
|
+
|
115
|
+
Possible causes:
|
116
|
+
#{ missing_entry_causes.map { |cause| "\t- #{ cause }" }.join("\n") }
|
117
|
+
|
118
|
+
Your manifest contains:
|
119
|
+
#{ JSON.pretty_generate(@manifest) }
|
120
|
+
MSG
|
121
|
+
end
|
122
|
+
|
123
|
+
def missing_entry_causes
|
124
|
+
local = config.auto_build
|
125
|
+
[
|
126
|
+
(dev_server_running? && 'Vite has not yet re-built your latest changes.'),
|
127
|
+
(local && !dev_server_running? && "\"autoBuild\": false in your #{ config.mode } configuration."),
|
128
|
+
'You have misconfigured config/vite.json file.',
|
129
|
+
(!local && 'Assets have not been precompiled'),
|
130
|
+
].select(&:itself)
|
131
|
+
rescue StandardError
|
132
|
+
[]
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Public: Executes Vite commands, providing conveniences for debugging.
|
4
|
+
class ViteRails::Runner
|
5
|
+
def initialize(argv)
|
6
|
+
detect_unsupported_switches!(argv)
|
7
|
+
@argv = argv
|
8
|
+
end
|
9
|
+
|
10
|
+
# Public: Executes Vite with the specified arguments.
|
11
|
+
def run
|
12
|
+
execute_command(@argv.clone)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
UNSUPPORTED_SWITCHES = %w[--host --port --https --root -r --config -c]
|
18
|
+
private_constant :UNSUPPORTED_SWITCHES
|
19
|
+
|
20
|
+
# Internal: Allows to prevent configuration mistakes by ensuring the Rails app
|
21
|
+
# and vite-plugin-ruby are using the same configuration for the dev server.
|
22
|
+
def detect_unsupported_switches!(args)
|
23
|
+
return unless (unsupported = UNSUPPORTED_SWITCHES & args).any?
|
24
|
+
|
25
|
+
$stdout.puts "Please set the following switches in your vite.json instead: #{ unsupported }."
|
26
|
+
exit!
|
27
|
+
end
|
28
|
+
|
29
|
+
# Internal: Executes the command with the specified arguments.
|
30
|
+
def execute_command(args)
|
31
|
+
cmd = vite_executable
|
32
|
+
cmd.prepend('node', '--inspect-brk') if args.include?('--debug')
|
33
|
+
cmd.prepend('node', '--trace-deprecation') if args.delete('--trace-deprecation')
|
34
|
+
args.append('--mode', ENV['RAILS_ENV']) unless args.include?('--mode') || args.include?('-m')
|
35
|
+
cmd += args
|
36
|
+
puts cmd.join(' ')
|
37
|
+
Dir.chdir(File.expand_path('.', Dir.pwd)) { Kernel.exec(ViteRails.env, *cmd) }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Internal: Resolves to an executable for Vite.
|
41
|
+
def vite_executable
|
42
|
+
executable_exists?(path = vite_bin_path) ? [path] : %w[yarn vite]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Internal: Only so that we can easily cover both paths in tests
|
46
|
+
def executable_exists?(path)
|
47
|
+
File.exist?(path)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Internal: Returns a path where a Vite executable should be found.
|
51
|
+
def vite_bin_path
|
52
|
+
ENV["#{ ViteRails::ENV_PREFIX }_VITE_BIN_PATH"] || `yarn bin vite`.chomp
|
53
|
+
rescue StandardError
|
54
|
+
"#{ `npm bin`.chomp }/vite"
|
55
|
+
end
|
56
|
+
end
|