cli icon indicating copy to clipboard operation
cli copied to clipboard

Edge function with npm dependency behaves erratically on development environments and doesn't work on production

Open MarcusRiemer opened this issue 3 years ago • 0 comments

Bug report

Running deno code that loads JavaScript modules via the deno provided require wrapper doesn't work on the hosted environments but sort of works locally. "Sort of" because it crashes if enabled on boot, but it works fine after hot reload. So this bug report is fundamentally about two things:

  1. The development environment behaves differently on boot (crash) and after hot reload (works fine)
  2. Neither the development environment nor the production environment allow me to work with existing code that relies on npm dependencies

I'm sorry for the lengthy report, it really took me a while to understand that the root of the different behavior is the hot reloading. I assume I'm doing something that's unsupported, but I would really appreciate it if this at least would fail fast and consistently.

To Reproduce

Steps are explained in a example repository: https://github.com/MarcusRiemer/supabase-npm-edge-functions

I basically compile TypeScript project called npm-lib with a single dependency (immer) to JavaScript and load it using the following deno typescript file:

// server/supabase/functions/core-data.ts
import { createRequire } from "https://deno.land/[email protected]/node/module.ts";

const require = createRequire(import.meta.url);
export const core_data = require("./npm-lib");

console.log("Hello from core data", core_data);

I then use this module in a edge function:

// server/supabase/functions/hello-npm/index.ts
import { serve } from "https://deno.land/[email protected]/http/server.ts"

// ### Uncomment after boot ###
//import { core_data } from "../core-data.ts"
//console.log("Hello from Functions, core data is ", core_data.CORE_DATA)

serve(async (req) => {
  const { name } = await req.json()
  let data = name;

  // ### Uncomment after boot ###
  //data = core_data.update(name);

  return new Response(
    JSON.stringify(data),
    { headers: { "Content-Type": "application/json" } },
  )
})

Expected behavior

The code in the library (and the immer dependency) are loaded, so that the log output reads as follows:

Hello from core data { CORE_DATA: { foo: [ 1, 2, 3 ] }, update: [Function: update] }
Hello from Functions, core data is  { foo: [ 1, 2, 3 ] }

Additonally requests should be answered with a { foo: $NAME } response depending on the argument given when invoking the function.

Actual behavior

The function fails to boot if the marked lines are executed. The errors read something along the lines of the following:

TS2339 [ERROR]: Property 'loadavg' does not exist on type 'typeof Deno'. 'Deno.loadavg' is an unstable API. Did you forget to run with the '--unstable' flag?
    return Deno.loadavg();
                ~~~~~~~
      at https://deno.land/[email protected]/node/os.ts:171:15

If the lines are commented out after boot, the function works flawlessly though.

On production I get ReferenceError: Cannot access 'NodeTypeError' before initialization at file:///src/main.ts:4730:36. I checked the output of deno bundle and it simply omits the package.json and npm-lib content.

System information

  • OS: Arch Linux
  • Version of supabase: 1.7.0
  • Version of Node.js: v16.16.0

Additional context

My existing TypeScript library is almost free of npm dependencies (save for immer) and must work in a browser context as well. So this was my (failed) attempt to re-use the library in an edge function.

MarcusRiemer avatar Oct 10 '22 12:10 MarcusRiemer