136 lines
4.0 KiB
JavaScript
136 lines
4.0 KiB
JavaScript
import * as ESBuild from "https://deno.land/x/esbuild@v0.25.0/wasm.js";
|
|
await ESBuild.initialize({ worker: false });
|
|
|
|
/** @typedef {{imports?:Record<string, string>, scopes?:Record<string, Record<string, string>>}} ImportMap */
|
|
/** @typedef {{fileSystem:string, esBuild:ESBuild.BuildOptions, importMap:ImportMap}} BuildOptions */
|
|
|
|
/**
|
|
* Resolves a module specifier against an import map
|
|
* @param {string} specifier - The module specifier to resolve (bare specifier or absolute URL)
|
|
* @param {ImportMap} importMap - The import map object containing imports and scopes
|
|
* @param {string} baseURL - The base URL for context (especially for scopes)
|
|
* @returns {string} The resolved URL
|
|
*/
|
|
function resolveImportMap(specifier, importMap, baseURL) {
|
|
|
|
// Check for prefix matches in the main imports
|
|
const result = checkPrefixMatch(specifier, importMap.imports);
|
|
if (result) {
|
|
return result
|
|
}
|
|
|
|
// First check scopes that match the baseURL (scope applies based on baseURL, not specifier)
|
|
if (importMap.scopes) {
|
|
const scopeKeys = Object.keys(importMap.scopes).sort((a, b) => b.length - a.length);
|
|
|
|
for (const scopeKey of scopeKeys) {
|
|
// Convert scope key to absolute URL and check if baseURL starts with it
|
|
const scopeURL = new URL(scopeKey, baseURL).href;
|
|
|
|
if (baseURL.startsWith(scopeURL)) {
|
|
const scopeImports = importMap.scopes[scopeKey];
|
|
|
|
// Check for prefix match in the scope
|
|
const result = checkPrefixMatch(specifier, scopeImports);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to check for prefix matches
|
|
* @param {string} specifier - The specifier to check
|
|
* @param {Object} mappings - Object with prefix mappings
|
|
* @returns {string|null} The resolved path or null if no match
|
|
*/
|
|
function checkPrefixMatch(specifier, mappings) {
|
|
|
|
const check = mappings[specifier];
|
|
if(check){ return check; }
|
|
|
|
const prefixes = Object.keys(mappings)
|
|
.filter(key => key.endsWith('/') && specifier.startsWith(key))
|
|
.sort((a, b) => b.length - a.length);
|
|
|
|
for (const prefix of prefixes) {
|
|
const remainder = specifier.slice(prefix.length);
|
|
return mappings[prefix] + remainder;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} fullPathDir
|
|
* @param {ImportMap} importMap
|
|
* @returns {ESBuild.Plugin}
|
|
*/
|
|
export function resolvePlugin(fullPathDir, importMap)
|
|
{
|
|
return {
|
|
name: "resolve-plugin",
|
|
setup(build) {
|
|
|
|
build.onResolve( {/* `/`, `./`, and `../` */ filter:/^(\/|\.\/|\.\.\/).*/}, args=>
|
|
{
|
|
const resolveRoot = args.importer||fullPathDir;
|
|
const out = { path:new URL(args.path, resolveRoot).href, namespace:"FULLPATH" };
|
|
return out;
|
|
} );
|
|
|
|
build.onResolve({filter:/.*/}, args=>
|
|
{
|
|
const resolveRoot = args.importer||fullPathDir;
|
|
const check = resolveImportMap(args.path, importMap, resolveRoot);
|
|
if(check)
|
|
{
|
|
console.log("import remap", args.path, "=>", check);
|
|
const out = { path:new URL(check, resolveRoot).href, namespace:"FULLPATH" };
|
|
return out;
|
|
}
|
|
|
|
})
|
|
|
|
build.onLoad(
|
|
{/* `file://`, `http://`, and `https://` */ filter:/^(file:\/\/|http:\/\/|https:\/\/).*/},
|
|
async(args)=>
|
|
{
|
|
const contents = await fetch(args.path).then(r=>r.text());
|
|
const out = { contents, loader: `tsx` };
|
|
return out;
|
|
} );
|
|
},
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Perform a bundle
|
|
* @param {Partial<BuildOptions>} options
|
|
* @returns {Promise<ESBuild.BuildResult<ESBuild.BuildOptions>>} build result
|
|
*/
|
|
export default async function Build(options)
|
|
{
|
|
const configuration = {
|
|
entryPoints: ["entry"],
|
|
bundle: true,
|
|
minify: true,
|
|
format: "esm",
|
|
jsx: "automatic",
|
|
jsxImportSource: "react",
|
|
...options.esBuild||{},
|
|
plugins: [
|
|
resolvePlugin(options.fileSystem||import.meta.resolve("./"), options.importMap||{}),
|
|
...options.esBuild.plugins||[]
|
|
]
|
|
};
|
|
|
|
const result = await ESBuild.build(configuration);
|
|
return result;
|
|
}
|
|
|
|
export { ESBuild } |