observablehq / framework

A static site generator for data apps, dashboards, reports, and more. Observable Framework combines JavaScript on the front-end for interactive graphics with any language on the back-end for data analysis.
https://observablehq.com/framework/
ISC License
2.34k stars 102 forks source link

JSR imports #956

Open mbostock opened 6 months ago

mbostock commented 6 months ago

E.g.,

import {printProgress} from "jsr:@luca/flag";

But it’s not clear to me that the JSR API supports conversion to vanilla ES modules? Like, I get that I can fetch https://jsr.io/@luca/flag/1.0.0/main.ts, but how would I get the default entry into a module? And how would I bundle and convert TypeScript to vanilla JavaScript? 🤔

Ref. https://jsr.io/docs/native-imports Ref. https://jsr.io/docs/api Ref. https://jsr.io/docs/native-imports#implementing-native-jsr-imports-in-tools (not yet written)

mbostock commented 6 months ago

Some clues here… It looks like we could use the npm compatibility API to download the tarball, which contains the transpiled ES modules. So https://npm.jsr.io/@jsr/luca__flag tells us which versions are available and what’s the latest

{
  "name": "@jsr/luca__flag",
  "description": "I like flags!",
  "dist-tags": {
    "latest": "1.0.1"
  },
  "versions": {
    "1.0.1": {
      "name": "@jsr/luca__flag",
      "version": "1.0.1",
      "description": "I like flags!",
      "dist": {
        "tarball": "https://npm.jsr.io/~/5/@jsr/luca__flag/1.0.1.tgz",
        "shasum": "121867B05BC5E2DC7B8B0D094D257441B3925A03",
        "integrity": "sha512-H0HxTnwINL5VPb0d9Paa0rlWYKyEmm+/tKRodWcKQxOEDCQ2uSaIQmPacT6LH8r6nERmMt8qHOjIYo7F2Dpg3Q=="
      },
      "dependencies": {}
    },
    "1.0.0": {
      "name": "@jsr/luca__flag",
      "version": "1.0.0",
      "description": "I like flags!",
      "dist": {
        "tarball": "https://npm.jsr.io/~/5/@jsr/luca__flag/1.0.0.tgz",
        "shasum": "AE1F23270B377B1733E3C6626589A51A39998206",
        "integrity": "sha512-o3aiKqepCk3D3XHVoHH81Td6XDPa7VQWQabn566sLTFUxxX+vN+2BVxShji3bVply57l1n6Z07Q6g+4Gh5cNnQ=="
      },
      "dependencies": {}
    }
  },
  "time": {
    "created": "2023-12-14T23:05:13.518Z",
    "modified": "2024-02-08T00:18:46.212Z",
    "1.0.1": "2024-01-26T19:05:08.325Z",
    "1.0.0": "2023-12-15T11:19:06.411Z"
  }
}

and then https://npm.jsr.io/~/5/@jsr/luca__flag/1.0.1.tgz gives us

package
├── main.d.ts
├── main.js
└── package.json

1 directory, 3 files

And then the package.json gives the default export (or at least .):

{
  "name": "@jsr/luca__flag",
  "version": "1.0.1",
  "homepage": "https://jsr.io/@luca/flag",
  "type": "module",
  "dependencies": {},
  "exports": {
    ".": "./main.js"
  }
}

And the main.js is ES modules. Though I imagine we’ll have to rewrite external imports… not sure what those look like yet.

mbostock commented 6 months ago

I imagine we could expand the tarball into docs/.observablehq/cache/_jsr/@jsr/luca__flag@1.0.1 and this would dovetail nicely with our existing self-hosted npm imports.

huw commented 6 months ago

FWIW esm.sh also supports JSR directly, which is what I'm using right now. You can run:

import {printProgress} from "https://esm.sh/jsr/@luca/flag@0.1.0"

ESM.sh does a lot of its own transpiling & import changes etc that you mention you need (and it uses the @jsr NPM namespace under the hood). If the jsDelivr code for npm: is reusable it's probably the fastest way to production for now :)