vite_ruby 3.11.1 → 4.0.0.alpha1
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 +4 -4
- data/CHANGELOG.md +2 -520
- data/README.md +2 -2
- data/default.vite.json +2 -8
- data/exe/vite +3 -5
- data/lib/tasks/vite.rake +19 -56
- data/lib/vite_ruby/build.rb +17 -47
- data/lib/vite_ruby/builder.rb +35 -66
- data/lib/vite_ruby/cli/build.rb +4 -6
- data/lib/vite_ruby/cli/clobber.rb +4 -4
- data/lib/vite_ruby/cli/dev.rb +3 -3
- data/lib/vite_ruby/cli/file_utils.rb +9 -16
- data/lib/vite_ruby/cli/install.rb +42 -47
- data/lib/vite_ruby/cli/upgrade.rb +4 -4
- data/lib/vite_ruby/cli/upgrade_packages.rb +4 -3
- data/lib/vite_ruby/cli/version.rb +1 -1
- data/lib/vite_ruby/cli/vite.rb +9 -24
- data/lib/vite_ruby/cli.rb +8 -21
- data/lib/vite_ruby/commands.rb +75 -31
- data/lib/vite_ruby/compatibility_check.rb +8 -8
- data/lib/vite_ruby/config.rb +37 -76
- data/lib/vite_ruby/dev_server_proxy.rb +24 -31
- data/lib/vite_ruby/error.rb +1 -1
- data/lib/vite_ruby/io.rb +4 -4
- data/lib/vite_ruby/manifest.rb +32 -63
- data/lib/vite_ruby/missing_entrypoint_error.rb +14 -21
- data/lib/vite_ruby/missing_executable_error.rb +1 -1
- data/lib/vite_ruby/runner.rb +12 -20
- data/lib/vite_ruby/version.rb +3 -3
- data/lib/vite_ruby.rb +38 -77
- metadata +21 -48
- data/lib/vite_ruby/cli/ssr.rb +0 -27
data/lib/tasks/vite.rake
CHANGED
|
@@ -2,49 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
$stdout.sync = true
|
|
4
4
|
|
|
5
|
-
require
|
|
5
|
+
require 'rake'
|
|
6
6
|
|
|
7
7
|
namespace :vite do
|
|
8
8
|
task :binstubs do
|
|
9
9
|
ViteRuby.commands.install_binstubs
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
desc
|
|
13
|
-
task build: :
|
|
12
|
+
desc 'Compile JavaScript packs using vite for production with digests'
|
|
13
|
+
task build: :'vite:verify_install' do
|
|
14
14
|
ViteRuby.commands.build_from_task
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
desc
|
|
18
|
-
task
|
|
19
|
-
ViteRuby.commands.
|
|
17
|
+
desc 'Remove old compiled vites'
|
|
18
|
+
task :clean, [:keep, :age] => :'vite:verify_install' do |_, args|
|
|
19
|
+
ViteRuby.commands.clean_from_task(args)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
desc
|
|
23
|
-
task
|
|
24
|
-
ViteRuby.commands.build_from_task
|
|
25
|
-
ViteRuby.commands.build_from_task("--ssr") if ViteRuby.config.ssr_build_enabled
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
desc "Remove the build output directory for ViteRuby"
|
|
29
|
-
task clobber: :"vite:verify_install" do
|
|
22
|
+
desc 'Remove the vite build output directory'
|
|
23
|
+
task clobber: :'vite:verify_install' do
|
|
30
24
|
ViteRuby.commands.clobber
|
|
31
25
|
end
|
|
32
26
|
|
|
33
|
-
desc
|
|
27
|
+
desc 'Verifies if ViteRuby is properly installed in this application'
|
|
34
28
|
task :verify_install do
|
|
35
29
|
ViteRuby.commands.verify_install
|
|
36
30
|
end
|
|
37
31
|
|
|
38
|
-
desc
|
|
32
|
+
desc 'Ensures build dependencies like Vite are installed when compiling assets'
|
|
39
33
|
task :install_dependencies do
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
install_cmd = case (pkg = ViteRuby.config.package_manager)
|
|
43
|
-
when "npm" then "npm ci"
|
|
44
|
-
else "#{pkg} install --frozen-lockfile"
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
system(install_env_args, install_cmd)
|
|
34
|
+
system({ 'NODE_ENV' => 'development' }, 'npx --yes ci')
|
|
48
35
|
end
|
|
49
36
|
|
|
50
37
|
desc "Provide information on ViteRuby's environment"
|
|
@@ -53,43 +40,19 @@ namespace :vite do
|
|
|
53
40
|
end
|
|
54
41
|
end
|
|
55
42
|
|
|
56
|
-
unless ENV[
|
|
57
|
-
if Rake::Task.task_defined?(
|
|
58
|
-
Rake::Task[
|
|
43
|
+
unless ENV['VITE_RUBY_SKIP_ASSETS_PRECOMPILE_EXTENSION'] == 'true'
|
|
44
|
+
if Rake::Task.task_defined?('assets:precompile')
|
|
45
|
+
Rake::Task['assets:precompile'].enhance do |task|
|
|
59
46
|
prefix = task.name.split(/#|assets:precompile/).first
|
|
60
|
-
|
|
61
|
-
Rake::Task["#{prefix}vite:install_dependencies"].invoke
|
|
62
|
-
end
|
|
63
|
-
Rake::Task["#{prefix}vite:build_all"].invoke
|
|
47
|
+
Rake::Task["#{ prefix }vite:build"].invoke
|
|
64
48
|
end
|
|
65
49
|
else
|
|
66
|
-
|
|
67
|
-
if ENV["VITE_RUBY_SKIP_ASSETS_PRECOMPILE_INSTALL"] == "true"
|
|
68
|
-
Rake::Task.define_task("assets:precompile" => "vite:build_all")
|
|
69
|
-
else
|
|
70
|
-
Rake::Task.define_task("assets:precompile" => ["vite:install_dependencies", "vite:build_all"])
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
if Rake::Task.task_defined?("assets:clobber")
|
|
75
|
-
Rake::Task["assets:clobber"].enhance do
|
|
76
|
-
Rake::Task["vite:clobber"].invoke
|
|
77
|
-
end
|
|
78
|
-
else
|
|
79
|
-
desc "Remove compiled assets"
|
|
80
|
-
Rake::Task.define_task("assets:clobber" => "vite:clobber")
|
|
50
|
+
Rake::Task.define_task('assets:precompile' => ['vite:install_dependencies', 'vite:build'])
|
|
81
51
|
end
|
|
82
52
|
end
|
|
83
53
|
|
|
84
54
|
# Any prerequisite task that installs packages should also install build dependencies.
|
|
85
|
-
if ARGV.include?(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
else
|
|
89
|
-
ENV["NPM_CONFIG_INCLUDE"] = "dev"
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
if ViteRuby.commands.legacy_yarn_version?
|
|
93
|
-
ENV["YARN_PRODUCTION"] = "false"
|
|
94
|
-
end
|
|
55
|
+
if ARGV.include?('assets:precompile')
|
|
56
|
+
ENV['NPM_CONFIG_PRODUCTION'] = 'false'
|
|
57
|
+
ENV['YARN_PRODUCTION'] = 'false'
|
|
95
58
|
end
|
data/lib/vite_ruby/build.rb
CHANGED
|
@@ -1,35 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require "time"
|
|
3
|
+
require 'time'
|
|
5
4
|
|
|
6
5
|
# Internal: Value object with information about the last build.
|
|
7
|
-
ViteRuby::Build = Struct.new(:success, :timestamp, :vite_ruby, :digest, :current_digest
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
# Internal: Reads metadata recorded on the last build, if it exists.
|
|
21
|
-
def parse_metadata(pathname)
|
|
22
|
-
return default_metadata unless pathname.exist?
|
|
23
|
-
|
|
24
|
-
JSON.parse(pathname.read.to_s).transform_keys(&:to_sym).slice(*members)
|
|
25
|
-
rescue JSON::JSONError, Errno::ENOENT, Errno::ENOTDIR
|
|
26
|
-
default_metadata
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Internal: To make it evident that there's no last build in error messages.
|
|
30
|
-
def default_metadata
|
|
31
|
-
{timestamp: "never", digest: "none"}
|
|
32
|
-
end
|
|
6
|
+
ViteRuby::Build = Struct.new(:success, :timestamp, :vite_ruby, :digest, :current_digest) do
|
|
7
|
+
# Internal: Combines information from a previous build with the current digest.
|
|
8
|
+
def self.from_previous(attrs, current_digest)
|
|
9
|
+
new(
|
|
10
|
+
attrs['success'],
|
|
11
|
+
attrs['timestamp'] || 'never',
|
|
12
|
+
attrs['vite_ruby'] || 'unknown',
|
|
13
|
+
attrs['digest'] || 'none',
|
|
14
|
+
current_digest,
|
|
15
|
+
)
|
|
33
16
|
end
|
|
34
17
|
|
|
35
18
|
# Internal: A build is considered stale when watched files have changed since
|
|
@@ -53,30 +36,17 @@ ViteRuby::Build = Struct.new(:success, :timestamp, :vite_ruby, :digest, :current
|
|
|
53
36
|
end
|
|
54
37
|
|
|
55
38
|
# Internal: Returns a new build with the specified result.
|
|
56
|
-
def with_result(
|
|
39
|
+
def with_result(success)
|
|
57
40
|
self.class.new(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
current_digest: current_digest,
|
|
63
|
-
last_build_path: last_build_path,
|
|
41
|
+
success,
|
|
42
|
+
Time.now.strftime('%F %T'),
|
|
43
|
+
ViteRuby::VERSION,
|
|
44
|
+
current_digest,
|
|
64
45
|
)
|
|
65
46
|
end
|
|
66
47
|
|
|
67
|
-
# Internal: Writes the result of the new build to a local file.
|
|
68
|
-
def write_to_cache
|
|
69
|
-
last_build_path.write to_json
|
|
70
|
-
end
|
|
71
|
-
|
|
72
48
|
# Internal: Returns a JSON string with the metadata of the build.
|
|
73
49
|
def to_json(*_args)
|
|
74
|
-
JSON.pretty_generate(
|
|
75
|
-
success: success,
|
|
76
|
-
errors: errors,
|
|
77
|
-
timestamp: timestamp,
|
|
78
|
-
vite_ruby: vite_ruby,
|
|
79
|
-
digest: digest,
|
|
80
|
-
)
|
|
50
|
+
JSON.pretty_generate(to_h)
|
|
81
51
|
end
|
|
82
52
|
end
|
data/lib/vite_ruby/builder.rb
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'digest/sha1'
|
|
4
5
|
|
|
5
6
|
# Public: Keeps track of watched files and triggers builds as needed.
|
|
6
7
|
class ViteRuby::Builder
|
|
7
8
|
def initialize(vite_ruby)
|
|
8
9
|
@vite_ruby = vite_ruby
|
|
9
|
-
@file_digests = {}
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
# Public: Checks if the watched files have changed since the last compilation,
|
|
13
13
|
# and triggers a Vite build if any files have changed.
|
|
14
14
|
def build(*args)
|
|
15
|
-
last_build = last_build_metadata
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
stdout, stderr, status = build_with_vite(*args)
|
|
19
|
-
log_build_result(stdout, stderr, status)
|
|
20
|
-
record_build_metadata(last_build, errors: stderr, success: status.success?)
|
|
21
|
-
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) }
|
|
22
18
|
elsif last_build.success
|
|
23
|
-
logger.debug "Skipping vite build. Watched files have not changed since the last build at #{last_build.timestamp}"
|
|
19
|
+
logger.debug "Skipping vite build. Watched files have not changed since the last build at #{ last_build.timestamp }"
|
|
24
20
|
true
|
|
25
21
|
else
|
|
26
|
-
logger.error "Skipping vite build. Watched files have not changed since the build failed at #{last_build.timestamp} ❌"
|
|
22
|
+
logger.error "Skipping vite build. Watched files have not changed since the build failed at #{ last_build.timestamp } ❌"
|
|
27
23
|
false
|
|
28
24
|
end
|
|
29
25
|
end
|
|
30
26
|
|
|
31
27
|
# Internal: Reads the result of the last compilation from disk.
|
|
32
|
-
def last_build_metadata
|
|
33
|
-
ViteRuby::Build.from_previous(
|
|
28
|
+
def last_build_metadata
|
|
29
|
+
ViteRuby::Build.from_previous(last_build_attrs, watched_files_digest)
|
|
34
30
|
end
|
|
35
31
|
|
|
36
32
|
private
|
|
@@ -39,70 +35,44 @@ private
|
|
|
39
35
|
|
|
40
36
|
def_delegators :@vite_ruby, :config, :logger, :run
|
|
41
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
|
+
|
|
42
45
|
# Internal: Writes a digest of the watched files to disk for future checks.
|
|
43
|
-
def record_build_metadata(
|
|
46
|
+
def record_build_metadata(success, build)
|
|
44
47
|
config.build_cache_dir.mkpath
|
|
45
|
-
build.with_result(
|
|
48
|
+
last_build_path.write build.with_result(success).to_json
|
|
46
49
|
end
|
|
47
50
|
|
|
48
51
|
# Internal: The file path where metadata of the last build is stored.
|
|
49
|
-
def last_build_path
|
|
50
|
-
config.build_cache_dir.join("last
|
|
52
|
+
def last_build_path
|
|
53
|
+
config.build_cache_dir.join("last-build-#{ config.mode }.json")
|
|
51
54
|
end
|
|
52
55
|
|
|
53
56
|
# Internal: Returns a digest of all the watched files, allowing to detect
|
|
54
57
|
# changes, and skip Vite builds if no files have changed.
|
|
55
58
|
def watched_files_digest
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@file_digests = {}
|
|
61
|
-
file_ids = Dir[*config.watched_paths].sort.filter_map { |file|
|
|
62
|
-
file_digest(file, previous_digests)
|
|
63
|
-
}
|
|
64
|
-
@last_digest_at = Time.now
|
|
65
|
-
@last_digest = Digest::SHA1.hexdigest(file_ids.join("/"))
|
|
59
|
+
Dir.chdir File.expand_path(config.root) do
|
|
60
|
+
files = Dir[*config.watched_paths].reject { |f| File.directory?(f) }
|
|
61
|
+
file_ids = files.sort.map { |f| "#{ File.basename(f) }/#{ Digest::SHA1.file(f).hexdigest }" }
|
|
62
|
+
Digest::SHA1.hexdigest(file_ids.join('/'))
|
|
66
63
|
end
|
|
67
64
|
end
|
|
68
65
|
|
|
69
|
-
# Internal: Returns the id of a watched file, or nil if it's a directory.
|
|
70
|
-
#
|
|
71
|
-
# NOTE: Reading and hashing every watched file dominates the cost of the
|
|
72
|
-
# check, and the answer is almost always the same one as the last time, so the
|
|
73
|
-
# contents are read again only once the file has been touched. The digest
|
|
74
|
-
# stays content-based: a checkout that changes mtimes but not contents still
|
|
75
|
-
# counts as unchanged, and no Vite build is triggered.
|
|
76
|
-
def file_digest(file, previous_digests)
|
|
77
|
-
stat = File.stat(file)
|
|
78
|
-
return if stat.directory?
|
|
79
|
-
|
|
80
|
-
signature = [stat.mtime, stat.size]
|
|
81
|
-
previous_signature, previous_id = previous_digests[file]
|
|
82
|
-
id = if previous_signature == signature && !recently_modified?(stat)
|
|
83
|
-
previous_id
|
|
84
|
-
else
|
|
85
|
-
"#{File.basename(file)}/#{Digest::SHA1.file(file).hexdigest}"
|
|
86
|
-
end
|
|
87
|
-
@file_digests[file] = [signature, id]
|
|
88
|
-
id
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
# Internal: Whether the file was modified too recently to trust its mtime.
|
|
92
|
-
#
|
|
93
|
-
# NOTE: A file edited twice within the resolution of the file system clock,
|
|
94
|
-
# without changing its size, would keep the same signature. Rehashing the
|
|
95
|
-
# files touched in the last second rules that out, the same way Git resolves
|
|
96
|
-
# a racily clean entry in the index.
|
|
97
|
-
def recently_modified?(stat)
|
|
98
|
-
Time.now - stat.mtime < 1
|
|
99
|
-
end
|
|
100
|
-
|
|
101
66
|
# Public: Initiates a Vite build command to generate assets.
|
|
67
|
+
#
|
|
68
|
+
# Returns true if the build is successful, or false if it failed.
|
|
102
69
|
def build_with_vite(*args)
|
|
103
|
-
logger.info
|
|
70
|
+
logger.info 'Building with Vite ⚡️'
|
|
71
|
+
|
|
72
|
+
stdout, stderr, status = run(['build', *args])
|
|
73
|
+
log_build_result(stdout, stderr.to_s, status)
|
|
104
74
|
|
|
105
|
-
|
|
75
|
+
status.success?
|
|
106
76
|
end
|
|
107
77
|
|
|
108
78
|
# Internal: Outputs the build results.
|
|
@@ -110,13 +80,12 @@ private
|
|
|
110
80
|
# NOTE: By default it also outputs the manifest entries.
|
|
111
81
|
def log_build_result(_stdout, stderr, status)
|
|
112
82
|
if status.success?
|
|
113
|
-
logger.info "Build with Vite complete: #{config.build_output_dir}"
|
|
114
|
-
logger.error stderr unless stderr.empty?
|
|
83
|
+
logger.info "Build with Vite complete: #{ config.build_output_dir }"
|
|
84
|
+
logger.error stderr.to_s unless stderr.empty?
|
|
115
85
|
else
|
|
116
86
|
logger.error stderr
|
|
117
|
-
logger.error
|
|
118
|
-
logger.error
|
|
119
|
-
logger.error "❌ Check that vite and vite-plugin-ruby are in devDependencies and have been installed. " if stderr.include?("ERR! canceled")
|
|
87
|
+
logger.error 'Build with Vite failed! ❌'
|
|
88
|
+
logger.error '❌ Check that vite and vite-plugin-ruby are in devDependencies and have been installed. ' if stderr.include?('ERR! canceled')
|
|
120
89
|
end
|
|
121
90
|
end
|
|
122
91
|
end
|
data/lib/vite_ruby/cli/build.rb
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ViteRuby::CLI::Build < ViteRuby::CLI::Vite
|
|
4
|
-
DEFAULT_ENV = CURRENT_ENV ||
|
|
4
|
+
DEFAULT_ENV = CURRENT_ENV || 'production'
|
|
5
5
|
|
|
6
|
-
desc
|
|
6
|
+
desc 'Bundle all entrypoints using Vite.'
|
|
7
7
|
shared_options
|
|
8
|
-
option(:
|
|
9
|
-
option(:
|
|
10
|
-
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)
|
|
8
|
+
option(:force, desc: 'Force the build even if assets have not changed', type: :boolean)
|
|
9
|
+
option(:watch, desc: 'Start the Rollup watcher and rebuild on files changes', type: :boolean)
|
|
12
10
|
|
|
13
11
|
def call(**options)
|
|
14
12
|
super { |args| ViteRuby.commands.build_from_task(*args) }
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ViteRuby::CLI::Clobber < Dry::CLI::Command
|
|
4
|
-
desc
|
|
4
|
+
desc 'Clear the Vite cache, temp files, and builds'
|
|
5
5
|
|
|
6
|
-
current_env = ENV[
|
|
6
|
+
current_env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
|
|
7
7
|
|
|
8
|
-
option(:mode, default: current_env, values: %w[development production test], aliases: [
|
|
8
|
+
option(:mode, default: current_env, values: %w[development production test], aliases: ['m'], desc: 'The mode to use')
|
|
9
9
|
|
|
10
10
|
def call(mode:, **)
|
|
11
|
-
ViteRuby.env[
|
|
11
|
+
ViteRuby.env['VITE_RUBY_MODE'] = mode
|
|
12
12
|
ViteRuby.commands.clobber
|
|
13
13
|
end
|
|
14
14
|
end
|
data/lib/vite_ruby/cli/dev.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ViteRuby::CLI::Dev < ViteRuby::CLI::Vite
|
|
4
|
-
DEFAULT_ENV = CURRENT_ENV ||
|
|
4
|
+
DEFAULT_ENV = CURRENT_ENV || 'development'
|
|
5
5
|
|
|
6
|
-
desc
|
|
6
|
+
desc 'Start the Vite development server.'
|
|
7
7
|
shared_options
|
|
8
|
-
option(:force, desc:
|
|
8
|
+
option(:force, desc: 'Force Vite to re-bundle dependencies', type: :boolean)
|
|
9
9
|
|
|
10
10
|
def call(**options)
|
|
11
11
|
super { |args| ViteRuby.run(args, exec: true) }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'pathname'
|
|
4
|
+
require 'fileutils'
|
|
5
5
|
|
|
6
6
|
# NOTE: Extracted from dry-cli version 0.6.0, which later removed this file as
|
|
7
7
|
# it was refactored and extracted into the more complete (and complex) dry-files.
|
|
@@ -32,18 +32,11 @@ module ViteRuby::CLI::FileUtils
|
|
|
32
32
|
# @since 1.2.11
|
|
33
33
|
# @api private
|
|
34
34
|
def append(path, contents)
|
|
35
|
-
append_unless_present(path, contents, pattern: contents)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Adds a new line at the bottom of the file, unless any line matches the pattern.
|
|
39
|
-
#
|
|
40
|
-
# @api private
|
|
41
|
-
def append_unless_present(path, contents, pattern:)
|
|
42
35
|
content = read_lines(path)
|
|
43
|
-
return if content.
|
|
36
|
+
return if content.join.include?(contents)
|
|
44
37
|
|
|
45
38
|
content << "\n" unless content.last&.end_with?("\n")
|
|
46
|
-
content << "#{contents}\n"
|
|
39
|
+
content << "#{ contents }\n"
|
|
47
40
|
|
|
48
41
|
write(path, content)
|
|
49
42
|
end
|
|
@@ -54,7 +47,7 @@ module ViteRuby::CLI::FileUtils
|
|
|
54
47
|
# @api private
|
|
55
48
|
def replace_first_line(path, target, replacement)
|
|
56
49
|
content = read_lines(path)
|
|
57
|
-
content[index(content, path, target)] = "#{replacement}\n"
|
|
50
|
+
content[index(content, path, target)] = "#{ replacement }\n"
|
|
58
51
|
|
|
59
52
|
write(path, content)
|
|
60
53
|
end
|
|
@@ -102,14 +95,14 @@ module ViteRuby::CLI::FileUtils
|
|
|
102
95
|
# @api private
|
|
103
96
|
def index(content, path, target)
|
|
104
97
|
content.index { |line| line.include?(target) } ||
|
|
105
|
-
raise(ArgumentError, "Cannot find `#{target}' inside `#{path}'.")
|
|
98
|
+
raise(ArgumentError, "Cannot find `#{ target }' inside `#{ path }'.")
|
|
106
99
|
end
|
|
107
100
|
|
|
108
101
|
# @since 1.2.11
|
|
109
102
|
# @api private
|
|
110
103
|
def rindex(content, path, target)
|
|
111
104
|
content.rindex { |line| line.include?(target) } ||
|
|
112
|
-
raise(ArgumentError, "Cannot find `#{target}' inside `#{path}'.")
|
|
105
|
+
raise(ArgumentError, "Cannot find `#{ target }' inside `#{ path }'.")
|
|
113
106
|
end
|
|
114
107
|
|
|
115
108
|
# @since 1.2.11
|
|
@@ -120,7 +113,7 @@ module ViteRuby::CLI::FileUtils
|
|
|
120
113
|
|
|
121
114
|
i = finder.call(content, path, target)
|
|
122
115
|
|
|
123
|
-
content.insert(i, "#{contents}\n")
|
|
116
|
+
content.insert(i, "#{ contents }\n")
|
|
124
117
|
write(path, content)
|
|
125
118
|
end
|
|
126
119
|
|
|
@@ -132,7 +125,7 @@ module ViteRuby::CLI::FileUtils
|
|
|
132
125
|
|
|
133
126
|
i = finder.call(content, path, target)
|
|
134
127
|
|
|
135
|
-
content.insert(i + 1, "#{contents}\n")
|
|
128
|
+
content.insert(i + 1, "#{ contents }\n")
|
|
136
129
|
write(path, content)
|
|
137
130
|
end
|
|
138
131
|
end
|
|
@@ -1,31 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require "json"
|
|
3
|
+
require 'stringio'
|
|
5
4
|
|
|
6
5
|
class ViteRuby::CLI::Install < Dry::CLI::Command
|
|
7
|
-
desc
|
|
8
|
-
|
|
9
|
-
option(:package_manager, values: %w[npm pnpm yarn bun], aliases: %w[package-manager with], desc: "The package manager to use when installing JS dependencies.")
|
|
10
|
-
|
|
11
|
-
def call(package_manager: nil, **)
|
|
12
|
-
ENV["VITE_RUBY_PACKAGE_MANAGER"] ||= package_manager if package_manager
|
|
6
|
+
desc 'Performs the initial configuration setup to get started with Vite Ruby.'
|
|
13
7
|
|
|
8
|
+
def call(**)
|
|
14
9
|
$stdout.sync = true
|
|
15
10
|
|
|
16
|
-
say
|
|
11
|
+
say 'Creating binstub'
|
|
17
12
|
ViteRuby.commands.install_binstubs
|
|
18
13
|
|
|
19
|
-
say
|
|
14
|
+
say 'Creating configuration files'
|
|
20
15
|
create_configuration_files
|
|
21
16
|
|
|
22
|
-
say
|
|
17
|
+
say 'Installing sample files'
|
|
23
18
|
install_sample_files
|
|
24
19
|
|
|
25
|
-
say
|
|
20
|
+
say 'Installing js dependencies'
|
|
26
21
|
install_js_dependencies
|
|
27
22
|
|
|
28
|
-
say
|
|
23
|
+
say 'Adding files to .gitignore'
|
|
29
24
|
install_gitignore
|
|
30
25
|
|
|
31
26
|
say "\nVite ⚡️ Ruby successfully installed! 🎉"
|
|
@@ -36,38 +31,38 @@ protected
|
|
|
36
31
|
# Internal: The JS packages that should be added to the app.
|
|
37
32
|
def js_dependencies
|
|
38
33
|
[
|
|
39
|
-
"vite@#{ViteRuby::DEFAULT_VITE_VERSION}",
|
|
40
|
-
"vite-plugin-ruby@#{ViteRuby::DEFAULT_PLUGIN_VERSION}",
|
|
34
|
+
"vite@#{ ViteRuby::DEFAULT_VITE_VERSION }",
|
|
35
|
+
"vite-plugin-ruby@#{ ViteRuby::DEFAULT_PLUGIN_VERSION }",
|
|
41
36
|
]
|
|
42
37
|
end
|
|
43
38
|
|
|
44
39
|
# Internal: Setup for a plain Rack application.
|
|
45
40
|
def setup_app_files
|
|
46
|
-
copy_template
|
|
41
|
+
copy_template 'config/vite.json', to: config.config_path
|
|
47
42
|
|
|
48
|
-
if (rackup_file = root.join(
|
|
49
|
-
inject_line_after_last rackup_file,
|
|
43
|
+
if (rackup_file = root.join('config.ru')).exist?
|
|
44
|
+
inject_line_after_last rackup_file, 'require', 'use(ViteRuby::DevServerProxy, ssl_verify_none: true) if ViteRuby.run_proxy?'
|
|
50
45
|
end
|
|
51
46
|
end
|
|
52
47
|
|
|
53
48
|
# Internal: Create a sample JS file and attempt to inject it in an HTML template.
|
|
54
49
|
def install_sample_files
|
|
55
|
-
copy_template
|
|
50
|
+
copy_template 'entrypoints/application.js', to: config.resolved_entrypoints_dir.join('application.js')
|
|
56
51
|
end
|
|
57
52
|
|
|
58
53
|
private
|
|
59
54
|
|
|
60
55
|
extend Forwardable
|
|
61
56
|
|
|
62
|
-
def_delegators
|
|
57
|
+
def_delegators 'ViteRuby', :config
|
|
63
58
|
|
|
64
|
-
%i[append
|
|
65
|
-
define_method(util) { |*args
|
|
66
|
-
ViteRuby::CLI::FileUtils.send(util, *args
|
|
59
|
+
%i[append cp inject_line_after inject_line_after_last inject_line_before replace_first_line write].each do |util|
|
|
60
|
+
define_method(util) { |*args|
|
|
61
|
+
ViteRuby::CLI::FileUtils.send(util, *args) rescue nil
|
|
67
62
|
}
|
|
68
63
|
end
|
|
69
64
|
|
|
70
|
-
TEMPLATES_PATH = Pathname.new(File.expand_path(
|
|
65
|
+
TEMPLATES_PATH = Pathname.new(File.expand_path('../../../templates', __dir__))
|
|
71
66
|
|
|
72
67
|
def copy_template(path, to:)
|
|
73
68
|
cp TEMPLATES_PATH.join(path), to
|
|
@@ -75,42 +70,33 @@ private
|
|
|
75
70
|
|
|
76
71
|
# Internal: Creates the Vite and vite-plugin-ruby configuration files.
|
|
77
72
|
def create_configuration_files
|
|
78
|
-
copy_template
|
|
79
|
-
append root.join(
|
|
73
|
+
copy_template 'config/vite.config.ts', to: root.join('vite.config.ts')
|
|
74
|
+
append root.join('Procfile.dev'), 'vite: bin/vite dev'
|
|
80
75
|
setup_app_files
|
|
81
76
|
ViteRuby.reload_with(config_path: config.config_path)
|
|
82
77
|
end
|
|
83
78
|
|
|
84
79
|
# Internal: Installs vite and vite-plugin-ruby at the project level.
|
|
85
80
|
def install_js_dependencies
|
|
86
|
-
package_json = root.join(
|
|
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(" ")
|
|
81
|
+
package_json = root.join('package.json')
|
|
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.
|
|
104
88
|
def install_gitignore
|
|
105
|
-
return unless (gitignore_file = root.join(
|
|
89
|
+
return unless (gitignore_file = root.join('.gitignore')).exist?
|
|
106
90
|
|
|
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
|
-
# https://
|
|
99
|
+
# https://vitejs.dev/guide/env-and-mode.html#env-files
|
|
114
100
|
*.local
|
|
115
101
|
GITIGNORE
|
|
116
102
|
end
|
|
@@ -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
|