lib/vite_ruby/builder.rb in vite_ruby-1.0.5 vs lib/vite_ruby/builder.rb in vite_ruby-1.1.0

- old
+ new

@@ -1,59 +1,60 @@ # frozen_string_literal: true +require 'json' require 'digest/sha1' # Public: Keeps track of watched files and triggers builds as needed. class ViteRuby::Builder def initialize(vite_ruby) @vite_ruby = vite_ruby end # Public: Checks if the watched files have changed since the last compilation, # and triggers a Vite build if any files have changed. - def build - if stale? - build_with_vite.tap { record_files_digest } - else - logger.debug 'Skipping build. Vite assets are already up-to-date ⚡️' + def build(*args) + last_build = last_build_metadata + if args.delete('--force') || last_build.stale? + build_with_vite(*args).tap { |success| record_build_metadata(success, last_build) } + elsif last_build.success + logger.debug "Skipping vite build. Watched files have not changed since the last build at #{ last_build.timestamp }" true + else + logger.error "Skipping vite build. Watched files have not changed since the build failed at #{ last_build.timestamp } ❌" + false end end - # Public: Returns true if all the assets built by Vite are up to date. - def fresh? - previous_files_digest&.== watched_files_digest + # Internal: Reads the result of the last compilation from disk. + def last_build_metadata + ViteRuby::Build.from_previous(last_build_attrs, watched_files_digest) end - # Public: Returns true if any of the assets built by Vite is out of date. - def stale? - !fresh? - end - private extend Forwardable def_delegators :@vite_ruby, :config, :logger + # Internal: Reads metadata recorded on the last build, if it exists. + def last_build_attrs + last_build_path.exist? ? JSON.parse(last_build_path.read.to_s) : {} + rescue JSON::JSONError, Errno::ENOENT, Errno::ENOTDIR + {} + end + # Internal: Writes a digest of the watched files to disk for future checks. - def record_files_digest + def record_build_metadata(success, build) config.build_cache_dir.mkpath - files_digest_path.write(watched_files_digest) + last_build_path.write build.with_result(success).to_json end - # Internal: The path of where a digest of the watched files is stored. - def files_digest_path - config.build_cache_dir.join("last-compilation-digest-#{ config.mode }") + # Internal: The file path where metadata of the last build is stored. + def last_build_path + config.build_cache_dir.join("last-build-#{ config.mode }.json") end - # Internal: Reads a digest of watched files from disk. - def previous_files_digest - files_digest_path.read if files_digest_path.exist? && config.manifest_path.exist? - rescue Errno::ENOENT, Errno::ENOTDIR - end - # Internal: Returns a digest of all the watched files, allowing to detect # changes, and skip Vite builds if no files have changed. def watched_files_digest Dir.chdir File.expand_path(config.root) do files = Dir[*watched_paths].reject { |f| File.directory?(f) } @@ -63,32 +64,30 @@ end # Public: Initiates a Vite build command to generate assets. # # Returns true if the build is successful, or false if it failed. - def build_with_vite + def build_with_vite(*args) logger.info 'Building with Vite ⚡️' - stdout, stderr, status = ViteRuby.run(['build'], capture: true) - log_build_result(stdout, stderr, status) + stdout, stderr, status = ViteRuby.run(['build', *args], capture: true) + log_build_result(stdout, stderr.to_s, status) status.success? end # Internal: Outputs the build results. # # NOTE: By default it also outputs the manifest entries. - def log_build_result(stdout, stderr, status) + def log_build_result(_stdout, stderr, status) if status.success? logger.info "Build with Vite complete: #{ config.build_output_dir }" - logger.error(stderr.to_s) unless stderr.empty? - logger.info(stdout) unless config.hide_build_console_output + logger.error stderr.to_s unless stderr.empty? else - non_empty_streams = [stdout, stderr].delete_if(&:empty?) - errors = non_empty_streams.join("\n\n") - errors += "\n❌ Check that vite and vite-plugin-ruby are in devDependencies and have been installed. " if errors.include?('ERR! canceled') - logger.error "Build with Vite failed:\n#{ errors }" + logger.error stderr + logger.error 'Build with Vite failed! ❌' + logger.error '❌ Check that vite and vite-plugin-ruby are in devDependencies and have been installed. ' if stderr.include?('ERR! canceled') end end # Internal: Files and directories that should be watched for changes. # @@ -96,10 +95,14 @@ def watched_paths [ *config.watch_additional_paths, "#{ config.source_code_dir }/**/*", 'yarn.lock', + 'package-lock.json', + 'pnpm-lock.yaml', 'package.json', + 'vite.config.ts', + 'vite.config.js', config.config_path, ].freeze end end