Class: Dommy::Js::ModuleLoader
- Inherits:
-
Object
- Object
- Dommy::Js::ModuleLoader
- Defined in:
- lib/dommy/js/module_loader.rb
Overview
The ESM resolver the engine consults for every import. Resolves a
specifier to an absolute URL (bare via the import map, relative against
the importer, absolute as-is), then fetches its source through the
Resources interface. CSS imports become an empty module (apps that
import "./x.css" for side effects don't crash). Returns the engine
contract: { code:, as: } | nil (nil → module resolution error).
Constant Summary collapse
- CSS_STUB =
An empty default export so
import sheet from "./x.css"yields an object rather than failing — layout/styling is out of scope. "export default {};"
Instance Method Summary collapse
-
#call(specifier, importer = nil) ⇒ Object
The engine module-loader callable.
-
#initialize(resources, import_map, base_url: nil) ⇒ ModuleLoader
constructor
A new instance of ModuleLoader.
-
#resolve_url(specifier, importer = nil) ⇒ Object
Resolve a specifier to an absolute URL string (nil if unresolvable).
-
#seed(url, source) ⇒ Object
Register an in-memory module source under
url(served before any network fetch). -
#seed_inline(preferred_url, source) ⇒ Object
Seed an inline module under
preferred_url(the document URL) if free, so the common single-inline-module page gets a cleanimport.meta.url== the page URL.
Constructor Details
#initialize(resources, import_map, base_url: nil) ⇒ ModuleLoader
Returns a new instance of ModuleLoader.
18 19 20 21 22 23 |
# File 'lib/dommy/js/module_loader.rb', line 18 def initialize(resources, import_map, base_url: nil) @resources = resources @import_map = import_map @base_url = base_url.to_s @seeded = {} end |
Instance Method Details
#call(specifier, importer = nil) ⇒ Object
The engine module-loader callable.
55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/dommy/js/module_loader.rb', line 55 def call(specifier, importer = nil) url = resolve_url(specifier, importer) return nil unless url return {code: @seeded[url], as: url} if @seeded.key?(url) return {code: CSS_STUB, as: url} if css?(url) response = @resources&.get(url) return nil unless response&.success? {code: response.body, as: url} end |
#resolve_url(specifier, importer = nil) ⇒ Object
Resolve a specifier to an absolute URL string (nil if unresolvable). Bare specifiers go through the import map; relative/absolute resolve against the importer (or the document base URL for the entry module).
71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/dommy/js/module_loader.rb', line 71 def resolve_url(specifier, importer = nil) spec = specifier.to_s base = importer.to_s.empty? ? @base_url : importer.to_s if relative?(spec) || absolute?(spec) || spec.start_with?("/") join(base, spec) else mapped = @import_map&.resolve(spec, importer) mapped ? join(base, mapped) : nil end end |
#seed(url, source) ⇒ Object
Register an in-memory module source under url (served before any
network fetch). Used to give an inline <script type="module"> a real
document-based URL as its module identity, so its relative imports
resolve against the page instead of a synthetic filename.
29 30 31 32 |
# File 'lib/dommy/js/module_loader.rb', line 29 def seed(url, source) @seeded[url.to_s] = source.to_s url.to_s end |
#seed_inline(preferred_url, source) ⇒ Object
Seed an inline module under preferred_url (the document URL) if free,
so the common single-inline-module page gets a clean
import.meta.url == the page URL. A second inline module on the same
page falls back to a #dommy-inline-N fragment for a unique module
identity (the engine caches modules by canonical name); the fragment is
ignored when resolving relative imports, so ./x still resolves against
the page. Returns the chosen URL.
41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/dommy/js/module_loader.rb', line 41 def seed_inline(preferred_url, source) base = preferred_url.to_s base = "about:blank" if base.empty? url = base i = 0 while @seeded.key?(url) i += 1 url = "#{base}#dommy-inline-#{i}" end @seeded[url] = source.to_s url end |