# frozen_string_literal: true# Public: Registry for accessing resources managed by Vite, using a generated# manifest file which maps entrypoint names to file paths.## Example:# lookup_entrypoint('calendar', type: :javascript)# => { "file" => "/vite/assets/calendar-1016838bab065ae1e314.js", "imports" => [] }## NOTE: Using `"autoBuild": true` in `config/vite.json` file will trigger a build# on demand as needed, before performing any lookup.classViteRuby::Manifestdefinitialize(vite_ruby)@vite_ruby=vite_ruby@build_mutex=Mutex.newifconfig.auto_buildend# Public: Returns the path for the specified Vite entrypoint file.## Raises an error if the resource could not be found in the manifest.defpath_for(name,**options)lookup!(name,**options).fetch('file')end# Public: Returns scripts, imported modules, and stylesheets for the specified# entrypoint files.defresolve_entries(*names,**options)entries=names.map{|name|lookup!(name,**options)}script_paths=entries.map{|entry|entry.fetch('file')}imports=dev_server_running??[]:entries.flat_map{|entry|entry['imports']}.compact.uniq{scripts: script_paths,imports: imports.map{|entry|entry.fetch('file')}.uniq,stylesheets: dev_server_running??[]:(entries+imports).flat_map{|entry|entry['css']}.compact.uniq,}end# Public: Refreshes the cached mappings by reading the updated manifest files.defrefresh@manifest=load_manifestend# Public: The path from where the browser can download the Vite HMR client.defvite_client_srcprefix_asset_with_host('@vite/client')ifdev_server_running?end# Public: The content of the preamble needed by the React Refresh plugin.defreact_refresh_preambleifdev_server_running?<<~REACT_REFRESH
<script type="module">
import RefreshRuntime from '#{prefix_asset_with_host('@react-refresh')}'
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>
REACT_REFRESHendendprotected# Internal: Strict version of lookup.## Returns a relative path for the asset, or raises an error if not found.deflookup!(name,**options)lookup(name,**options)||missing_entry_error(name,**options)end# Internal: Computes the path for a given Vite asset using manifest.json.## Returns a relative path, or nil if the asset is not found.## Example:# manifest.lookup('calendar.js')# => { "file" => "/vite/assets/calendar-1016838bab065ae1e122.js", "imports" => [] }deflookup(name,**options)@build_mutex.synchronize{builder.build||(returnnil)}ifshould_build?find_manifest_entryresolve_entry_name(name,**options)endprivate# Internal: The prefix used by Vite.js to request files with an absolute path.FS_PREFIX='/@fs/'extendForwardabledef_delegators:@vite_ruby,:config,:builder,:dev_server_running?# NOTE: Auto compilation is convenient when running tests, when the developer# won't focus on the frontend, or when running the Vite server is not desired.defshould_build?config.auto_build&&!dev_server_running?end# Internal: Finds the specified entry in the manifest.deffind_manifest_entry(name)ifdev_server_running?{'file'=>prefix_vite_asset(name)}elsemanifest[name]endend# Internal: The parsed data from manifest.json.## NOTE: When using build-on-demand in development and testing, the manifest# is reloaded automatically before each lookup, to ensure it's always fresh.defmanifestreturnrefreshifconfig.auto_build@manifest||=load_manifestend# Internal: Loads and merges the manifest files, resolving the asset paths.defload_manifestfiles=config.manifest_pathsfiles.map{|path|JSON.parse(path.read)}.inject({},&:merge).tap(&method(:resolve_references))end# Internal: Scopes an asset to the output folder in public, as a path.defprefix_vite_asset(path)File.join("/#{config.public_output_dir}",path)end# Internal: Prefixes an asset with the `asset_host` for tags that do not use# the framework tag helpers.defprefix_asset_with_host(path)File.join(config.asset_host||'/',config.public_output_dir,path)end# Internal: Resolves the paths that reference a manifest entry.defresolve_references(manifest)manifest.each_valuedo|entry|entry['file']=prefix_vite_asset(entry['file'])%w[css assets].eachdo|key|entry[key]=entry[key].map{|path|prefix_vite_asset(path)}ifentry[key]endentry['imports']&.map!{|name|manifest.fetch(name)}endend# Internal: Resolves the manifest entry name for the specified resource.defresolve_entry_name(name,type: nil)returnresolve_virtual_entry(name)iftype==:virtualname=with_file_extension(name.to_s,type)raiseArgumentError,"Asset names can not be relative. Found: #{name}"ifname.start_with?('.')# Explicit path, relative to the source_code_dir.name.sub(%r{^~/(.+)$}){returnRegexp.last_match(1)}# Explicit path, relative to the project root.name.sub(%r{^/(.+)$}){returnresolve_absolute_entry(Regexp.last_match(1))}# Sugar: Prefix with the entrypoints dir if the path is not nested.name.include?('/')?name:File.join(config.entrypoints_dir,name)end# Internal: Entry names in the manifest are relative to the Vite.js.# During develoment, files outside the root must be requested explicitly.defresolve_absolute_entry(name)ifdev_server_running?File.join(FS_PREFIX,config.root,name)elseconfig.root.join(name).relative_path_from(config.vite_root_dir).to_sendend# Internal: Resolves a virtual entry by walking all the manifest keys.defresolve_virtual_entry(name)manifest.keys.find{|file|file.include?(name)}||nameend# Internal: Adds a file extension to the file name, unless it already has one.defwith_file_extension(name,entry_type)ifFile.extname(name).empty?&&(ext=extension_for_type(entry_type))"#{name}.#{ext}"elsenameendend# Internal: Allows to receive :javascript and :stylesheet as :type in helpers.defextension_for_type(entry_type)caseentry_typewhen:javascriptthen'js'when:stylesheetthen'css'when:typescriptthen'ts'elseentry_typeendend# Internal: Raises a detailed message when an entry is missing in the manifest.defmissing_entry_error(name,**options)raiseViteRuby::MissingEntrypointError,OpenStruct.new(file_name: resolve_entry_name(name,**options),last_build: builder.last_build_metadata,manifest: @manifest,config: config,)endend