Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

supabase functions serve: Import maps fail to resolve inside of 'functions' directory #1338

Closed
ChuckJonas opened this issue Jul 27, 2023 · 13 comments · Fixed by #2187 or #2402
Closed
Assignees

Comments

@ChuckJonas
Copy link

ChuckJonas commented Jul 27, 2023

Issue

It seems like import maps are failing in multiple ways:

  1. When the mapped directory is INSIDE the function folder, the import map does not properly resolve in the docker instance
  2. When the import is outside of the supabase folder, it seems like a private module is created? But this causes the Duplicate mount point issue
  3. Behavior of import maps seems to be different if --import-maps flag vs using the defaults

Note: I haven't had a chance to test any of this with deploy, but I assume these issues will carry over in one way or another...

Reproduction

(this was previously posted to #1093, but decided it deserves a new, open issue)

This is failing in my setup:

Project Structure

root
   - common
   - react-app
   - supabase
   - functions
      - _core
         - supabaseClient.ts
      - chat
         - index.ts
      - import_map.json
   - package.json

supabase/functions/chat/index.ts

import { corsHeaders } from "core/supabaseClient.ts";
import { fnSharedWithReact } from "common/template";

In "supabase_edge_runtime" Docker container

home/deno

home/deno
  - fallback_import_map.json
  - main
  - functions
     - _core
        - supabaseClient.ts
     - chat
        - index.ts
     - import_map.json
  - modules
      - 4b0ed4fd36b0064d333d0ebb53b49ba5d84e9b130af0ab0c15f9924364d718c6

fallback_import_map.json

{
    "imports": {
        "@supabase/supabase-js": "https://esm.sh/@supabase/supabase-js@2",
        "common/": "/home/deno/modules/4b0ed4fd36b0064d333d0ebb53b49ba5d84e9b130af0ab0c15f9924364d718c6/",
        "core/": "./_core/"
    },
    "scopes": {}
}

The deno LSP (vscode) is happy with this configuration, but when I try to invoke the functions/chat function, I get this error:

Failed to load module: "file:///home/deno/_core/supabaseClient.ts" - No such file or directory (os error 2)

It seems like thefallback_import_map.json that gets setup in the "supabase_edge_runtime" container is referencing the wrong path:

"core/": "./_core/" should be "core/": "./functions/_core/"

Also, when I try to run it with the --import-map flag, I get the Duplicate mount point error as above:

supabase functions serve --env-file .env --no-verify-jwt --import-map supabase/functions/import_map.json

-> Error response from daemon: Duplicate mount point: /home/deno/modules/4b0ed4fd36b0064d333d0ebb53b49ba5d84e9b130af0ab0c15f9924364d718c6

Update

If I update my import map to:

    "core/": "./functions/_core/",

Then it works (as suspected), but this breaks the imports in my local deno LSP... Also, it goes against what was said in #1093:

paths in import_map are relative to supabase/functions directory

So... I don't really understand what's going on.

My workaround was to move my import map OUTSIDE of functions (./supabase/import-map.json), and now vscode and supabase serve are at least consistent. However, when I do this, it doesn't even attempt to generate the module for common anymore.

@idudinov
Copy link

idudinov commented Aug 4, 2023

Hi! Currently I abandoned using import maps (aka path aliases) within functions folder and moved all my client-server re-usable code outside supabase folder, and it works perfectly both in local and deployed versions.

However, since using relative paths is evil, I'm also looking for a solution for this issue to be able to use backend-only aliases for functions.

I suppose it could be resolved by keeping the same folders structure as in the project folder, I mean avoid moving import_map.json from supabase/functions to supabase level and mount /supabase/functions (instead of just functions) without any extra stuff like migrations etc., so in such case relative mappings in import_map.json shouldn't break I think. (or maybe re-map them by adding ./functions prefix?)

@rasphlat
Copy link

rasphlat commented Aug 9, 2023

In my case this issue occurs only on Windows, on MacOS is working fine

@laktek laktek self-assigned this Aug 10, 2023
@Matx00
Copy link

Matx00 commented Aug 18, 2023

@idudinov Hi, could you provide an example of how you structured the file? I tried what you said but still getting errors.
Thank you!

@idudinov
Copy link

idudinov commented Sep 5, 2023

@Matx00 no problem, here's my setup.

// supabase/functions/import_map.json

{
    "imports": {
        // here listed all packages that are used in "common"
        "yup": "https://esm.sh/[email protected]",

        // the "common" folder is in the root dir
        "common/": "../../src/common/"
    }
}

Now I can reference my models from common in Deno files:

import { UserProfile } from 'common/types/models/index.ts';

However I still use relative paths for my shared code within functions:

import '../_shared/utils/bigint.ts';

Hopefully this helps, but don't hesitate to ask any questions if any.

@ChuckJonas ChuckJonas changed the title supabase functions serve: Import maps failing to resolve proper directory & volume issue with modules supabase functions serve: Import maps fail to resolve inside of 'functions' directory Sep 25, 2023
@ChuckJonas
Copy link
Author

@laktek based on the comments here and additional research in my own project, I think the scope of this issue can be defined using the following reproduction steps.

Reproduction Steps

  1. Create a new supabase project
  2. create a new file supabase/functions/_shared/foo.ts with the following:
export const foo = 'bar'
  1. create a file supabase/functions/import_map.json with the following:
    "shared/": "./_shared/"
  1. create a new supabase function with the following:
import { serve } from "https://deno.land/[email protected]/http/server.ts"
import { foo } from 'shared/foo.ts'; 

console.log("Hello from Functions!")

serve(async (req) => {
  console.log(foo);
  const { name } = await req.json()
  const data = {
    message: `Hello ${name}!`,
  }

  return new Response(
    JSON.stringify(data),
    { headers: { "Content-Type": "application/json" } },
  )
})
  1. run the function:serve locally and curl the created function. You should see an error similar to this one:
Failed to load module: "file:///home/deno/_shared/foo.ts" - No such file or directory (os error 2)
An error has occured
InvalidWorkerCreation: worker boot error
    at async Function.create (ext:sb_user_workers/user_workers.js:124:15)
    at async Server.<anonymous> (file:///home/deno/main/index.ts:110:20)
    at async Server.#respond (https://deno.land/[email protected]/http/server.ts:220:18) {
  name: "InvalidWorkerCreation"
}

Expected Result

The module should be resolving to file:///home/deno/functions/_shared/foo.ts

Workaround

Move supabase/functions/_shared to supabase/_shared and update import_map.json.

Other Notes

The fix might be to update the bindImportMap function to detect imports inside of the functions directory (./) and properly rewrite these paths to ./functions.

@evelant
Copy link

evelant commented Dec 4, 2023

@sweatybridge have you had a chance to look at this? It seems to boil down to the cli mounting the import map in the container at /home/deno when it should be in /home/deno/functions so that relative paths remain correct since the default placement of import_map.json is supabase/functions in a project.

@inorganik
Copy link

inorganik commented Feb 3, 2024

I was struggling with trying to get import_map.json to work, only to discover that since v1.30, Deno wants you to put import aliases in the imports object of deno.json.

Since version 1.30, the deno.json configuration file acts as an import map for resolving bare specifiers.

See https://docs.deno.com/runtime/manual/getting_started/configuration_file#imports-and-scopes

Update: This makes my IDE happy but I hit a runtime error - "Relative import path "..." not prefixed with / or ./ or ../"...

Update 2: The error only occurs for executable code, it works fine for importing models

@sweatybridge
Copy link
Contributor

I finally managed to look into this more. I had to use absolute path when mounting import map inside the container.

Feel free to verify this fix with npx supabase@beta functions serve

@leoneparise
Copy link

leoneparise commented May 12, 2024

The issue persists in beta (v1.167.4). I found that the import_map.json only works correctly when the file is placed inside the supabase directory and not within the functions subdirectory. Here’s the content of my import_map.json:

{
  "imports": {
    "chai/": "npm:/[email protected]/",
    "drizzle-orm": "npm:[email protected]",
    "drizzle-orm/": "npm:/[email protected]/",      
    "postgres": "npm:[email protected]",
    "date-fns": "npm:[email protected]",
    "date-fns-tz": "npm:[email protected]",
    "langchain": "npm:[email protected]",
    "supabase-js": "npm:@supabase/[email protected]",
    "delay": "https://deno.land/x/[email protected]/mod.ts",
    "std/": "https://deno.land/[email protected]/",
    "oak/": "https://deno.land/x/[email protected]/",    
    "validasaur/": "https://deno.land/x/[email protected]/",
    "@utils/": "./functions/_utils/",
    "@repositories/": "./functions/_repositories/",
    "@shared/": "./functions/_shared/",
    "@tests/": "./functions/tests/"
  }
}

Here is the command I use as a workaround the issue:

npx supabase functions serve --import-map ./supabase/import_map.json --no-verify-jwt

@stefan-girlich
Copy link

stefan-girlich commented May 30, 2024

Confirmed that this is also broken in the release v1.167.4.
Edit: I moved import_map.json to supabase/ and the serve process began installing dependencies, but got stuck at Download https://esm.sh/v135/[email protected]/esnext/ws.mjs until I killed the process. Re-running supabase db functions serve would raise the error InvalidWorkerCreation: worker boot error Relative import path "@supabase/supabase-js" not prefixed with / or ./ or ../ and not in import map from "file:///home/deno/functions/on-user-create/index.ts".
I moved the file back to supabase/functions/ and I can now successfully import the dependencies from the map.
A very random experience overall.

@sweatybridge Could you please re-open this issue?

@sweatybridge sweatybridge reopened this May 30, 2024
@stefan-girlich
Copy link

stefan-girlich commented May 30, 2024

Observations using Supabase v1.168.8

import_map.json

(removed functions/ when placed in functions/)

{
  "imports": {
    "supabase-js": "https://esm.sh/@supabase/[email protected]",
    "supabase-types": "./functions/_shared/@types/supabase.ts"
  },
  "scopes": {}
}

using supabase/functions/import_map.json

failed to load 'file:///home/deno/_shared/@types/supabase.ts': Module not found "file:///home/deno/_shared/@types/supabase.ts".
An error has occured
InvalidWorkerCreation: worker boot error failed to load 'file:///home/deno/_shared/@types/supabase.ts': Module not found "file:///home/deno/_shared/@types/supabase.ts".
    at async UserWorker.create (ext:sb_user_workers/user_workers.js:155:15)
    at async Object.handler (file:///home/deno/main/index.ts:147:22)
    at async respond (ext:sb_core_main_js/js/http.js:162:14) {
  name: "InvalidWorkerCreation"
}

using supabase/import_map.json

Relative import path "supabase-js" not prefixed with / or ./ or ../ and not in import map from "file:///home/deno/functions/on-user-create/index.ts"
An error has occured
InvalidWorkerCreation: worker boot error Relative import path "supabase-js" not prefixed with / or ./ or ../ and not in import map from "file:///home/deno/functions/on-user-create/index.ts"
    at async UserWorker.create (ext:sb_user_workers/user_workers.js:155:15)
    at async Object.handler (file:///home/deno/main/index.ts:147:22)
    at async respond (ext:sb_core_main_js/js/http.js:162:14) {
  name: "InvalidWorkerCreation"
} 

@sweatybridge
Copy link
Contributor

sweatybridge commented Jun 10, 2024

Sorry I just double checked everything and confirmed it is a bug with importing directory paths. It will be fixed in the stable release tomorrow.

The expected behaviour is that relative paths in import_map.json should be based on where your import map is located. For eg. to import a file supabase/functions/_shared/types.ts

If your import map is located at supabase/functions/import_map.json, then it should read

{
  "imports": {
    "supabase-types": "./_shared/types.ts"
  },
}

Otherwise, if it is located at supabase/import_map.json, then it should read

{
  "imports": {
    "supabase-types": "./functions/_shared/types.ts"
  },
}

@AndryHTC
Copy link

I'm noting here that the Supabase functions appear to search for "import_map.json" within the "functions" directory. The newly recommended method of defining import maps in the "deno.json" file does not seem to be working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet