Support for npm modules in Edge Functions

We’re pleased to announce support for npm modules in Edge Functions, allowing you to leverage the more than two-million packages in the npm ecosystem when building on Netlify Edge Functions.

Using a module

The experience of using npm modules in Edge Functions in very similar to the one in Netlify Functions. To load a module, start by installing it in your site’s base directory.

npm install --save lodash

We’re using the npm client in this example, but you can replace that with your favorite package manager, like Yarn or pnpm.

Next, import the module into your edge function and use it as per its documentation.

import _ from "lodash";

const compiled = _.template("Hello, dear visitor from <%= country %>!");

export default async (req, context) => {
  const text = compiled({ country: context.geo.country.name });

  return new Response(text);
};

export const config = {
  path: "/hello",
};

In this example, we’re using Lodash to compile a template and render it in response of a request. If you deploy this edge function and access /hello, you should see a personalized message based on the country you’re accessing from.

Beta support

We wanted to get support for npm modules in the hands of our customers as early as possible, because it was one of the most requested features of Edge Functions. We’re launching it as an experimental feature because we’re still actively working on improving it and addressing some caveats that you should be aware of before using it in your production workflows.

Under the hood, our build system will traverse the entire module tree and bundle together the code in your edge functions, any npm modules they import, any dependencies of those modules, and so on.

This means that any files that aren’t directly loaded using an import or require statements will not be discovered in this process and will not be available at runtime. For example, if a module uses a filesystem method to dynamically read a text file at runtime (like cowsay), or expects a native addon to exist in a specific location (like prisma), the package may not work correctly.

We want to hear from you

We’re hard at work making this feature work for you, and we’d love to hear how it goes. If you come across a package that doesn’t work as expected, or anything about the experience that doesn’t feel right, please let us know in this thread.

If you use the Netlify CLI to test or deploy your edge functions, please update to version 16.8.0 or above.

Thanks!

Hey there! This is exciting. I’ve run into an issue with the package @optimizely/optimizely-sdk. Here’s the relevant error from the build logs:

3:50:32 PM: Packaging Edge Functions from sites/xxxxxx/netlify/edge-functions directory:
3:50:32 PM:  - optimizely
3:50:33 PM: error: Uncaught (in promise) Error: Relative import path "@optimizely/optimizely-sdk" not prefixed with / or ./ or ../ and not in import map from "file:///root/sites/marketing-site/netlify/edge-functions/optimizely.ts"
3:50:33 PM:       const ret = new Error(getStringFromWasm0(arg0, arg1));
3:50:33 PM:                   ^
3:50:33 PM:     at __wbg_new_15d3966e9981a196 (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm.generated.js:417:19)
3:50:33 PM:     at <anonymous> (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm_bg.wasm:1:93412)
3:50:33 PM:     at <anonymous> (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm_bg.wasm:1:1499594)
3:50:33 PM:     at <anonymous> (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm_bg.wasm:1:1938165)
3:50:33 PM:     at __wbg_adapter_40 (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm.generated.js:231:6)
3:50:33 PM:     at real (file:///opt/buildhome/node-deps/node_modules/@netlify/edge-bundler/deno/vendor/deno.land/x/eszip@v0.40.0/eszip_wasm.generated.js:215:14)
3:50:33 PM:     at eventLoopTick (ext:core/01_core.js:183:11)
3:50:33 PM: ​
3:50:33 PM: Bundling of edge function failed                              
3:50:33 PM: ────────────────────────────────────────────────────────────────
3:50:33 PM: ​
3:50:33 PM:   Error message
3:50:33 PM:   There was an error when loading the "@optimizely/optimizely-sdk" npm module. Support for npm modules in edge functions is an experimental feature. Refer to https://ntl.fyi/edge-functions-npm for more information.

And here’s how I’m importing in my file:

import { createInstance } from '@optimizely/optimizely-sdk';

I ran into the same issue when trying to import React. For my use case, I could switch to esm.sh but this issue is a blocker if esm.sh is not an option.

Hey @jon.darby and @Charles_Kornoelje, thanks for letting us know about this!

I’ve looked into the @optimizely/optimizely-sdk case, and it looks like your code should work, but there’s a problem in our bundling code around CJS / ESM imports. However, i’m seeing a different error than you - mine says SyntaxError: The requested module '@optimizely/optimizely-sdk' does not provide an export named 'createInstance'. Just to double-check, are you seeing this error in the CLI or in a CI build, and on what version of the CLI are you?

Provided you’re on a recent version of our build system, you should be able to work around this using a default import:

import optimizely from '@optimizely/optimizely-sdk';

optimizely.createInstance({ ... })

This is also what Optimizely shows in their docs: GitHub - optimizely/javascript-sdk: JavaScript SDK for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)

I’m taking a look now at how we can make this also work with a named import, will keep this thread updated.

@Charles_Kornoelje could you maybe post a similar code snippet of how you ran into this issue and wether you were using the CLI + what version you’re on?

Welcome to the forums, btw - good to have you! :grin:

Best Regards, Simon

Found a fix for Optimizely: fix: prefer ESM if available by Skn0tt · Pull Request #517 · netlify/edge-bundler · GitHub We’ll review this now, and i’ll ping here when this ships to production.

2 Likes

I’ll post a code snippet here soon! I sent a .zip with a reproduction to the Netlify support team.

Thanks
Charlie

We’ve rolled out the fix mentioned above. @jon.darby could you verify this fixes the build for you?

@Charles_Kornoelje I’ve found a bug related to react, it might be similar to the one you have in mind. It’s printing some error message relating to process.env being undefined. We’re working on a fix over here, will keep this updated: fix: parse TSX files for module detection, define NODE_ENV by Skn0tt · Pull Request #519 · netlify/edge-bundler · GitHub

Thanks for the updates, @skn0tt. I switched to use Deno Import Maps with my Netlify Edge functions. The Import Maps uses esm.sh or deno.land links which is working great.

awesome. thanks for sharing this @Charles_Kornoelje :+1:t6:

Im running into the issue with crypto package. I believe it is because of Firebase on angular 17. here’s the error. Any way to fix it?

@lfarjon, no duplicates please: Error while building: Relative import path “crypto” not prefixed with / or ./ or …/ and not in import map (netlify.com)