DEV Community

Cover image for A crash course on serverless-side rendering with Vue.js, Nuxt.js and AWS Lambda

A crash course on serverless-side rendering with Vue.js, Nuxt.js and AWS Lambda

Adnan Rahić on August 20, 2018

That's a mouthful of a title right there. Don't let it scare you away. What it boils down to is rather simple. We want the best of both worlds. Th...
Collapse
 
johey profile image
Johan Smolinski

Any way I can test my site locally? I've tried using the serverless-offline plugin, but although the local web server is starting up, I get no functional endpoints. Navigating to localhost:3000/ just gives a 404 in the server log.

Collapse
 
lewebsimple profile image
Pascal Martineau • Edited

I was having the same problem, but got it working with the following:

app.use((req, res) => setTimeout(() => nuxt.render(req, res), 0));

I have no idea why this works, I stole it from the jeehyukwon/nuxt-edge-serverless-template repository.

Collapse
 
svedova profile image
Savas Vedova • Edited

I believe it's safer if you wait till the renderer is ready. To do so, simply listen to the render:done hook. For instance something like should work:

app.use((req, res) => {
  nuxt.hook("render:done", () => {
    nuxt.render(req, res);
  });
});

setTimeout doesn't seem very reliable to me :) On my mac I had to wait around 60ms for instance.

Thread Thread
 
aphilippartd profile image
Alexis Philippart de Foy

The following works as well.

app.use(async (req, res) => {
  await nuxt.ready()
  nuxt.render(req, res)
})

With the nuxt.hook("render:done" () => {}) I was getting random 404 errors when deployed. nuxt.ready() did the trick for me!

Thread Thread
 
adnanrahic profile image
Adnan Rahić

Awesome of you to share this! Feel free to add a PR to the GitHub repo with this edit. 👌

Collapse
 
pachiradig profile image
pachiraDIG • Edited

Can confirm this solution works. Install serverless-offline with npm i serverless-offline. Then in nuxt.js, just replace app.use(nuxt.render) with Pascal's code, above. Run the plugin with sls offline. Be sure to include the http in http://localhost:3000.

Collapse
 
dseeker profile image
D See Ker

