class Builder
Builder class for constructing import maps with scoped base URIs.
The builder supports nested with(base:) blocks where each base is resolved
relative to its parent base, following RFC 3986 URL resolution rules.
Example: Nested base resolution.
ImportMap.build do |map|
# No base - imports as-is
map.import("app", "/app.js")
# Base: "https://cdn.example.com/"
map.with(base: "https://cdn.example.com/") do |cdn|
cdn.import("lib", "lib.js") # => "https://cdn.example.com/lib.js"
# Nested base: "https://cdn.example.com/" + "v2/" = "https://cdn.example.com/v2/"
cdn.with(base: "v2/") do |v2|
v2.import("new-lib", "lib.js") # => "https://cdn.example.com/v2/lib.js"
end
end
end
Signature
Definitions
def import(specifier, value, integrity: nil)
Add an import mapping with the current base URI.
If a base is set, the value is resolved relative to that base following RFC 3986. Absolute URLs (scheme://...) are preserved as-is when used as values.
Example: With base URL.
builder = Builder.new(map, base: "https://cdn.com/")
builder.import("lib", "lib.js") # Resolves to: "https://cdn.com/lib.js"
builder.import("ext", "https://other.com/ext.js") # Keeps: "https://other.com/ext.js"
Signature
-
parameter
specifierString The module specifier (e.g., "react", "@myapp/utils").
-
parameter
valueString The URL or path to resolve to.
-
parameter
integrityString, nil Optional subresource integrity hash.
-
returns
Builder Self for method chaining.
Implementation
def import(specifier, value, integrity: nil)
resolved_value = if @base
value_url = Protocol::URL[value]
# Combine base with value
(@base + value_url).to_s
else
value
end
@import_map.import(specifier, resolved_value, integrity: integrity)
self
end
def with(base:, &block)
Create a nested scope with a different base URI.
The new base is resolved relative to the current base. This allows for hierarchical organization of imports from different sources.
Example: Nested CDN paths.
builder.with(base: "https://cdn.com/") do |cdn|
cdn.with(base: "libs/v2/") do |v2|
# Base is now: "https://cdn.com/libs/v2/"
v2.import("util", "util.js") # => "https://cdn.com/libs/v2/util.js"
end
end
Signature
-
parameter
baseString The new base URI, resolved relative to current base.
-
returns
Builder The builder instance.
Implementation
def with(base:, &block)
# Resolve the new base relative to the current base
resolved_base = if @base
@base + Protocol::URL[base]
else
base
end
self.class.build(@import_map, base: resolved_base, &block)
end
def scope(scope_prefix, imports)
Add a scope mapping.
Scopes allow different import resolutions for different parts of your application.
Example: Scope-specific imports.
builder.scope("/admin/", {"utils" => "/admin/utils.js"})
Signature
-
parameter
scope_prefixString The scope prefix (e.g., "/pages/").
-
parameter
importsHash Import mappings specific to this scope.
-
returns
Builder Self for method chaining.
Implementation
def scope(scope_prefix, imports)
@import_map.scope(scope_prefix, imports)
self
end