Closed KaziSadmanAhmed closed 4 months ago
I'm experiencing the same problem, from what I can see it also happens for ecerything under the public
directory (all the assets)
We faced the same issue today and after many hours looking for the culprit, we found that the 'aws-lambda' nitro preset does not support serving static files. This is probably by design, because AWS API Gateway does not support serving binary files by default, as far as I know.
We propose two fixes:
One fix is very simple, just need to extend the 'aws-lambda' preset in nuxt.config.js
enabling the serveStatic
option.
export default {
nitro: {
preset: 'aws-lambda',
serveStatic: true
}
}
Then, if using API Gateway, you'll likely have to enable binary file serving. Our project is build using Serverless Framework, so we just used serverless-apigw-binary plugin.
We found this option by digging into the source code of the 'node-server' preset. You can also find the preset definition for 'aws-lambda' in case you want to define your own 'aws-lambda-static' or something.
If you don't include this option, Nitro will not include a handler for static file routes, which will be handled by regular Vue Router handler. Which is the reason you get 404 (it is not that the server can't find the files).
A (maybe better) second solution is to not serve static files through lambda, because it's slower and more expensive compared to dedicated static file serving such a CDN. What you do in this case is to not include the serveStatic: true
config and define your cndUrl in nuxt.config.js
:
export default {
nitro: {
preset: 'aws-lambda',
},
app: {
cndUrl: 'https://your-static-host.com/',
}
}
cndUrl
was previously known as publicPath
in Nuxt 2
In this case, you have to upload the content of .output/public/
into https://your-static-host.com/
. When using Serverless Framework, this would mean a manual process, but you could also automate it with serverless-finch (S3 Bucket) or serverless-lift (S3 + CloudFront Distribution) 👍🏻👍🏻👍🏻
We found the documentation lacking with regards to serving static files through lambda and Nitro config, so if any of this information is of help, we'd be happy to add it to the docs 🙂
Thanks for very well written insights @bros4president. Certainly contributing to the documentation is more than welcome in order to improve aws docs. Also, I think adding a new preset that enables serve-static would be a good idea 👍🏼
@bros4president You are a lifesaver. The documentation is very lacking with regards to this, and your solution fixed the problem!!!
@bros4president Hello, may i know where i can find the details of 'serveStatic: true' ?
@jerryisbusy There's documentation on the Nitro configuration, like serveStatic, in the Nitro docs here
@Lundi Thanks!
I'm getting stuck on this. I tried the following config:
nitro: {
preset: 'aws-lambda',
serveStatic: true,
},
but when my client tries to fetch public files, the page shows this:
{
"url": "/_nuxt/manifest.json",
"statusCode": 500,
"statusMessage": "Internal Server Error",
"message": "The \"path\" argument must be of type string or an instance of URL. Received undefined",
"description": ""
}
I must be missing something basic here.
@ffxsam having the exact sme problem! Have you had any luck?
@ffxsam
After a bit of reading on some older posts related to Serverless and nuxt2, it seems like a recommended approach is to serve static assets from a CDN
I installed serverless-finch, configured it to deploy .output/public to an S3 bucket, then configured nuxt to use that S3 bucket as the CDN URL.
Nuxt 2 post (advice seems to broadly hold up for Nuxt 3 in this regard) - https://epndavis.com/blog/nuxtjs-serverless-side-rendering-on-aws-lambda/
Serverless finch plugin: https://github.com/fernando-mc/serverless-finch#readme
Steps:
1) install the serverless-finch package - $ npm i serverless-finch / $ yarn add serverless-finch 2) Update serverless.yml to include the following blocks:
plugins:
custom: serverless-offline: noPrependStageInUrl: true client: bucketName: {{ENTER A BUCKET NAME HERE}} distributionFolder: .output/public
3) build project etc (whatever steps you're using)
Yeah, I realized it can just be hosted on the CDN. I've created the following deploy script to handle this for me:
#!/bin/sh
set -ex
source .env
npx nuxi build nuxt
aws s3 sync --delete nuxt/.output/public $CDN_S3_URL
yarn sst deploy $*
Don't want to be a pain, but could anybody create an example repo until the documentation is better? It would be greatly appreciated!
@uncle-samm https://github.com/ffxsam/nuxt-sst
@uncle-samm https://github.com/ffxsam/nuxt-sst
My hero!
@uncle-samm It may not necessarily be exactly what everyone needs (as it's highly opinionated by using SST to build the infrastructure), but it's a 100% working-out-of-the-box repo.. to the best of my knowledge. 🙂
@uncle-samm It may not necessarily be exactly what everyone needs (as it's highly opinionated by using SST to build the infrastructure), but it's a 100% working-out-of-the-box repo.. to the best of my knowledge. 🙂
Yes, I'll have to look into that but I do see a lot of advantages using SST. It's still relatively new for me, am used to Docker. However this seems like a logical next step for me
I'm not even able to reproduce this manually.
I have a Nuxt v3 project with a /server/api/hello.ts
file with some basic content
export default defineEventHandler((event) => {
return {
message: 'this endpoint works',
};
});
this is my nuxt.config.ts
import { defineNuxtConfig } from 'nuxt';
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
nitro: {
preset: 'aws-lambda'
},
ssr: false,
typescript: {
shim: false,
},
build: {
postcss: {
postcssOptions: require('./postcss.config.js'),
},
},
});
after running NITRO_PRESET=aws-lambda yarn build
(which does a nuxt build
) an .output
folder is created, containing
I immediately ask myself why there is a renderer.mjs
handler in the server sub-folder since I configured ssr: false
in the Nuxt config.
In the AWS console (for testing purposes), I created a Lambda proxy integration:
Regarding the target Lambda, I've tried everything from the whole .output
folder to only the content of the .output/server
folder.
I've not been able to access my API at https://xxx.execute-api.eu-central-1.amazonaws.com/dev/api/hello
Any hints would be welcome!
Ideally I want to host the static parts (the SPA) on S3+CloudFront and provide the API part via APIGW+Lambda. But one step after another..
I haven't built with ssr: false
, but with ssr enabled, you map the lambda handler to .output/server/index.handler
.
I've checked the method execution in the AWS console for APIGW and the response gives a hint:
Tue Sep 13 23:26:58 UTC 2022 : Sending request to https://lambda.eu-central-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:eu-central-1:xxxxxxxxxx:function:nuxt-test/invocations
Tue Sep 13 23:26:58 UTC 2022 : Received response. Status: 200, Integration latency: 25 ms
Tue Sep 13 23:26:58 UTC 2022 : Endpoint response headers: {Date=Tue, 13 Sep 2022 23:26:58 GMT, Content-Type=application/json, Content-Length=168, Connection=keep-alive, x-amzn-RequestId=d167144e-5c2e-48fb-af46-ed0xxxxxxxxxx, x-amzn-Remapped-Content-Length=0, X-Amz-Executed-Version=$LATEST, X-Amzn-Trace-Id=root=1-632111c2-8502d608c69e6xxxxxxxxxx;sampled=0}
Tue Sep 13 23:26:58 UTC 2022 : Endpoint response body before transformations: {"cookies":[],"statusCode":200,"headers":{"content-type":"application/json","server-timing":"-;dur=0;desc=\"Generate\""},"body":"{\"message\":\"this endpoint works\"}"}
Tue Sep 13 23:26:58 UTC 2022 : Execution failed due to configuration error: Malformed Lambda proxy response
Tue Sep 13 23:26:58 UTC 2022 : Method completed with status: 502
it says Malformed Lambda proxy response
what I can't understand yet, because the response seems to be fine:
{
"cookies": [],
"statusCode": 200,
"headers": {
"content-type": "application/json",
"server-timing": "-;dur=0;desc=\"Generate\""
},
"body": "{\"message\":\"this endpoint works\"}"
}
This means the endpoint is called, forwarded to Lambda, which executes the right Nuxt server endpoint GET /api/hello
and then has problems with the integration / method response.
The actual response is created by Nuxt / Nitro from my hello.ts
endpoint
export default defineEventHandler((event) => {
return {
message: 'this endpoint works',
};
});
it works locally though..
Any idea appreciated. And the Nuxt docs really lack some detail in this regard. I'm happy to document it once I figured this out
@steffenstolze Your issue is likely the same as https://github.com/unjs/nitro/issues/504.
Don't want to be a pain, but could anybody create an example repo until the documentation is better? It would be greatly appreciated!
For future readers in addition to the example from @ffxsam here is an example using AWS CDK to deploy to Lambda and S3. I also was not able to get it working until using a CDN for assets.
If anyone is still encountering this, please open an issue in the nitro repository? 🙏
Environment
Darwin
v14.19.0
3.0.0-27447229.20f3171
yarn@1.22.17
Vite
-
-
Build Modules:
-
Reproduction
npx nuxi init nuxt3-app
export NITRO_PRESET=lambda
)Describe the bug
The deployed function will not serve anything from the
/_nuxt
path. Either it will return the default welcome page or the 404 error page if you setup pages.Additional context
No response
Logs
No response