vite_rails 1.0.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 +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
|