Did anybody manage to run an nbb-based lambda function with serverless recently? There's some examples out there (like this one: https://github.com/vharmain/nbb-serverless-example/blob/main/index.mjs) that maybe worked some time ago, but for some reason, .mjs files are currently simply ignored by serverless. If I try to run this very example I'm getting: "Error: Cannot find module './index.js'". Every attempt to work around this problem: renaming index.mjs to index.js means I cannot "import" in it because it's not an ESM Module, turning the entire thing into an ESM module via package.json/type:module leads to other issues (apparently serverless adds some code using "require" during the build). I just can't seem to make it work and I can't tell why.. when it looks like it did work 10 months ago.
@roseneck It might help to put "type": "module" in your package.json
at least for the "cannot import init because ESM" thing
That's what I thought too, but while running: "serverless invoke local --function hello" A file called "s_hello.js" is generated that has a "require" in it. And then the following error is thrown: ✖️ ReferenceError: require is not defined in ES module scope, you can use import instead This file is being treated as an ES module because it has a '.js' file extension and '/.../package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension. at file:///.../s_hello.js:2:21
@roseneck Did you research their github issues? I'm sure someone else ran into this. But what you can do instead of do this in a .js file which is a commonJS one:
async function foo () {
await import("./foo.mjs")
}
foo()Maybe this issue? https://github.com/serverless/serverless/issues/11308
Perhaps @valtteri knows something here
Do you think I could just do it like this: in my index.js
async function loadStuff () {
const nbb = await import('nbb');
const cljsFile = await nbb.loadFile('./function.cljs')
}
exports.handler=loadStuff();
I think you might
Yea, that's one of several issues that kind of fit, but I didn't find a solution yet.
without the () though
it is better to the loading of the file once at startup instead of in the handler
so you might be able to cache the result
This is a workaround that we had in https://github.com/vharmain/nbb-lambda-adapter before we could just use ESM
hah, you might still be able to use that as a workaround for serverless
Looks like calling import as an async function did the trick!
yes nice! but now I think it's good to add some caching, since you don't want to do all this work on every lambda invocation
So something like this:
var cachedHandler;
async function loadStuff () {
if (cachedHandler) {
return cachedHandler;
}
const nbb = await import('nbb');
cachedHandler = await nbb.loadFile('./function.cljs');
return cachedHandler;
}
exports.handler=loadStuff;You mean if the function is still warm? Yea, good idea!
yes
I'm not entirely sure the above is 100% correct since handler is now set to a function that returns a promise of the handler, but you can probably figure this out :)
E.g. this may work better:
var cachedHandler;
async function handler(payLoad) {
if (cachedHandler) {
return cachedHandler(payLoad);
}
const nbb = await import('nbb');
cachedHandler = await nbb.loadFile('./function.cljs');
return cachedHandler(payLoad);
}
exports.handler=loadStuff;Hm.. .it says: TypeError: cachedHandler is not a function
Not sure why.
What do you return from function.cljs?
(ns function) (defn handler [event _ctx] (js/console.log event) (js/Promise.resolve #js{:hullo "world"}))
still the example code
Is it cachedHandler.handler(payload)?
I think you need to add something like:
#js {:handler handler}
at the bottom and then write:
cachedHandler = (await nbb.loadFile('./function.cljs')).handler;When you have defn as the last expression, the return value is a SCI Var which JS doesn't recognize as a function
probably
I gotta to go and will fiddle around more later, thanks a ton for your help!
user=> (defn foo [] 1)
#'user/foo
user=> (set! (.-foo js/globalThis) foo)
nil
user=> (js/eval "foo()")
1
user=> (set! (.-foo js/globalThis) #'foo)
nil
user=> (js/eval "foo()")
"TypeError: foo is not a function"I will try the example later when I get home and check if some issues have popped up
I’d expect it to just work as long as the lambda Nodejs runtime supports top-level await.. since 14.something.something
Yea I would totally expect that too and lambda definitely supports esm (zipping it up and uploading it manually works).
It must be something about serverless, but I can't tell what I'm doing wrong.
I just tried a fresh clone from the repo and ran the instructions in the example and it works 🤔
I can maybe help debug what’s wrong with your setup @roseneck. Could you please paste your serverless.yml contents here if possible?
and the version of serverless
and the Node.js version
And how you’re trying to run it 🙂
> npx sls --version > Framework Core: 2.72.3 (local) > Plugin: 5.5.4 > SDK: 4.3.2 > Components: 3.18.2
AHH sorry didn’t notice that this was about serverless invoke local . I just tested that the deployed one works. I’m not sure if the invoke local has ever worked since I don’t use it.
And yes.. https://github.com/serverless/serverless/issues/11308 looks relevant
I’m afraid that if you want to use invoke local your options are:
• patch serverless with this unmerged PR https://github.com/serverless/serverless/pull/11366/files
• use nbb-lambda-adapter instead that should work with non-`.mjs` stuff https://github.com/vharmain/nbb-lambda-adapter
It's not just local.. I just used local for faster feedback. I just did a fresh checkout of your repo and did a deploy with the following versions: Operating System: linux Node Version: 18.10.0 Framework Version: 2.72.3 (local) Plugin Version: 5.5.4 SDK Version: 4.3.2 Components Version: 3.18.2 Here's what I got: ~ serverless invoke --function add ✔️ 2m 19s Running "serverless" from node_modules Serverless: Using provider credentials, configured via dashboard: https://app.serverless.com/hankstenberg/apps/add/nbb-serverless-example/dev/eu-west-1/providers { "errorType": "Error", "errorMessage": "Cannot find module './index.js'\nRequire stack:\n- /var/task/s_add.js\n- /var/runtime/UserFunction.js\n- /var/runtime/Runtime.js\n- /var/runtime/index.js", "trace": [ "Error: Cannot find module './index.js'", "Require stack:", "- /var/task/s_add.js", "- /var/runtime/UserFunction.js", "- /var/runtime/Runtime.js", "- /var/runtime/index.js", " at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)", " at Module.require.i.require (/var/task/serverlesssdk/index.js:9:73131)", " at require (internal/modules/cjs/helpers.js:101:18)", " at Object.<anonymous> (/var/task/s_add.js:25:23)", " at Module._compile (internal/modules/cjs/loader.js:1085:14)", " at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)", " at Module.load (internal/modules/cjs/loader.js:950:32)", " at Function.Module._load (internal/modules/cjs/loader.js:790:12)", " at Module.require (internal/modules/cjs/loader.js:974:19)", " at require (internal/modules/cjs/helpers.js:101:18)" ] }
My node Version is v18.10.0
That’s a bummer. 😕 invoke without local seems to suffer from the same defect
But I assume that if you use curl the lambda itself does work
Hmmm invoke without local seems to work with the latest serverless
npx serverless invoke --function add --data '{"body":"{\"x\":1,\"y\":2}"}'
{
"statusCode": 200,
"body": "{\"result\":3}"
}> npx sls --version > Framework Core: 3.23.0 (local) > Plugin: 6.2.2 > SDK: 4.3.2
I just updated the example repo
• latest serverless and nbb
• add example how to use invoke
• add mention that invoke local does not work
https://github.com/vharmain/nbb-serverless-example
Thanks for notifying about the issue!
I really don't understand what is wrong with my setup. So I checked out your updated repo. I cd'ed into it. I ran: • "npm update". • npx sls --org my-org • I said: "yes, I want to deploy now" • Deployed successfully • I ran npx serverless invoke --function add --data '{"body":"{\"x\":1,\"y\":2}"}' And I'm getting: "errorType": "Error", "errorMessage": "Cannot find module './index.js'\nRequire stack:\n- /var/task/s_add.js\n- /var/runtime/UserFunction.js\n- /var/runtime/Runtime.js\n- /var/runtime/index.js", "trace": [ "Error: Cannot find module './index.js'", I have just the same versions: Framework Core: 3.23.0 (local) Plugin: 6.2.2 SDK: 4.3.2
Node.js version?
v18.10.0
What does your git status output look like?
On branch main Your branch is up to date with 'origin/main'. Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: serverless.yml Untracked files: (use "git add <file>..." to include in what will be committed) package-lock.json no changes added to commit (use "git add" and/or "git commit -a")
diff --git a/serverless.yml b/serverless.yml index f613ea5..c9bbec3 100644 --- a/serverless.yml +++ b/serverless.yml @@ -1,3 +1,5 @@ +org: hankstenberg +app: add service: nbb-serverless-example frameworkVersion: '2 || 3'
Could old serverless still be lurking in package-lock.json? You can try nuking it and running npm install
Ah no, your serverless version was new
Yes, I still tried, but no
My Node.. Don’t expect that to be the issue but you never know
node --version
v18.9.1Note sure how to downgrade to that specific version right now... but I really don't think that this can be the issue. I'll try some other things first. Like... I don't know.. restarting my computer. 😉
I’m also starting to run out of ideas. 😕 I’m on MacOS. Please let me know if there’s something more I can provide for help
Thanks a lot for all the support, at least I know that it is something about my setup now that helps a ton! I'll start ruling out things one by one. ❤️👍
I can only think of the “traditional rituals” with Node ecosystem • rm -rf node_modules • rm package-lock.json • npm install • wait for all the planets to be aligned