npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@downmoney/nextjs-lambda

v4.0.0

Published

Plug-and-play lambda for replacing default NextJS image optimization handler.

Downloads

2

Readme

NextJS Lambda Utils

This is a project allowing to deploy Next applications (standalone options turned on) to AWS Lambda without hassle.

This is an alternative to existing Lambda@Edge implementation (see) as it has too many limitations (primarily inability to use env vars) and deployments take too long.

This library uses Cloudfront, S3, ApiGateway and Lambdas to deploy easily in seconds (hotswap supported)

TL;DR

  • In your NextJS project, set output to standalone.
  • Run npm install @sladg/nextjs-lambda (will install dependency).
  • Run next build (will generate standalone next folder).
  • Run npm run-script env -- next-utils pack (will create ZIPs).
  • Run npm run-script env -- next-utils deploy (will deploy to AWS).
  • Profit 🎉

Usage

We need to create 2 lambdas in order to use NextJS. First one is handling pages/api rendering, second is solving image optimization.

This division makes it easier to control resources and specify sizes and timeouts as those operations are completely different.

Loading of assets and static content is handled via Cloudfront and S3 origin, so there is no need for specifying this behaviour in Lambda or handling it anyhow.

next.config.js

The only requirement is to change your Next12 config to produce standalone output via output: 'standalone'. This should work fine for single-repositories with yarn/npm/pnpm.

In case you are using monorepo/workspaces, be aware! Producing standalone build is tricky due to dependencies being spread out and not contained within single node_modules folder, making it complicated for SWC to properly produce required dependencies. This would most likely result in deployment failing with HTTP 500, internal error, as some required dependency is not in place.

See:

  • https://github.com/vercel/next.js/issues/36386
  • https://github.com/vercel/next.js/discussions/32223

Server handler

This is a Lambda entrypoint to handle non-asset requests. We need a way to start Next in lambda-friendly way and translate ApiGateway event into typical HTTP event. This is handled by server-handler, which sits alongside of next's server.js in standalone output.

Image handler

Lambda consumes Api Gateway requests, so we need to create ApiGw proxy (v2) that will trigger Lambda.

Lambda is designed to serve _next/image* route in NextJS stack and replaces the default handler so we can optimize caching and memory limits for page renders and image optimization.

Via CDK

See NextStandaloneStack construct in cdk/example.ts. Or just use next-utils deploy command so you don't have to manage CDK yourself.

Benchmark

  • Creation of stack: 385sec (6min 25sec)

  • Run #2 436sec (7min 16sec)

  • Run #3 383sec (6min 23sec)

  • Deletion of stack: 262sec (4min 22sec)

  • Run #2 319sec (5m 19sec)

  • Update of stack: 92sec (1min 32sec)

  • Run #2 5sec (no changes)

  • Run #3 3sec (no changes)

  • Run #4 164sec (2min 44sec)

  • Run #5 62sec (1min 2sec) (no changes, used next-utils deploy)

Sharp layer

Besides handler (wrapper) itself, underlying NextJS also requires sharp binaries. To build those, we use npm install with some extra parametes. Then we zip all sharp dependencies and compress it to easily importable zip file.

import { sharpLayerZipPath } from '@sladg/nextjs-lambda'

const sharpLayer = new LayerVersion(this, 'SharpDependenciesLayer', {
  code: Code.fromAsset(sharpLayerZipPath)
})

Next layer

To provide both image and server handlers with all depdencies (next is using require.resolve inside, so it cannot be bundled standalone for now).

We pre-package this layer so it can be included in Lambda without hassle.

import { nextLayerZipPath } from '@sladg/nextjs-lambda'

const nextLayer = new LayerVersion(this, 'NextDependenciesLayer', {
  code: Code.fromAsset(nextLayerZipPath)
})

Packaging

In order to succefully deploy, you firstly need to include target: 'standalone' in your next.config.js setup. Make sure to use NextJS in version 12 or above so this is properly supported.

Once target is set, you can go on and use your next build command as you normally would. To package everything, make sure to be in your project root folder and next folder .next and public exist. Packaging is done via NPM CLI command of @slack/nextjs-lambda package.

It will create next.out/ folder with 3 zip packages. One zip Lambda's code, one is dependencies layer and one is assets layer.

  • code zip: include all files generated by next that are required to run on Lambda behind ApiGateway. Original handler as well as new server handler are included. Use server-handler.handler for custom one or server.handler for original one.
  • dependencies layer: all transpilied node_modules. Next includes only used files, dramatically reducing overall size.
  • assets layer: your public folder together with generated assets. Keep in mind that to public refer file, you need to include it in public/assets/ folder, not just in public. This limitation dramatically simplifies whole setup. This zip file is uploaded to S3, it's not included in Lambda code.

Server handler

Custom wrapper around NextServer to allow for passing ApiGateway events into Next server.

Cloudfront paths used:

  • default
  • _next/data/*

Static assets

Next uses multiple directories to determine which file should be served. By default next provides us with list of routes for API/images/assets/pages. To simplify the process as much as possible, we are tapping into resulting paths.

We are packaging those assets to simulate output structure and we are using S3 behind CloudFront to serve those files. Also, Image Handler is tapping into S3 to provide images, so correct folder structure is crucial.

Cloudfront paths used:

  • _next/*
  • assets/*

Keep in minda, Cloudfront does not allow for multiple regex patterns in single origin, so using extensions to distinguish image/server handlers is not doable.

Versioning

This package exposes two CLI functions intended to deal with versioning your application and releasing.

Motivation behind is to get rid of huge dependencies and over-kill implementations such as @auto-it, release-it or semver. Those are bulky and unncessarily complex.

Guess

Simple CLI command that takes commit message and current version and outputs (stdout) next version based on keywords inside commit message.

Shipit

Similar to guess command, however, it automatically tags a commit on current branch and creates release branch for you so hooking up pipelines is as simple as it can be. Version is automatically bumped in common NPM and PHP files (package.json, package-lock.json and composer.json).

Simply call @sladg/next-lambda shipit on any branch and be done.

TODO

  • Move Next into peer dependency and build layer manually via npx. Parse next version from parent (allow parameter) to ensure compatibility with our implementation.
  • Move CDK into peer dependency and allow for CDK dependencies to not be used / to have version defined in upstream.

Disclaimer

At this point, advanced features were not tested with this setup. This includes:

  • GetServerSideProps,
  • middleware,
  • ISR and fallbacks,
  • streaming,
  • custom babel configuration.

I am looking for advanced projects implementing those features, so we can test them out! Reach out to me!