Works great, but resulting package is 40MB+
Would be good to see another tutorial on trimming the unused packages. I tried with Exclude/Include in serverless CLI and also the serverless-plugin-optimize and serverless-plugin-include-dependencies, they all had an effect on the output size, but none worked in AWS :(
Shouldn't we compile the application and send only the dist files instead of the entire node_modules folder?

Collapse
 
ludofleury profile image
Ludovic Fleury • Edited

check my answer here: dev.to/ludofleury/comment/icn2

Collapse
 
lucadalli profile image
Luca Dalli • Edited

Fantastic post, Adnan. Really enjoying this series of threads relating to serverless.
One (silly?) question.
Is further setup required to be able to serve static assets like images etc.?

Collapse
 
adnanrahic profile image
Adnan Rahić

Hey Luca

Not a silly question at all! To be direct, no further setup is required. Even though a lambda function is ephemeral, you can store static assets and serve them just as from any other server (check this out in the repo).

However, I would argue against this for a real-world use case. You should really use an S3 bucket to store the images and serve them from there.

Another cool fact is that you can use Nuxt to generate static files and host everything on S3, without using AWS Lambda at all. It all comes down to preference.

Hope this clears some things up. I'm glad you liked the article. Stay in touch or send me a message through the chat if you have any questions. 😃

Collapse
 
randyhoulahan profile image
Randy Houlahan

Very nice example and article! Any thoughts on how to store the static dist files on S3? I mean lambda for the SSR first hit from the client. Then any other nuxt dist files needed once the the SPA is hydrated on the client are then retrieved form the s3 bucket/cloud-front distribution?

Thread Thread
 
linusboehm profile image
Linus Boehm

Did you found a solution for this?

Thread Thread
 
ludofleury profile image
Ludovic Fleury • Edited

Alright, I spent my weekend on this, here's the insights:

  1. You need a "manually setup" cloudfront distribution and stop relying on the automated edge optimized domain name by serverless.
    You configure the cloudfront distribution with 2 behaviors:
    "/" to your API Gateway
    "/_nuxt/*" to your s3 bucket.
    And you configure manually the custom domain name in cloudfront and in Route53 DNS
    Its a bit of initial work but you'll do this only once. You can remove the serverless plugin for domain management.

  2. I used serverless-finch plugin which handle the upload to s3 + a manually s3 bucket setup
    You can remove the "app.use('/nuxt', express.static(path.join(_dirname, '.nuxt', 'dist')))" as your lambda won't be called anymore for serving static files.

  3. You need to optimize (aka reduce) your dependencies, rely on nuxt-start (check npm), which is a production-only distribution of nuxt.

Exclusively for aws lamba (not sure for other cloud providers):

  • I packaged expressjs in a lambda layer
  • I packaged nuxt-start and my other dependencies in a second layer

So I excluded the directory "node_modules/**" from my serverless deployment. Which means every time I install another npm package, I have to update my layer, you can automate this with a specific ".sh", but it's still cumbersome tbh.

For my serverless deployment, it becomes extremly lightweight and simple:
exclude everything, include only:

  • .nuxt/dist/server/*
  • index.js
  • prismic.config.js
  • nuxt.config.js
  • nuxt.js

The client ones are hosted on s3 thanks to the serverless-finch plugin:
bucketName: ********
distributionFolder: .nuxt/dist/client
keyPrefix: _nuxt

The result is efficient: the lambda size is around 15.7 Kb deployed.

Layers uploaded only once as my deps are not really moving:

  • The expressjs layer: 678 Kb zipped
  • My project dependencies layer: 4.7 Mb zipped

I might be writing a blog post about it here on dev.to soon.

Thread Thread
 
hedlainer profile image
Ivan

I really need your post =)
i can't integrate static with cloudfront

Thread Thread
 
larswww profile image
larswww

Thanks Ludovic,

I got things running however couldn't find the distribution listed in cloudfront. Hence, unable to use it to proxy to other aws resources... which seems to be a limit in the serverless domain plugin.

Collapse
 
pavewaytech profile image
PaveWay TECHNOLOGIES INC

Render static images in nuxt when deployed

I cloned the repo and deployed and everything worked until i added local file to the static folder of my nuxt app with other plugins like PWA and router etc. When i reference the images, they don't load and the sw.js script returns a 403 http error.

Please what am i to do to fix this error. Do i have to update the serverless.yml file or what?

Collapse
 
piyushgargdev profile image
Piyush Garg

Hey there, Nice Post. I made an npm package for handling AWS Lambda responses. Do checkout 😎

AWS-TS This package lets you handle and send responses from AWS lambda with ease. You have the ability to send various types of responses such as JSON or Plain Text without worrying about headers and status codes. You can also enable or disable cors for all or specific responses or set custom headers.

🚀 npmjs.com/package/aws-ts

Collapse
 
kirapwn profile image
Sebastian Luckos

Awesome article. I stumble upon one thing. My endpoint (nearby region) takes 1 second time to first byte, I am wondering if there is something in configuration that I missed in order to serve it more efficiently.

Collapse
 
adamorlowskipoland profile image
Adam

"This will create a CloudFront distribution and hook it up to your domain. Make sure that you've added the certificates to your AWS account."

I new I will stuck in some place.
As I am totaly new to the AWS... how am I supposed to add the certificates to my AWS account?
Should I change the default "vue-ssr.your-domain.com" and if so to what?

I have no domain on AWS this is my first touch with it.

Collapse
 
johey profile image
Johan Smolinski

I ran into the same problem. There are quite a few steps you need to do manually (i.e in the Web Console) before you can use this guide. I won't get into details, but first you need to register a domain name in Route53 (or add a hosted zone with a domain from another registrar, but that is probably more complicated). Then you will need to add a certificate. Easiest way is to use the Certificate Manager. Enter yourdomain.com and *.yourdomain.com in your certificate request, then follow the guide to verify it. After you've done this, you are ready to go with sls create_domain. It will add the vue-ssr subdomain for you.

Collapse
 
tahxcool profile image
tahxcool

I tried running the latest in the repo and im getting the following error:

Renderer resources are not loaded! Please check possible console errors and ensure dist..

I believe it run the npm run build on start-sls..anyone having the same issue?

Collapse
 
masamiki profile image
MASAMIKI • Edited

Thank you for a good article. I have a question. Is it possible to use nuxt v2 on this way?

Collapse
 
realquadrant profile image
timfong888

Hi, I was wondering about your thoughts of code compiled to WASM to execute serverlessly.

Collapse
 
komocode profile image
komocode

stuck at the part where i need to create a domain. there's like 0 explanation on this. annoying.