Import Maps API
Import Maps provide modern module resolution with bare specifiers and CDN integration in Andromeda, following the Web Import Maps specification.
Overview
Import Maps allow you to control how module specifiers are resolved, enabling:
- Bare specifiers - Use simple names like
@std/path
instead of relative paths - CDN integration - Map specifiers to remote URLs for dependencies
- Version management - Control which versions of libraries are loaded
- Local development - Map to local files during development
Configuration
Import Maps can be configured in several ways:
1. In Andromeda Configuration File
Add import maps directly to your andromeda.json
, andromeda.toml
, or
andromeda.yml
:
{
"imports": {
"@std/path": "./modules/path.ts",
"lodash": "https://cdn.skypack.dev/lodash@4.17.21",
"react": "https://esm.sh/react@18.2.0"
},
"scopes": {
"./vendor/": {
"lodash": "./vendor/lodash.js"
}
},
"integrity": {
"https://cdn.skypack.dev/lodash@4.17.21": "sha384-..."
}
}
2. Separate Import Map Files
Reference external import map files:
{
"import_map_files": [
"./importmap.json",
"./vendor/deps.json"
]
}
3. Standalone Import Map File
Create a dedicated importmap.json
:
{
"imports": {
"@std/": "https://deno.land/std@0.201.0/",
"preact": "https://esm.sh/preact@10.17.1",
"preact/": "https://esm.sh/preact@10.17.1/"
},
"scopes": {
"https://esm.sh/": {
"react": "https://esm.sh/preact@10.17.1/compat"
}
}
}
Import Map Structure
imports
Direct module specifier mappings for global resolution:
{
"imports": {
"bare-specifier": "./local/file.js",
"package": "https://cdn.example.com/package@1.0.0/index.js",
"utils/": "./src/utils/"
}
}
scopes
Scope-specific mappings that apply only within certain paths:
{
"scopes": {
"./vendor/": {
"lodash": "./vendor/lodash-local.js"
},
"https://cdn.example.com/": {
"react": "https://cdn.example.com/react@17.0.0"
}
}
}
integrity
Subresource integrity metadata for security:
{
"integrity": {
"https://cdn.example.com/package.js": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
}
}
Usage Examples
Basic Bare Specifier Resolution
// Import map configuration
{
"imports": {
"@std/path": "./modules/path.ts"
}
}
// In your code
import { join, dirname, basename } from "@std/path";
console.log(join("a", "b", "c")); // "a/b/c"
console.log(dirname("/path/to/file.ts")); // "/path/to"
console.log(basename("/path/to/file.ts")); // "file.ts"
CDN Dependencies
// Import map configuration
{
"imports": {
"lodash": "https://cdn.skypack.dev/lodash@4.17.21",
"date-fns": "https://cdn.skypack.dev/date-fns@2.29.3"
}
}
// In your code
import _ from "lodash";
import { format } from "date-fns";
console.log(_.chunk([1, 2, 3, 4, 5], 2)); // [[1, 2], [3, 4], [5]]
console.log(format(new Date(), "yyyy-MM-dd")); // "2024-01-01"
Directory Mapping
// Import map configuration
{
"imports": {
"utils/": "./src/utilities/",
"@components/": "./src/components/"
}
}
// In your code
import { helper } from "utils/helpers.ts";
import { Button } from "@components/Button.tsx";
Scoped Mappings
// Import map configuration
{
"imports": {
"react": "https://esm.sh/react@18.2.0"
},
"scopes": {
"./legacy/": {
"react": "https://esm.sh/react@16.14.0"
}
}
}
// In ./src/modern.ts
import React from "react"; // Uses React 18.2.0
// In ./legacy/old-component.ts
import React from "react"; // Uses React 16.14.0
Resolution Algorithm
Andromeda follows the standard Import Maps resolution algorithm:
- Check for relative/absolute specifiers - Skip mapping for
./
,../
,/
, or URLs with protocols - Apply scope-specific mappings - If the importing module is within a scope, check scope mappings first
- Apply global mappings - Check the global
imports
for exact matches - Try prefix matching - For directory mappings ending with
/
- Fall back to standard resolution - Use normal module resolution if no mapping found
API Reference
ImportMap Interface
interface ImportMap {
imports?: Record<string, string>;
scopes?: Record<string, Record<string, string>>;
integrity?: Record<string, string>;
}
Methods
ImportMap.from_file(path)
Load an import map from a JSON file:
// In Rust/internal API
let import_map = ImportMap::from_file("./importmap.json")?;
ImportMap.resolve_specifier(specifier, base_url?)
Resolve a bare specifier using the import map:
// Returns the mapped specifier or None if not found
let resolved = import_map.resolve_specifier("@std/path", Some("./src/"));
ImportMap.merge(other)
Merge another import map into this one:
// Combines imports, scopes, and integrity from both maps
import_map.merge(other_map);
Runtime Integration
Import Maps are automatically integrated into Andromeda's module system:
// Create a runtime with import map support
let import_map = ImportMap::from_file("./importmap.json")?;
let hooks = RuntimeHostHooks::with_import_map(host_data, base_path, import_map);
The import map resolution happens transparently during module loading, so your TypeScript/JavaScript code can use bare specifiers without any special syntax.
Best Practices
1. Use Consistent Patterns
{
"imports": {
"@std/": "https://deno.land/std@0.201.0/",
"@app/": "./src/",
"npm:": "https://esm.sh/"
}
}
2. Version Pinning
{
"imports": {
"react": "https://esm.sh/react@18.2.0",
"react-dom": "https://esm.sh/react-dom@18.2.0"
}
}
3. Development vs Production
{
"imports": {
"debug": "./src/debug-dev.ts"
},
"scopes": {
"./dist/": {
"debug": "./src/debug-prod.ts"
}
}
}
4. Security with Integrity
{
"imports": {
"lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"
},
"integrity": {
"https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js": "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
}
}
Common Patterns
Standard Library Mapping
{
"imports": {
"@std/assert": "https://deno.land/std@0.201.0/assert/mod.ts",
"@std/path": "https://deno.land/std@0.201.0/path/mod.ts",
"@std/fs": "https://deno.land/std@0.201.0/fs/mod.ts"
}
}
Framework Setup
{
"imports": {
"react": "https://esm.sh/react@18.2.0",
"react-dom": "https://esm.sh/react-dom@18.2.0",
"@emotion/react": "https://esm.sh/@emotion/react@11.11.1",
"@emotion/styled": "https://esm.sh/@emotion/styled@11.11.0"
}
}
Local Development
{
"imports": {
"@app/components": "./src/components/index.ts",
"@app/utils": "./src/utils/index.ts",
"@app/types": "./src/types/index.ts"
}
}
Error Handling
Import Maps provide clear error messages for common issues:
- Module not found: When a mapped specifier points to a non-existent file
- Invalid JSON: When import map files contain syntax errors
- Resolution errors: When circular dependencies or invalid mappings are detected
// Error examples
import { nonExistent } from "@std/path"; // TypeError: Module not found
import cycles from "@app/cycles"; // Error: Circular import detected
Compatibility
Andromeda's Import Maps implementation follows the WHATWG Import Maps specification, ensuring compatibility with:
- Web browsers supporting Import Maps
- Deno runtime import maps
- Node.js with appropriate tooling
- Bundlers that support Import Maps
This makes your code portable across different JavaScript runtimes and build tools.