Skip to content

Instantly share code, notes, and snippets.

@NuroDev
Last active March 27, 2025 09:57
Show Gist options
  • Save NuroDev/32c20979c92b9ddd82fb091e6c831286 to your computer and use it in GitHub Desktop.
Save NuroDev/32c20979c92b9ddd82fb091e6c831286 to your computer and use it in GitHub Desktop.
πŸ”Œ Bun HTTP import plugin
preload = ['./path/to/plugin.ts']
import type { OnLoadCallback, OnResolveCallback } from 'bun';
const rx_absolute_path = /^\//;
const rx_any = /./;
const rx_bare_import = /^[^\.\/]/; // Matches bare imports like 'source-map-support'
const rx_http = /^https?:\/\//;
const rx_relative_path = /^\.\.?\//;
const loadHttpModule =
(prefix: string): OnLoadCallback =>
async (args) => {
const href = `${prefix}${args.path}`;
try {
const response = await fetch(href);
if (!response.ok)
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
const text = await response.text();
return {
contents: text,
loader: 'js',
};
} catch (error) {
throw new Error(`Failed to load module '${href}': ${error}`);
}
};
const resolveHttpImport: OnResolveCallback = (args) => {
if (!rx_http.test(args.importer)) return;
// Create a URL object from the importer
const importerUrl = new URL(args.importer);
// Handle the path with any query parameters
let resolvedUrl: URL;
try {
resolvedUrl = new URL(args.path, importerUrl);
} catch (e) {
// If direct resolution fails, try a different approach
// This might be a bare import that needs to be resolved through esm.sh or similar
if (rx_bare_import.test(args.path)) {
// For bare imports from esm.sh, we'll pass them back to esm.sh
// Extract the base URL and append the new import
const baseUrl =
importerUrl.origin +
importerUrl.pathname.substring(0, importerUrl.pathname.lastIndexOf('/') + 1);
resolvedUrl = new URL(args.path, baseUrl);
} else {
throw e;
}
}
return {
path: resolvedUrl.pathname + resolvedUrl.search, // Include query parameters
namespace: resolvedUrl.protocol.replace(':', ''), // 'http' or 'https'
};
};
Bun.plugin({
name: 'http_imports',
target: 'bun',
setup(build) {
// Handle relative paths from HTTP modules
build.onResolve({ filter: rx_relative_path }, resolveHttpImport);
// Handle absolute paths from HTTP modules
build.onResolve({ filter: rx_absolute_path }, resolveHttpImport);
// Load HTTP modules
build.onLoad({ filter: rx_any, namespace: 'http' }, loadHttpModule('http:'));
// Load HTTPS modules
build.onLoad({ filter: rx_any, namespace: 'https' }, loadHttpModule('https:'));
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment