vite_ruby 1.0.4 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8ef54a43f8457a31e8af99da6da97e50b9c406c7f0595f7840057dbf830c557
4
- data.tar.gz: fa00714f7a3ad4c63562950b596c564ffc1a8a1592c88a7e313f8a74027a05cb
3
+ metadata.gz: d9655dc4d615097239f9382298b8e2080b0ea63b9d23423cbb6c603817b6a3a1
4
+ data.tar.gz: 7046d45ec63fdcdb7e712113d0d6861a6c6df11ed06e0befac721315cb31546c
5
5
  SHA512:
6
- metadata.gz: 65f96a4b01af3c5a773fb6545d893ec072b5eaea006a7456878f651fdac459bd27ea9172dca776b5194011e513b6a10ed623c3c73705f1206825f88dc4909f76
7
- data.tar.gz: 60d845e48ac820e6791a7dafa4d5d549fb652b52c7e60bdcdca22cf6c62862717f04bef0043b9e3bbad6fddd9167eab58e93c5654ca1c5858c452960f07413a5
6
+ metadata.gz: c7553b547d6a411ec608128285c84321a96707906b29c8e5c94f91d8a63db65a8054cb6d529bbaf1f30acc1bbbe98df392ea1bea8f0c80b8c827e6a630e4ab38
7
+ data.tar.gz: 4c9b45b1804d5d8aa10cc8997bbe4ab4277d9d2de44c497e679c9d67bb65dcae516210a8b3813ed84aa4627d28656112a40c69878e7f89aab0b6df045cf496f2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,61 @@
1
+ # [1.2.0](https://github.com/ElMassimo/vite_ruby/compare/vite_ruby@1.1.2...vite_ruby@1.2.0) (2021-03-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Improve error messages when the Vite executable is missing ([#41](https://github.com/ElMassimo/vite_ruby/issues/41)) ([a79edc6](https://github.com/ElMassimo/vite_ruby/commit/a79edc6cc603c1094ede9e899226e98f734e7bbe))
7
+
8
+
9
+ ### Features
10
+
11
+ * Add `clobber` to the CLI, usable as `--clear` in the `dev` and `build` commands ([331d861](https://github.com/ElMassimo/vite_ruby/commit/331d86163c12eb3303d3975a94ecc205fa59dd41))
12
+ * Allow `clobber` to receive a `--mode` option. ([e6e7a6d](https://github.com/ElMassimo/vite_ruby/commit/e6e7a6dd0a2acf205d06877f76deb924c1d5aba7))
13
+
14
+
15
+
16
+ ## [1.1.2](https://github.com/ElMassimo/vite_ruby/compare/vite_ruby@1.1.1...vite_ruby@1.1.2) (2021-03-19)
17
+
18
+
19
+ ### Features
20
+
21
+ * Automatically retry failed builds after a certain time ([cbb3058](https://github.com/ElMassimo/vite_ruby/commit/cbb305863a49c46e7a0d95c773f56f7d822d01d9))
22
+
23
+
24
+
25
+ ## [1.1.1](https://github.com/ElMassimo/vite_ruby/compare/vite_ruby@1.1.0...vite_ruby@1.1.1) (2021-03-19)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * handle getaddrinfo errors when checking dev server ([#39](https://github.com/ElMassimo/vite_ruby/issues/39)) ([df57d6b](https://github.com/ElMassimo/vite_ruby/commit/df57d6ba5d8ed20e15bd2de3a57c8ff711671d28))
31
+
32
+
33
+
34
+ # [1.1.0](https://github.com/ElMassimo/vite_ruby/compare/vite_ruby@1.0.5...vite_ruby@1.1.0) (2021-03-07)
35
+
36
+
37
+ ### Bug Fixes
38
+
39
+ * Add development mutex in manifest to prevent re-entrant builds ([a6c6976](https://github.com/ElMassimo/vite_ruby/commit/a6c6976ba3821d8d6f26d012de13a440cb91c95b))
40
+ * Allow passing --inspect and other options to the build command ([1818ea4](https://github.com/ElMassimo/vite_ruby/commit/1818ea4f1d211923dfe0c04037baca8b2fd3b991))
41
+
42
+
43
+ ### Features
44
+
45
+ * Record status and timestamp of each build to provide better errors ([a35a64a](https://github.com/ElMassimo/vite_ruby/commit/a35a64ad4ca802da7bb6d5f5139985da864293a4))
46
+ * Stream build output to provide feedback as the command runs ([2bce338](https://github.com/ElMassimo/vite_ruby/commit/2bce33888513f6961da11ddfa9f9c703182abfa6))
47
+
48
+
49
+
50
+ ## [1.0.5](https://github.com/ElMassimo/vite_ruby/compare/vite_ruby@1.0.4...vite_ruby@1.0.5) (2021-03-03)
51
+
52
+
53
+ ### Bug Fixes
54
+
55
+ * Fix installation of JS packages, prevent silent failures (closes [#22](https://github.com/ElMassimo/vite_ruby/issues/22)) ([#23](https://github.com/ElMassimo/vite_ruby/issues/23)) ([d972e6f](https://github.com/ElMassimo/vite_ruby/commit/d972e6f3968988460753e7a831c8e9199bbd6891))
56
+
57
+
58
+
1
59
  ## [1.0.4](https://github.com/ElMassimo/vite_ruby/compare/vite_ruby@1.0.3...vite_ruby@1.0.4) (2021-02-25)
2
60
 
3
61
 
data/README.md CHANGED
@@ -70,6 +70,8 @@ Please use [Issues] to report bugs you find, and [Discussions] to make feature r
70
70
 
71
71
  Don't hesitate to _⭐️ star the project_ if you find it useful!
72
72
 
73
+ Using it in production? Always love to hear about it! 😃
74
+
73
75
 
74
76
  ## Special Thanks 🙏
75
77
 
data/default.vite.json CHANGED
@@ -13,5 +13,6 @@
13
13
  "https": null,
14
14
  "port": 3036,
15
15
  "hideBuildConsoleOutput": false,
16
+ "viteBinPath": "node_modules/.bin/vite",
16
17
  "watchAdditionalPaths": []
17
18
  }
data/lib/tasks/vite.rake CHANGED
@@ -22,7 +22,6 @@ namespace :vite do
22
22
  desc 'Remove the vite build output directory'
23
23
  task clobber: :'vite:verify_install' do
24
24
  ViteRuby.commands.clobber
25
- $stdout.puts "Removed vite build output directory #{ ViteRuby.config.build_output_dir }"
26
25
  end
27
26
 
28
27
  desc 'Verifies if ViteRuby is properly installed in this application'
data/lib/vite_ruby.rb CHANGED
@@ -28,7 +28,6 @@ class ViteRuby
28
28
 
29
29
  def_delegators :instance, :config, :commands, :run_proxy?
30
30
  def_delegators :config, :mode
31
- def_delegators 'ViteRuby::Runner.new', :run
32
31
 
33
32
  def instance
34
33
  @instance ||= ViteRuby.new
@@ -52,6 +51,11 @@ class ViteRuby
52
51
  load File.expand_path('tasks/vite.rake', __dir__)
53
52
  end
54
53
 
54
+ # Internal: Executes the vite binary.
55
+ def run(argv, **options)
56
+ ViteRuby::Runner.new(instance).run(argv, **options)
57
+ end
58
+
55
59
  # Internal: Refreshes the config after setting the env vars.
56
60
  def reload_with(env_vars)
57
61
  env.update(env_vars)
@@ -75,9 +79,6 @@ class ViteRuby
75
79
  end
76
80
  end
77
81
 
78
- extend Forwardable
79
- def_delegators :builder, :build
80
-
81
82
  attr_writer :logger
82
83
 
83
84
  def logger
@@ -93,7 +94,7 @@ class ViteRuby
93
94
  Socket.tcp(config.host, config.port, connect_timeout: config.dev_server_connect_timeout).close
94
95
  @running_at = Time.now
95
96
  true
96
- rescue SystemCallError
97
+ rescue StandardError
97
98
  @running_at = false
98
99
  end
99
100
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ # Internal: Value object with information about the last build.
6
+ ViteRuby::Build = Struct.new(:success, :timestamp, :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(attrs['success'], attrs['timestamp'] || 'never', attrs['digest'] || 'none', current_digest)
10
+ end
11
+
12
+ # Internal: A build is considered stale when watched files have changed since
13
+ # the last build, or when a certain time has ellapsed in case of failure.
14
+ def stale?
15
+ digest != current_digest || retry_failed?
16
+ end
17
+
18
+ # Internal: A build is considered fresh if watched files have not changed, or
19
+ # the last failed build happened recently.
20
+ def fresh?
21
+ !stale?
22
+ end
23
+
24
+ # Internal: To avoid cascading build failures, if the last build failed and it
25
+ # happened within a short time window, a new build should not be triggered.
26
+ def retry_failed?
27
+ !success && Time.parse(timestamp) + 3 < Time.now # 3 seconds
28
+ rescue ArgumentError
29
+ true
30
+ end
31
+
32
+ # Internal: Returns a new build with the specified result.
33
+ def with_result(success)
34
+ self.class.new(success, Time.now.strftime('%F %T'), current_digest)
35
+ end
36
+
37
+ # Internal: Returns a JSON string with the metadata of the build.
38
+ def to_json(*_args)
39
+ JSON.pretty_generate(to_h)
40
+ end
41
+ end
@@ -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.
@@ -10,23 +11,22 @@ class ViteRuby::Builder
10
11
 
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
- def build
14
- if stale?
15
- build_with_vite.tap { record_files_digest }
16
- else
17
- logger.debug 'Skipping build. Vite assets are already up-to-date ⚡️'
14
+ def build(*args)
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) }
18
+ elsif last_build.success
19
+ logger.debug "Skipping vite build. Watched files have not changed since the last build at #{ last_build.timestamp }"
18
20
  true
21
+ else
22
+ logger.error "Skipping vite build. Watched files have not changed since the build failed at #{ last_build.timestamp } ❌"
23
+ false
19
24
  end
20
25
  end
21
26
 
22
- # Public: Returns true if all the assets built by Vite are up to date.
23
- def fresh?
24
- previous_files_digest&.== watched_files_digest
25
- end
26
-
27
- # Public: Returns true if any of the assets built by Vite is out of date.
28
- def stale?
29
- !fresh?
27
+ # Internal: Reads the result of the last compilation from disk.
28
+ def last_build_metadata
29
+ ViteRuby::Build.from_previous(last_build_attrs, watched_files_digest)
30
30
  end
31
31
 
32
32
  private
@@ -35,21 +35,22 @@ private
35
35
 
36
36
  def_delegators :@vite_ruby, :config, :logger
37
37
 
38
- # Internal: Writes a digest of the watched files to disk for future checks.
39
- def record_files_digest
40
- config.build_cache_dir.mkpath
41
- files_digest_path.write(watched_files_digest)
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
+ {}
42
43
  end
43
44
 
44
- # Internal: The path of where a digest of the watched files is stored.
45
- def files_digest_path
46
- config.build_cache_dir.join("last-compilation-digest-#{ config.mode }")
45
+ # Internal: Writes a digest of the watched files to disk for future checks.
46
+ def record_build_metadata(success, build)
47
+ config.build_cache_dir.mkpath
48
+ last_build_path.write build.with_result(success).to_json
47
49
  end
48
50
 
49
- # Internal: Reads a digest of watched files from disk.
50
- def previous_files_digest
51
- files_digest_path.read if files_digest_path.exist? && config.manifest_path.exist?
52
- rescue Errno::ENOENT, Errno::ENOTDIR
51
+ # Internal: The file path where metadata of the last build is stored.
52
+ def last_build_path
53
+ config.build_cache_dir.join("last-build-#{ config.mode }.json")
53
54
  end
54
55
 
55
56
  # Internal: Returns a digest of all the watched files, allowing to detect
@@ -65,11 +66,11 @@ private
65
66
  # Public: Initiates a Vite build command to generate assets.
66
67
  #
67
68
  # Returns true if the build is successful, or false if it failed.
68
- def build_with_vite
69
+ def build_with_vite(*args)
69
70
  logger.info 'Building with Vite ⚡️'
70
71
 
71
- stdout, stderr, status = ViteRuby.run(['build'], capture: true)
72
- log_build_result(stdout, stderr, status)
72
+ stdout, stderr, status = ViteRuby.run(['build', *args], capture: true)
73
+ log_build_result(stdout, stderr.to_s, status)
73
74
 
74
75
  status.success?
75
76
  end
@@ -77,14 +78,14 @@ private
77
78
  # Internal: Outputs the build results.
78
79
  #
79
80
  # NOTE: By default it also outputs the manifest entries.
80
- def log_build_result(stdout, stderr, status)
81
+ def log_build_result(_stdout, stderr, status)
81
82
  if status.success?
82
83
  logger.info "Build with Vite complete: #{ config.build_output_dir }"
83
- logger.error(stderr.to_s) unless stderr.empty?
84
- logger.info(stdout) unless config.hide_build_console_output
84
+ logger.error stderr.to_s unless stderr.empty?
85
85
  else
86
- non_empty_streams = [stdout, stderr].delete_if(&:empty?)
87
- logger.error "Build with Vite failed:\n#{ non_empty_streams.join("\n\n") }"
86
+ logger.error stderr
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')
88
89
  end
89
90
  end
90
91
 
@@ -96,7 +97,11 @@ private
96
97
  *config.watch_additional_paths,
97
98
  "#{ config.source_code_dir }/**/*",
98
99
  'yarn.lock',
100
+ 'package-lock.json',
101
+ 'pnpm-lock.yaml',
99
102
  'package.json',
103
+ 'vite.config.ts',
104
+ 'vite.config.js',
100
105
  config.config_path,
101
106
  ].freeze
102
107
  end
data/lib/vite_ruby/cli.rb CHANGED
@@ -8,6 +8,7 @@ class ViteRuby::CLI
8
8
  extend Dry::CLI::Registry
9
9
 
10
10
  register 'build', Build, aliases: ['b']
11
+ register 'clobber', Clobber, aliases: %w[clean clear]
11
12
  register 'dev', Dev, aliases: %w[d serve]
12
13
  register 'install', Install, aliases: %w[setup init]
13
14
  register 'version', Version, aliases: ['v', '-v', '--version', 'info']
@@ -5,14 +5,21 @@ class ViteRuby::CLI::Build < Dry::CLI::Command
5
5
  DEFAULT_ENV = CURRENT_ENV || 'production'
6
6
 
7
7
  def self.shared_options
8
- option(:mode, default: self::DEFAULT_ENV, values: %w[development production], aliases: ['m'], desc: 'The build mode for Vite.')
8
+ option(:mode, default: self::DEFAULT_ENV, values: %w[development production test], aliases: ['m'], desc: 'The build mode for Vite')
9
+ option(:clobber, desc: 'Clear cache and previous builds', type: :boolean, aliases: %w[clean clear])
10
+ option(:debug, desc: 'Run Vite in verbose mode, printing all debugging output', aliases: ['verbose'], type: :boolean)
11
+ option(:inspect, desc: 'Run Vite in a debugging session with node --inspect-brk', aliases: ['inspect-brk'], type: :boolean)
12
+ option(:trace_deprecation, desc: 'Run Vite in debugging mode with node --trace-deprecation', aliases: ['trace-deprecation'], type: :boolean)
9
13
  end
10
14
 
11
15
  desc 'Bundle all entrypoints using Vite.'
12
16
  shared_options
17
+ option(:force, desc: 'Force the build even if assets have not changed', type: :boolean)
13
18
 
14
- def call(mode:)
19
+ def call(mode:, args: [], clobber: false, **boolean_opts)
15
20
  ViteRuby.env['VITE_RUBY_MODE'] = mode
16
- block_given? ? yield(mode) : ViteRuby.commands.build_from_task
21
+ ViteRuby.commands.clobber if clobber
22
+ boolean_opts.map { |name, value| args << "--#{ name }" if value }
23
+ block_given? ? yield(args) : ViteRuby.commands.build_from_task(*args)
17
24
  end
18
25
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ViteRuby::CLI::Clobber < Dry::CLI::Command
4
+ desc 'Clear the Vite cache, temp files, and builds'
5
+
6
+ current_env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
7
+
8
+ option(:mode, default: current_env, values: %w[development production test], aliases: ['m'], desc: 'The mode to use')
9
+
10
+ def call(**)
11
+ ViteRuby.commands.clobber
12
+ end
13
+ end
@@ -5,8 +5,9 @@ class ViteRuby::CLI::Dev < ViteRuby::CLI::Build
5
5
 
6
6
  desc 'Start the Vite development server.'
7
7
  shared_options
8
+ option(:force, desc: 'Force Vite to re-bundle dependencies', type: :boolean)
8
9
 
9
- def call(mode:, args: [])
10
- super(mode: mode) { ViteRuby.run(args) }
10
+ def call(**options)
11
+ super { |args| ViteRuby.run(args) }
11
12
  end
12
13
  end
@@ -75,7 +75,7 @@ private
75
75
  write(package_json, '{}') unless package_json.exist?
76
76
  Dir.chdir(root) do
77
77
  deps = "vite@#{ ViteRuby::DEFAULT_VITE_VERSION } vite-plugin-ruby@#{ ViteRuby::DEFAULT_PLUGIN_VERSION }"
78
- stdout, stderr, status = Open3.capture3({ 'CI' => 'true' }, "npx @antfu/ni -D #{ deps }")
78
+ stdout, stderr, status = Open3.capture3({ 'CI' => 'true' }, "npx --package @antfu/ni -- ni -D #{ deps }")
79
79
  stdout, stderr, = Open3.capture3({}, "yarn add -D #{ deps }") unless status.success?
80
80
  say(stdout, "\n", stderr)
81
81
  end
@@ -8,24 +8,24 @@ class ViteRuby::Commands
8
8
  end
9
9
 
10
10
  # Public: Defaults to production, and exits if the build fails.
11
- def build_from_task
11
+ def build_from_task(*args)
12
12
  with_node_env(ENV.fetch('NODE_ENV', 'production')) {
13
13
  ensure_log_goes_to_stdout {
14
- build || exit!
14
+ build(*args) || exit!
15
15
  }
16
16
  }
17
17
  end
18
18
 
19
19
  # Public: Builds all assets that are managed by Vite, from the entrypoints.
20
- def build
21
- builder.build.tap { manifest.refresh }
20
+ def build(*args)
21
+ builder.build(*args).tap { manifest.refresh }
22
22
  end
23
23
 
24
24
  # Public: Removes all build cache and previously compiled assets.
25
25
  def clobber
26
- config.build_output_dir.rmtree if config.build_output_dir.exist?
27
- config.build_cache_dir.rmtree if config.build_cache_dir.exist?
28
- config.vite_cache_dir.rmtree if config.vite_cache_dir.exist?
26
+ dirs = [config.build_output_dir, config.build_cache_dir, config.vite_cache_dir]
27
+ dirs.each { |dir| dir.rmtree if dir.exist? }
28
+ $stdout.puts "Removed vite cache and output dirs:\n\t#{ dirs.join("\n\t") }"
29
29
  end
30
30
 
31
31
  # Public: Receives arguments from a rake task.
@@ -69,6 +69,7 @@ class ViteRuby::Commands
69
69
  def verify_install
70
70
  unless File.exist?(config.root.join('bin/vite'))
71
71
  warn <<~WARN
72
+
72
73
  vite binstub not found.
73
74
  Have you run `bundle binstub vite`?
74
75
  Make sure the bin directory and bin/vite are not included in .gitignore
@@ -78,6 +79,7 @@ class ViteRuby::Commands
78
79
  config_path = config.root.join(config.config_path)
79
80
  unless config_path.exist?
80
81
  warn <<~WARN
82
+
81
83
  Configuration #{ config_path } file for vite-plugin-ruby not found.
82
84
  Make sure `bundle exec vite install` has run successfully before running dependent tasks.
83
85
  WARN
@@ -88,7 +90,7 @@ class ViteRuby::Commands
88
90
  # Internal: Prints information about ViteRuby's environment.
89
91
  def print_info
90
92
  Dir.chdir(config.root) do
91
- $stdout.puts "Is bin/vite present?: #{ File.exist? 'bin/vite' }"
93
+ $stdout.puts "bin/vite present?: #{ File.exist? 'bin/vite' }"
92
94
 
93
95
  $stdout.puts "vite_ruby: #{ ViteRuby::VERSION }"
94
96
  ViteRuby.framework_libraries.each do |framework, library|
@@ -98,11 +100,14 @@ class ViteRuby::Commands
98
100
 
99
101
  $stdout.puts "node: #{ `node --version` }"
100
102
  $stdout.puts "npm: #{ `npm --version` }"
101
- $stdout.puts "yarn: #{ `yarn --version` }"
103
+ $stdout.puts "yarn: #{ `yarn --version` rescue nil }"
104
+ $stdout.puts "pnpm: #{ `pnpm --version` rescue nil }"
102
105
  $stdout.puts "ruby: #{ `ruby --version` }"
103
106
 
104
107
  $stdout.puts "\n"
105
- $stdout.puts "vite-plugin-ruby: \n#{ `npm list vite-plugin-ruby version` }"
108
+ packages = `npm ls vite vite-plugin-ruby`
109
+ 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
+ $stdout.puts packages_msg
106
111
  end
107
112
  end
108
113
 
@@ -144,10 +149,12 @@ private
144
149
  end
145
150
 
146
151
  def ensure_log_goes_to_stdout
147
- old_logger = logger
148
- self.logger = Logger.new($stdout)
152
+ old_logger, original_sync = logger, $stdout.sync
153
+
154
+ $stdout.sync = true
155
+ self.logger = Logger.new($stdout, formatter: proc { |_, _, progname, msg| progname == 'vite' ? msg : "#{ msg }\n" })
149
156
  yield
150
157
  ensure
151
- self.logger = old_logger
158
+ self.logger, $stdout.sync = old_logger, original_sync
152
159
  end
153
160
  end
@@ -91,7 +91,7 @@ private
91
91
  }
92
92
 
93
93
  # Internal: Default values for a Ruby application.
94
- def config_defaults(asset_host: nil, mode: ENV.fetch('RACK_ENV', 'production'), root: Dir.pwd)
94
+ def config_defaults(asset_host: nil, mode: ENV.fetch('RACK_ENV', 'development'), root: Dir.pwd)
95
95
  {
96
96
  'asset_host' => option_from_env('asset_host') || asset_host,
97
97
  'config_path' => option_from_env('config_path') || DEFAULT_CONFIG.fetch('config_path'),
@@ -9,7 +9,7 @@ class ViteRuby::DevServerProxy < Rack::Proxy
9
9
 
10
10
  def initialize(app = nil, options = {})
11
11
  @vite_ruby = options.delete(:vite_ruby) || ViteRuby.instance
12
- options[:streaming] = false if ViteRuby.mode == 'test' && !options.key?(:streaming)
12
+ options[:streaming] = false if config.mode == 'test' && !options.key?(:streaming)
13
13
  super
14
14
  end
15
15
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal: Provides common functionality for errors.
4
+ class ViteRuby::Error < StandardError
5
+ def message
6
+ super.sub(':troubleshooting:', <<~MSG)
7
+ Visit the Troubleshooting guide for more information:
8
+ https://vite-ruby.netlify.app/guide/troubleshooting.html#troubleshooting
9
+ MSG
10
+ end
11
+ end
@@ -10,11 +10,9 @@
10
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
- class MissingEntryError < StandardError
14
- end
15
-
16
13
  def initialize(vite_ruby)
17
14
  @vite_ruby = vite_ruby
15
+ @build_mutex = Mutex.new if config.auto_build
18
16
  end
19
17
 
20
18
  # Public: Returns the path for the specified Vite entrypoint file.
@@ -65,7 +63,7 @@ protected
65
63
  # manifest.lookup('calendar.js')
66
64
  # => { "file" => "/vite/assets/calendar-1016838bab065ae1e122.js", "imports" => [] }
67
65
  def lookup(name, type: nil)
68
- build if should_build?
66
+ @build_mutex.synchronize { builder.build } if should_build?
69
67
 
70
68
  find_manifest_entry(with_file_extension(name, type))
71
69
  end
@@ -74,7 +72,7 @@ private
74
72
 
75
73
  extend Forwardable
76
74
 
77
- def_delegators :@vite_ruby, :config, :build, :dev_server_running?
75
+ def_delegators :@vite_ruby, :config, :builder, :dev_server_running?
78
76
 
79
77
  # NOTE: Auto compilation is convenient when running tests, when the developer
80
78
  # won't focus on the frontend, or when running the Vite server is not desired.
@@ -141,28 +139,11 @@ private
141
139
 
142
140
  # Internal: Raises a detailed message when an entry is missing in the manifest.
143
141
  def missing_entry_error(name, type: nil, **_options)
144
- file_name = with_file_extension(name, type)
145
- raise ViteRuby::Manifest::MissingEntryError, <<~MSG
146
- Vite Ruby can't find #{ file_name } in #{ config.manifest_path } or #{ config.assets_manifest_path }.
147
-
148
- Possible causes:
149
- #{ missing_entry_causes.map { |cause| "\t- #{ cause }" }.join("\n") }
150
-
151
- Content in your manifests:
152
- #{ JSON.pretty_generate(@manifest) }
153
- MSG
154
- end
155
-
156
- def missing_entry_causes
157
- local = config.auto_build
158
- [
159
- (dev_server_running? && 'Vite has not yet re-built your latest changes.'),
160
- (local && !dev_server_running? && "\"autoBuild\": false in your #{ config.mode } configuration."),
161
- (local && !dev_server_running? && 'The Vite development server has crashed or is no longer available.'),
162
- 'You have misconfigured config/vite.json file.',
163
- (!local && 'Assets have not been precompiled'),
164
- ].select(&:itself)
165
- rescue StandardError
166
- []
142
+ raise ViteRuby::MissingEntrypointError, OpenStruct.new(
143
+ file_name: with_file_extension(name, type),
144
+ last_build: builder.last_build_metadata,
145
+ manifest: @manifest,
146
+ config: config,
147
+ )
167
148
  end
168
149
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal: Raised when an entry is not found in the build manifest.
4
+ #
5
+ # NOTE: The complexity here is justified by the improved usability of providing
6
+ # a more specific error message depending on the situation.
7
+ class ViteRuby::MissingEntrypointError < ViteRuby::Error
8
+ extend Forwardable
9
+ def_delegators :@info, :file_name, :last_build, :manifest, :config
10
+
11
+ def initialize(info)
12
+ @info = info
13
+ super <<~MSG
14
+ Vite Ruby can't find #{ file_name } in #{ config.manifest_path.relative_path_from(config.root) } or #{ config.assets_manifest_path.relative_path_from(config.root) }.
15
+
16
+ Possible causes:
17
+ #{ possible_causes(last_build) }
18
+ :troubleshooting:
19
+ #{ "\nContent in your manifests:\n#{ JSON.pretty_generate(manifest) }\n" if last_build.success }
20
+ #{ "Last build in #{ config.mode } mode:\n#{ last_build.to_json }\n" unless last_build.success.nil? }
21
+ MSG
22
+ end
23
+
24
+ def possible_causes(last_build)
25
+ return FAILED_BUILD_CAUSES.sub(':mode:', config.mode) if last_build.success == false
26
+ return DEFAULT_CAUSES if config.auto_build
27
+
28
+ DEFAULT_CAUSES + NO_AUTO_BUILD_CAUSES
29
+ end
30
+
31
+ FAILED_BUILD_CAUSES = <<-MSG
32
+ - The last build failed. Try running `bin/vite build --clear --mode=:mode:` manually and check for errors.
33
+ MSG
34
+
35
+ DEFAULT_CAUSES = <<-MSG
36
+ - The file path is incorrect.
37
+ - The file is not in the entrypoints directory.
38
+ - Some files are outside the sourceCodeDir, and have not been added to watchAdditionalPaths.
39
+ MSG
40
+
41
+ NO_AUTO_BUILD_CAUSES = <<-MSG
42
+ - You have not run `bin/vite dev` to start Vite, or the dev server is not reachable.
43
+ - "autoBuild" is set to `false` in your config/vite.json for this environment.
44
+ MSG
45
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Internal: Raised when the Vite executable can not be found.
4
+ class ViteRuby::MissingExecutableError < ViteRuby::Error
5
+ def initialize(error = nil)
6
+ super <<~MSG
7
+ ❌ The vite binary is not available. Have you installed Vite?
8
+
9
+ :troubleshooting:
10
+ #{ error }
11
+ MSG
12
+ end
13
+ end
@@ -4,54 +4,63 @@ require 'open3'
4
4
 
5
5
  # Public: Executes Vite commands, providing conveniences for debugging.
6
6
  class ViteRuby::Runner
7
+ def initialize(vite_ruby)
8
+ @vite_ruby = vite_ruby
9
+ end
10
+
7
11
  # Public: Executes Vite with the specified arguments.
8
- def run(argv, **options)
9
- $stdout.sync = true
10
- detect_unsupported_switches!(argv)
11
- execute_command(argv.clone, **options)
12
+ def run(argv, capture: false)
13
+ Dir.chdir(config.root) {
14
+ cmd = command_for(argv)
15
+ capture ? capture3_with_output(*cmd, chdir: config.root) : Kernel.exec(*cmd)
16
+ }
17
+ rescue Errno::ENOENT => error
18
+ raise ViteRuby::MissingExecutableError, error
12
19
  end
13
20
 
14
21
  private
15
22
 
16
- UNSUPPORTED_SWITCHES = %w[--host --port --https --root -r --config -c].freeze
23
+ extend Forwardable
17
24
 
18
- # Internal: Allows to prevent configuration mistakes by ensuring the Ruby app
19
- # and vite-plugin-ruby are using the same configuration for the dev server.
20
- def detect_unsupported_switches!(args)
21
- return unless (unsupported = UNSUPPORTED_SWITCHES & args).any?
22
-
23
- $stdout.puts "Please set the following switches in your vite.json instead: #{ unsupported }."
24
- exit!
25
- end
26
-
27
- # Internal: Executes the command with the specified arguments.
28
- def execute_command(args, capture: false)
29
- if capture
30
- Open3.capture3(*command_for(args), chdir: ViteRuby.config.root)
31
- else
32
- Dir.chdir(ViteRuby.config.root) { Kernel.exec(*command_for(args)) }
33
- end
34
- end
25
+ def_delegators :@vite_ruby, :config, :logger
35
26
 
36
27
  # Internal: Returns an Array with the command to run.
37
28
  def command_for(args)
38
- [vite_env].tap do |cmd|
39
- cmd.append('node', '--inspect-brk') if args.include?('--debug')
40
- cmd.append('node', '--trace-deprecation') if args.delete('--trace-deprecation')
41
- cmd.append(*vite_executable(cmd))
29
+ [config.to_env].tap do |cmd|
30
+ args = args.clone
31
+ cmd.append('node', '--inspect-brk') if args.delete('--inspect')
32
+ cmd.append('node', '--trace-deprecation') if args.delete('--trace_deprecation')
33
+ cmd.append(vite_executable)
42
34
  cmd.append(*args)
43
- cmd.append('--mode', ViteRuby.mode) unless args.include?('--mode') || args.include?('-m')
35
+ cmd.append('--mode', config.mode) unless args.include?('--mode') || args.include?('-m')
44
36
  end
45
37
  end
46
38
 
47
- # Internal: The environment variables to pass to the command.
48
- def vite_env
49
- ViteRuby.config.to_env
39
+ # Internal: Resolves to an executable for Vite.
40
+ def vite_executable
41
+ bin_path = config.vite_bin_path
42
+ File.exist?(bin_path) ? bin_path : "#{ `npm bin`.chomp }/vite"
50
43
  end
51
44
 
52
- # Internal: Resolves to an executable for Vite.
53
- def vite_executable(cmd)
54
- npx = cmd.include?('node') ? `which npx`.chomp("\n") : 'npx' rescue 'npx'
55
- [npx, 'vite']
45
+ # Internal: A modified version of capture3 that continuosly prints stdout.
46
+ # NOTE: This improves the experience of running bin/vite build.
47
+ def capture3_with_output(*cmd, **opts)
48
+ return Open3.capture3(*cmd, opts) if config.hide_build_console_output
49
+
50
+ Open3.popen3(*cmd, opts) { |_stdin, stdout, stderr, wait_threads|
51
+ out = Thread.new { read_lines(stdout) { |l| logger.info('vite') { l } } }
52
+ err = Thread.new { stderr.read }
53
+ [out.value, err.value, wait_threads.value]
54
+ }
55
+ end
56
+
57
+ # Internal: Reads and yield every line in the stream. Returns the full content.
58
+ def read_lines(io)
59
+ buffer = +''
60
+ while line = io.gets
61
+ buffer << line
62
+ yield line
63
+ end
64
+ buffer
56
65
  end
57
66
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ViteRuby
4
- VERSION = '1.0.4'
4
+ VERSION = '1.2.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vite_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Máximo Mussini
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-25 00:00:00.000000000 Z
11
+ date: 2021-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-cli
@@ -28,6 +28,9 @@ dependencies:
28
28
  name: rack-proxy
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.6'
31
34
  - - ">="
32
35
  - !ruby/object:Gem::Version
33
36
  version: 0.6.1
@@ -35,6 +38,9 @@ dependencies:
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '0.6'
38
44
  - - ">="
39
45
  - !ruby/object:Gem::Version
40
46
  version: 0.6.1
@@ -42,58 +48,156 @@ dependencies:
42
48
  name: zeitwerk
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
- - - ">="
51
+ - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '0'
53
+ version: '2.2'
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
- - - ">="
58
+ - - "~>"
53
59
  - !ruby/object:Gem::Version
54
- version: '0'
60
+ version: '2.2'
55
61
  - !ruby/object:Gem::Dependency
56
- name: bundler
62
+ name: m
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
- - - ">="
65
+ - - "~>"
60
66
  - !ruby/object:Gem::Version
61
- version: 1.3.0
67
+ version: '1.5'
62
68
  type: :development
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
- - - ">="
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.5'
75
+ - !ruby/object:Gem::Dependency
76
+ name: minitest
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '5.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
67
87
  - !ruby/object:Gem::Version
68
- version: 1.3.0
88
+ version: '5.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: minitest-reporters
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1.4'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1.4'
103
+ - !ruby/object:Gem::Dependency
104
+ name: minitest-stub_any_instance
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1.0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: pry-byebug
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '3.9'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '3.9'
131
+ - !ruby/object:Gem::Dependency
132
+ name: rake
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '13.0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '13.0'
69
145
  - !ruby/object:Gem::Dependency
70
146
  name: rubocop
71
147
  requirement: !ruby/object:Gem::Requirement
72
148
  requirements:
73
- - - ">="
149
+ - - "~>"
74
150
  - !ruby/object:Gem::Version
75
- version: '0'
151
+ version: '1.9'
76
152
  type: :development
77
153
  prerelease: false
78
154
  version_requirements: !ruby/object:Gem::Requirement
79
155
  requirements:
80
- - - ">="
156
+ - - "~>"
81
157
  - !ruby/object:Gem::Version
82
- version: '0'
158
+ version: '1.9'
159
+ - !ruby/object:Gem::Dependency
160
+ name: rubocop-minitest
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '0.10'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - "~>"
171
+ - !ruby/object:Gem::Version
172
+ version: '0.10'
83
173
  - !ruby/object:Gem::Dependency
84
174
  name: rubocop-performance
85
175
  requirement: !ruby/object:Gem::Requirement
86
176
  requirements:
87
- - - ">="
177
+ - - "~>"
88
178
  - !ruby/object:Gem::Version
89
- version: '0'
179
+ version: '1.9'
90
180
  type: :development
91
181
  prerelease: false
92
182
  version_requirements: !ruby/object:Gem::Requirement
93
183
  requirements:
94
- - - ">="
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: '1.9'
187
+ - !ruby/object:Gem::Dependency
188
+ name: simplecov
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "<"
192
+ - !ruby/object:Gem::Version
193
+ version: '0.18'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "<"
95
199
  - !ruby/object:Gem::Version
96
- version: '0'
200
+ version: '0.18'
97
201
  description:
98
202
  email:
99
203
  - maximomussini@gmail.com
@@ -109,16 +213,21 @@ files:
109
213
  - exe/vite
110
214
  - lib/tasks/vite.rake
111
215
  - lib/vite_ruby.rb
216
+ - lib/vite_ruby/build.rb
112
217
  - lib/vite_ruby/builder.rb
113
218
  - lib/vite_ruby/cli.rb
114
219
  - lib/vite_ruby/cli/build.rb
220
+ - lib/vite_ruby/cli/clobber.rb
115
221
  - lib/vite_ruby/cli/dev.rb
116
222
  - lib/vite_ruby/cli/install.rb
117
223
  - lib/vite_ruby/cli/version.rb
118
224
  - lib/vite_ruby/commands.rb
119
225
  - lib/vite_ruby/config.rb
120
226
  - lib/vite_ruby/dev_server_proxy.rb
227
+ - lib/vite_ruby/error.rb
121
228
  - lib/vite_ruby/manifest.rb
229
+ - lib/vite_ruby/missing_entrypoint_error.rb
230
+ - lib/vite_ruby/missing_executable_error.rb
122
231
  - lib/vite_ruby/runner.rb
123
232
  - lib/vite_ruby/version.rb
124
233
  - templates/config/vite.config.ts
@@ -128,8 +237,8 @@ homepage: https://github.com/ElMassimo/vite_ruby
128
237
  licenses:
129
238
  - MIT
130
239
  metadata:
131
- source_code_uri: https://github.com/ElMassimo/vite_ruby/tree/vite_ruby@1.0.4/vite_ruby
132
- changelog_uri: https://github.com/ElMassimo/vite_ruby/blob/vite_ruby@1.0.4/vite_ruby/CHANGELOG.md
240
+ source_code_uri: https://github.com/ElMassimo/vite_ruby/tree/vite_ruby@1.2.0/vite_ruby
241
+ changelog_uri: https://github.com/ElMassimo/vite_ruby/blob/vite_ruby@1.2.0/vite_ruby/CHANGELOG.md
133
242
  post_install_message:
134
243
  rdoc_options: []
135
244
  require_paths: