diff --git a/src/javascript/module.ts b/src/javascript/module.ts index 7ba45f766..46daa8f47 100644 --- a/src/javascript/module.ts +++ b/src/javascript/module.ts @@ -6,10 +6,11 @@ import {extname, join} from "node:path/posix"; import type {Program} from "acorn"; import type {TransformOptions} from "esbuild"; import {transform, transformSync} from "esbuild"; +import {resolveJsrImport} from "../jsr.js"; import {resolveNodeImport} from "../node.js"; import {resolveNpmImport} from "../npm.js"; import {resolvePath} from "../path.js"; -import {builtins} from "../resolvers.js"; +import {builtins, resolveBuiltin} from "../resolvers.js"; import type {RouteResult} from "../route.js"; import {route} from "../route.js"; import {findFiles} from "./files.js"; @@ -94,8 +95,12 @@ export async function getLocalModuleHash(root: string, path: string, getHash?: ( if (info) { const globalPaths = new Set(); for (const i of [...info.globalStaticImports, ...info.globalDynamicImports]) { - if (i.startsWith("npm:") && !builtins.has(i)) { + if (builtins.has(i) || i.startsWith("observablehq:")) { + hash.update(`${resolveBuiltin(i)}?version=${process.env.npm_package_version}`); // change hash when Framework changes + } else if (i.startsWith("npm:")) { globalPaths.add(await resolveNpmImport(root, i.slice("npm:".length))); + } else if (i.startsWith("jsr:")) { + globalPaths.add(await resolveJsrImport(root, i.slice("jsr:".length))); } else if (!/^\w+:/.test(i)) { globalPaths.add(await resolveNodeImport(root, i)); } diff --git a/src/resolvers.ts b/src/resolvers.ts index a531f411e..8343c4552 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -477,10 +477,8 @@ export function getModuleResolver( return async (specifier) => { return isPathImport(specifier) ? relativePath(servePath, resolveImportPath(root, resolvePath(path, specifier), getHash)) - : builtins.has(specifier) - ? relativePath(servePath, builtins.get(specifier)!) - : specifier.startsWith("observablehq:") - ? relativePath(servePath, `/_observablehq/${specifier.slice("observablehq:".length)}${extname(specifier) ? "" : ".js"}`) // prettier-ignore + : builtins.has(specifier) || specifier.startsWith("observablehq:") + ? relativePath(servePath, resolveBuiltin(specifier)) : specifier.startsWith("npm:") ? relativePath(servePath, await resolveNpmImport(root, specifier.slice("npm:".length))) : specifier.startsWith("jsr:") @@ -491,6 +489,12 @@ export function getModuleResolver( }; } +export function resolveBuiltin(specifier: string): string { + if (builtins.has(specifier)) return builtins.get(specifier)!; + if (!specifier.startsWith("observablehq:")) throw new Error(`not built-in: ${specifier}`); + return `/_observablehq/${specifier.slice("observablehq:".length)}${extname(specifier) ? "" : ".js"}`; +} + export function resolveStylesheetPath(root: string, path: string): string { return `/${join("_import", path)}?sha=${getFileHash(root, path)}`; } diff --git a/test/input/build/npm/index.js b/test/input/build/npm/index.js new file mode 100644 index 000000000..35785ba46 --- /dev/null +++ b/test/input/build/npm/index.js @@ -0,0 +1 @@ +import "npm:@observablehq/inputs"; diff --git a/test/input/build/npm/index.md b/test/input/build/npm/index.md new file mode 100644 index 000000000..5171a891a --- /dev/null +++ b/test/input/build/npm/index.md @@ -0,0 +1,3 @@ +```js +import "./index.js"; +``` diff --git a/test/mocks/jsdelivr.ts b/test/mocks/jsdelivr.ts index bc5c36b75..38b7c81c3 100644 --- a/test/mocks/jsdelivr.ts +++ b/test/mocks/jsdelivr.ts @@ -15,6 +15,7 @@ const packages: [name: string, {version: string; dependencies?: Record - + +
+ +
+
+
+ +