diff --git a/bin/resolve-dependencies b/bin/resolve-dependencies new file mode 100755 index 00000000..130d0716 --- /dev/null +++ b/bin/resolve-dependencies @@ -0,0 +1,73 @@ +#!/usr/bin/env node + +const fetch = require("node-fetch"); + +(async () => { + console.log(`import dependency from "./dependency.js";`); + { + const package = await resolve("d3"); + console.log(`export const d3 = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("d3-dsv"); + console.log(`export const d3Dsv = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("@observablehq/inputs"); + console.log(`export const inputs = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("@observablehq/plot"); + console.log(`export const plot = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("@observablehq/graphviz"); + console.log(`export const graphviz = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("@observablehq/highlight.js"); + console.log(`export const highlight = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("@observablehq/katex"); + console.log(`export const katex = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("lodash"); + console.log(`export const lodash = dependency("${package.name}", "${package.version}", "${package.export.replace(/\.js$/, ".min.js")}");`); + } + { + const package = await resolve("htl"); + console.log(`export const htl = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("marked@0.3.12"); + console.log(`export const marked = dependency("${package.name}", "${package.version}", "marked.min.js");`); + } + { + const package = await resolve("sql.js"); + console.log(`export const sql = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("vega"); + console.log(`export const vega = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("vega-lite"); + console.log(`export const vegalite = dependency("${package.name}", "${package.version}", "${package.export}");`); + } + { + const package = await resolve("vega-lite-api"); + console.log(`export const vegaliteApi = dependency("${package.name}", "${package.version}", "${package.export}");`); + } +})(); + +async function resolve(specifier) { + const response = await fetch(`https://cdn.jsdelivr.net/npm/${specifier}/package.json`); + const package = await response.json(); + return { + name: package.name, + version: package.version, + export: (package.unpkg || package.jsdelivr || package.browser || package.main).replace(/^\.\//, "") + }; +} diff --git a/package.json b/package.json index cdcd551b..0fc55e5f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "devDependencies": { "eslint": "^7.18.0", "husky": "^4.3.8", + "node-fetch": "^2.6.1", "rollup": "^2.37.1", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-terser": "^7.0.2", diff --git a/src/dependencies.js b/src/dependencies.js new file mode 100644 index 00000000..7ee82291 --- /dev/null +++ b/src/dependencies.js @@ -0,0 +1,15 @@ +import dependency from "./dependency.js"; +export const d3 = dependency("d3", "6.7.0", "dist/d3.min.js"); +export const d3Dsv = dependency("d3-dsv", "2.0.0", "dist/d3-dsv.min.js"); +export const inputs = dependency("@observablehq/inputs", "0.8.0", "dist/inputs.umd.min.js"); +export const plot = dependency("@observablehq/plot", "0.1.0", "dist/plot.umd.min.js"); +export const graphviz = dependency("@observablehq/graphviz", "0.2.1", "dist/graphviz.min.js"); +export const highlight = dependency("@observablehq/highlight.js", "2.0.0", "highlight.min.js"); +export const katex = dependency("@observablehq/katex", "0.11.1", "dist/katex.min.js"); +export const lodash = dependency("lodash", "4.17.21", "lodash.min.js"); +export const htl = dependency("htl", "0.2.5", "dist/htl.min.js"); +export const marked = dependency("marked", "0.3.12", "marked.min.js"); +export const sql = dependency("sql.js", "1.5.0", "dist/sql-wasm.js"); +export const vega = dependency("vega", "5.20.2", "build/vega.min.js"); +export const vegalite = dependency("vega-lite", "5.1.0", "build/vega-lite.min.js"); +export const vegaliteApi = dependency("vega-lite-api", "5.0.0", "build/vega-lite-api.min.js"); diff --git a/src/dependency.js b/src/dependency.js new file mode 100644 index 00000000..3c93e56f --- /dev/null +++ b/src/dependency.js @@ -0,0 +1,7 @@ +export default function dependency(name, version, main) { + return { + resolve(path = main) { + return `https://cdn.jsdelivr.net/npm/${name}@${version}/${path}`; + } + }; +} diff --git a/src/fileAttachment.js b/src/fileAttachment.js index 38931b82..70ace731 100644 --- a/src/fileAttachment.js +++ b/src/fileAttachment.js @@ -1,4 +1,5 @@ import {require as requireDefault} from "d3-require"; +import {d3Dsv} from "./dependencies.js"; import {SQLiteDatabaseClient} from "./sqlite.js"; import jszip from "./zip.js"; @@ -9,7 +10,7 @@ async function remote_fetch(file) { } async function dsv(file, delimiter, {array = false, typed = false} = {}) { - const [text, d3] = await Promise.all([file.text(), requireDefault("d3-dsv@2.0.0/dist/d3-dsv.min.js")]); + const [text, d3] = await Promise.all([file.text(), requireDefault(d3Dsv.resolve())]); return (delimiter === "\t" ? (array ? d3.tsvParseRows : d3.tsvParse) : (array ? d3.csvParseRows : d3.csvParse))(text, typed && d3.autoType); diff --git a/src/library.js b/src/library.js index 2f873d4a..d872126b 100644 --- a/src/library.js +++ b/src/library.js @@ -15,20 +15,21 @@ import svg from "./svg.js"; import tex from "./tex.js"; import vegalite from "./vegalite.js"; import width from "./width.js"; +import {d3, graphviz, htl, inputs, lodash, plot} from "./dependencies.js"; export default Object.assign(function Library(resolver) { const require = requirer(resolver); Object.defineProperties(this, properties({ FileAttachment: () => NoFileAttachments, - Inputs: () => require("@observablehq/inputs@0.8.0/dist/inputs.umd.min.js"), + Inputs: () => require(inputs.resolve()), Mutable: () => Mutable, - Plot: () => require("@observablehq/plot@0.1.0/dist/plot.umd.min.js"), + Plot: () => require(plot.resolve()), SQLite: () => SQLite(require), SQLiteDatabaseClient: () => SQLiteDatabaseClient, - _: () => require("lodash@4.17.21/lodash.min.js"), - d3: () => require("d3@6.7.0/dist/d3.min.js"), - dot: () => require("@observablehq/graphviz@0.2.1/dist/graphviz.min.js"), - htl: () => require("htl@0.2.5/dist/htl.min.js"), + _: () => require(lodash.resolve()), + d3: () => require(d3.resolve()), + dot: () => require(graphviz.resolve()), + htl: () => require(htl.resolve()), html: () => html, md: () => md(require), now, diff --git a/src/md.js b/src/md.js index a09c0f99..5bd37ae0 100644 --- a/src/md.js +++ b/src/md.js @@ -1,16 +1,15 @@ +import {highlight, marked} from "./dependencies.js"; import template from "./template.js"; -const HL_ROOT = "https://cdn.jsdelivr.net/npm/@observablehq/highlight.js@2.0.0/"; - export default function(require) { - return require("marked@0.3.12/marked.min.js").then(function(marked) { + return require(marked.resolve()).then(function(marked) { return template( function(string) { var root = document.createElement("div"); root.innerHTML = marked(string, {langPrefix: ""}).trim(); var code = root.querySelectorAll("pre code[class]"); if (code.length > 0) { - require(HL_ROOT + "highlight.min.js").then(function(hl) { + require(highlight.resolve()).then(function(hl) { code.forEach(function(block) { function done() { hl.highlightBlock(block); @@ -19,12 +18,10 @@ export default function(require) { if (hl.getLanguage(block.className)) { done(); } else { - require(HL_ROOT + "async-languages/index.js") + require(highlight.resolve("async-languages/index.js")) .then(index => { if (index.has(block.className)) { - return require(HL_ROOT + - "async-languages/" + - index.get(block.className)).then(language => { + return require(highlight.resolve("async-languages/" + index.get(block.className))).then(language => { hl.registerLanguage(block.className, language); }); } diff --git a/src/sqlite.js b/src/sqlite.js index 12b745c6..629d0c0f 100644 --- a/src/sqlite.js +++ b/src/sqlite.js @@ -1,8 +1,9 @@ import {require as requireDefault} from "d3-require"; +import {sql} from "./dependencies"; export default async function sqlite(require) { - const sql = await require("sql.js@1.5.0/dist/sql-wasm.js"); - return sql({locateFile: file => `https://cdn.jsdelivr.net/npm/sql.js@1.5.0/dist/${file}`}); + const init = await require(sql.resolve()); + return init({locateFile: file => sql.resolve(`dist/${file}`)}); } export class SQLiteDatabaseClient { diff --git a/src/tex.js b/src/tex.js index c07cea43..097deca1 100644 --- a/src/tex.js +++ b/src/tex.js @@ -1,3 +1,5 @@ +import {katex} from "./dependencies.js"; + var raw = String.raw; function style(href) { @@ -13,8 +15,8 @@ function style(href) { export default function tex(require) { return Promise.all([ - require("@observablehq/katex@0.11.1/dist/katex.min.js"), - require.resolve("@observablehq/katex@0.11.1/dist/katex.min.css").then(style) + require(katex.resolve()), + style(katex.resolve("dist/katex.min.css")) ]).then(function(values) { var katex = values[0], tex = renderer(); diff --git a/src/vegalite.js b/src/vegalite.js index 652a77f1..9799088b 100644 --- a/src/vegalite.js +++ b/src/vegalite.js @@ -1,8 +1,6 @@ +import {vega, vegalite, vegaliteApi} from "./dependencies.js"; + export default async function vl(require) { - const [vega, vegalite, api] = await Promise.all([ - "vega@5.20.2/build/vega.min.js", - "vega-lite@5.1.0/build/vega-lite.min.js", - "vega-lite-api@5.0.0/build/vega-lite-api.min.js" - ].map(module => require(module))); - return api.register(vega, vegalite); + const [v, vl, api] = await Promise.all([vega, vegalite, vegaliteApi].map(d => require(d.resolve()))); + return api.register(v, vl); } diff --git a/yarn.lock b/yarn.lock index 19c97b29..3478074a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1805,6 +1805,11 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"