Back to blog
Using less popular NPM packages in Supabase edge functions
12 May 2023

5 min read

Using less popular NPM packages in Supabase edge functions

Yogi Seetharaman

Yogi Seetharaman

Supabase edge functions run on Deno which can be a little tricky for those familiar with the typical JS ecosystem. For example, in Deno, instead of running npm install you just import a url like so:

// your-file.ts
import { z } from "https://deno.land/x/zod@v3.21.4/mod.ts";

Most Supabase documentation uses very common packages that you can import from https://deno.land/x which is a hosting service for Deno scripts. Based on the name, and given that you can import familiar packages like lodash and zod, you might assume that all packages are in deno.land/x, the same way you might expect to find every npm package on npmjs.com. This is not the case!

Recently while developing Vonsole we ran into an issue where we couldn't find any host that had the Node.js pusher library. Googling "lodash deno" will quickly link you to the https://deno.land/x/lodash@4.17.19 page while searching for "pusher deno" results in nothing. What are we to do?

Fortunately, you can look elsewhere for Deno packages. One of the best hosts (and depending on where you're coming from, relatively unadvertised) we've found is esm.sh. One of the coolest features of esm.sh is that you can import a package directly from a Github repo like so

import tslib from "https://esm.sh/gh/microsoft/tslib";

This theoretically meant that if we can find Pusher on Github, we can import it into Deno.

import Pusher from "https://esm.sh/gh/pusher/pusher-http-node?target=deno&no-check";

This works! The pusher library worked exactly as we expected, just like it would in Node. You might notice that you need a couple extra query params if you want this to work. You need to add target=deno&no-check to the end of your URL or you won't be able to serve or deploy your Supabase function. Without this, you'll run into this error:

error: Uncaught (in promise) Error: Relative import path "http" not prefixed with / or ./ or ../ and not in import map from "https://esm.sh/v120/@types/node@18.16.0/http.d.ts"
      const ret = new Error(getStringFromWasm0(arg0, arg1));
                  ^
    at __wbg_new_8d2af00bc1e329ee (https://deno.land/x/eszip@v0.30.0/eszip_wasm.generated.js:312:19)
    at <anonymous> (https://deno.land/x/eszip@v0.30.0/eszip_wasm_bg.wasm:1:79439)
    at <anonymous> (https://deno.land/x/eszip@v0.30.0/eszip_wasm_bg.wasm:1:1388039)
    at <anonymous> (https://deno.land/x/eszip@v0.30.0/eszip_wasm_bg.wasm:1:1862894)
    at __wbg_adapter_18 (https://deno.land/x/eszip@v0.30.0/eszip_wasm.generated.js:146:6)
    at real (https://deno.land/x/eszip@v0.30.0/eszip_wasm.generated.js:130:14)

According to the esm docs, by default, esm.sh should check the User-Agent header to get the build target automatically. Unfortunately something about the way Supabase bundles the edge functions prevents this from happening automatically and you'll need to add these params.

The caveat is I don't really understand how this works. Does esm.sh require the package to be built already? Does there need to be a Github release or a dist/ folder in the repo? Importing from the pusher github package worked pretty instantly so I'm not really sure. If you have the answer, please let us know!

Neorepo is a production-ready SaaS boilerplate

Skip the tedious parts of building auth, org management, payments, and emails

See the demo