serverless-nextjs / serverless-next.js

⚡ Deploy your Next.js apps on AWS Lambda@Edge via Serverless Components
MIT License
4.45k stars 455 forks source link

Documentation for how to use `plaiceholder` to generate blurred image placeholders #1599

Open WarcraftYax opened 3 years ago

WarcraftYax commented 3 years ago

I recently had to work out how to get plaiceholder (https://github.com/joe-bell/plaiceholder) working inside my getStaticProps method to generate blurred image placeholders. As I understand, this works out of the box in Vercel (assuming you wrap your Next config with the withPlaiceholder helper method). This was not the case using serverless-nextjs, as the regeneration lambda would throw an error when trying to require('sharp'), as this is an external module and no node_modules are included in the bundle.

Digging through issues, I noticed that the image lambda had this issue at one point, and the solution had been to bundle node_modules (with sharp installed) in the lambda (at the cost of ~7MB compressed space on the 50MB bundle limit). So, my (admittedly hacky), solution was to simply copy the node_modules folder from the image lambda to the default and regeneration lambdas using post build commands (I had to copy it to the default lambda as otherwise 404 pages were crashing as, even though sharp wasn't used on a 404 page, it still imported plaiceholder and would attempt to require sharp).

App:
  component: "@sls-next/serverless-component@3.2.0"
  inputs:
    build:
      # Our default & regeneration lambdas also need the sharp module like the image lambda does, so copy it from there
      postBuildCommands:
        - "cp -r ./.serverless_nextjs/image-lambda/node_modules ./.serverless_nextjs/default-lambda/node_modules"
        - "cp -r ./.serverless_nextjs/image-lambda/node_modules ./.serverless_nextjs/regeneration-lambda/node_modules"

I understand a more elegant method might be to run an npm install sharp command in each lambda instead of simply copying the node_modules across from the image lambda (which maybe one day will have even more packages installed or will be able to remove the reliance altogether, making the current solution flaky).

I think using plaiceholder is a semi-common use case and it would be good to have some documentation on how to use it in serverless-nextjs.

dphang commented 3 years ago

Yes right now the sharp modules are bundled for the image optimization lambda since it's built specifically for the AWS Lambda Node14 image (via Docker) which is recommended by Sharp authors (although they use another image). I created a Dockerfile here: https://github.com/serverless-nextjs/serverless-next.js/blob/master/packages/libs/lambda-at-edge/scripts/Dockerfile which I guess you can use as well to build sharp for yourself and copy it using custom postBuildCommands.

I was trying to create a third party integrations module: https://github.com/serverless-nextjs/serverless-next.js/tree/master/packages/libs/lambda-at-edge/src/build/third-party which is for next-18n right now only (it should probably move to core instead of lambda-at-edge, though that refactor is still long overdue, it seems like a good fit for things like plaiceholder, if you'd like to explore that path.

Actually, I also think that only the sharp binaries need to be compiled for the AWS Lambda Node.js image, but the rest of the JS code can be bundled normally. Though also right now rollup doesn't bundle at deploy-time (it's pre-bundled and distributed), so we would need a change to bundle at deploy-time for including additional packages.

Lea23VC commented 2 years ago

Hello, there's a solution for this now?, I have the same problem, but running those postBuildCommands didn't work for me