|
55 | 55 | }<link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&display=swap"> |
56 | 56 | <link rel="stylesheet" type="text/css" href="/_observablehq/style.css"> |
57 | 57 | <script type="importmap"> |
58 | | -${JSON.stringify({imports: Object.fromEntries(imports)}, null, 2)} |
| 58 | +${JSON.stringify({imports: Object.fromEntries(Array.from(imports, ([name, [href]]) => [name, href]))}, null, 2)} |
59 | 59 | </script> |
60 | | -${imports.map(([, href]) => `<link rel="modulepreload" href="${href}">`).join("\n")} |
| 60 | +${Array.from(imports.values()) |
| 61 | + .filter(([, preload]) => preload) |
| 62 | + .map(([href]) => `<link rel="modulepreload" href="${href}">`) |
| 63 | + .join("\n")} |
61 | 64 | <script type="module"> |
62 | 65 |
|
63 | 66 | import {${preview ? "open, " : ""}define} from "/_observablehq/client.js"; |
@@ -104,23 +107,30 @@ ${parseResult.html}</main> |
104 | 107 | `; |
105 | 108 | } |
106 | 109 |
|
107 | | -function getImportMap(parseResult: ParseResult): [name: string, href: string][] { |
108 | | - const modules = new Set(["npm:@observablehq/runtime"]); |
109 | | - if (parseResult.cells.some((c) => c.inputs?.includes("d3") || c.inputs?.includes("Plot"))) modules.add("npm:d3"); |
110 | | - if (parseResult.cells.some((c) => c.inputs?.includes("Plot"))) modules.add("npm:@observablehq/plot"); |
111 | | - if (parseResult.cells.some((c) => c.inputs?.includes("htl") || c.inputs?.includes("Inputs"))) modules.add("npm:htl"); |
112 | | - if (parseResult.cells.some((c) => c.inputs?.includes("Inputs"))) modules.add("npm:@observablehq/inputs"); |
113 | | - for (const {name} of parseResult.imports) { |
114 | | - if (name.startsWith("npm:")) { |
115 | | - modules.add(name); |
116 | | - } |
| 110 | +// These are always supplied in the import map so that npm imports work from |
| 111 | +// local ES modules. TODO We’ll need to parse local ES modules and detect their |
| 112 | +// npm imports; and we’ll want to preload those modules, too! |
| 113 | +const baseImportMap: Map<string, [href: string, preload: boolean]> = new Map([ |
| 114 | + ["npm:@observablehq/inputs", ["https://cdn.jsdelivr.net/npm/@observablehq/inputs/+esm", false]], |
| 115 | + ["npm:@observablehq/plot", ["https://cdn.jsdelivr.net/npm/@observablehq/plot/+esm", false]], |
| 116 | + ["npm:@observablehq/runtime", ["/_observablehq/runtime.js", true]], |
| 117 | + ["npm:d3", ["https://cdn.jsdelivr.net/npm/d3/+esm", false]], |
| 118 | + ["npm:htl", ["https://cdn.jsdelivr.net/npm/htl/+esm", false]] |
| 119 | +]); |
| 120 | + |
| 121 | +function getImportMap(parseResult: ParseResult): Map<string, [href: string, preload: boolean]> { |
| 122 | + const map = new Map(baseImportMap); |
| 123 | + const imports = parseResult.imports.map(({name}) => name); |
| 124 | + const inputs = new Set(parseResult.cells.flatMap((cell) => cell.inputs ?? [])); |
| 125 | + if (inputs.has("d3") || inputs.has("Plot")) imports.push("npm:d3"); |
| 126 | + if (inputs.has("Plot")) imports.push("npm:@observablehq/plot"); |
| 127 | + if (inputs.has("htl") || inputs.has("Inputs")) imports.push("npm:htl"); |
| 128 | + if (inputs.has("Inputs")) imports.push("npm:@observablehq/inputs"); |
| 129 | + for (const name of imports) { |
| 130 | + if (map.has(name)) map.set(name, [map.get(name)![0], true]); |
| 131 | + else map.set(name, [`https://cdn.jsdelivr.net/npm/${name.slice(4)}/+esm`, true]); |
117 | 132 | } |
118 | | - return Array.from(modules, (name) => [ |
119 | | - name, |
120 | | - name === "npm:@observablehq/runtime" |
121 | | - ? "/_observablehq/runtime.js" // self-hosted |
122 | | - : `https://cdn.jsdelivr.net/npm/${name.slice(4)}/+esm` |
123 | | - ]); |
| 133 | + return map; |
124 | 134 | } |
125 | 135 |
|
126 | 136 | // TODO Adopt Hypertext Literal? |
|
0 commit comments