Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deploy next.js 9 to AWS Lambda without using Serverless Components

I would like to simply deploy my Next.js 9 to AWS Lambdas using just API Gateway in front and make a proxy to the static path pointing to S3, but the only available option (without having to write all the stuff from the scratch) is https://github.com/serverless-nextjs/serverless-next.js which is currently using a beta version of Serverless Components (very buggy and lack of control over resources created as it does not uses CloudFormation), also this SLS Component forces the user to use CloudFront which is not my need, I have PR environments created all the time and allocating CloudFront for that is just waste of time/money/resources.

I tried to use the old version of the plugin serverless-nextjs-plugin but it seems not to work with Next.js 9, it fails to create the Lambdas for .html generated pages.

Is there any light in the end of this tunnel?

https://github.com/serverless-nextjs/serverless-next.js/issues/296 by this issue it looks like there's no way to do that.

like image 311
Marcelo Luiz Onhate Avatar asked Oct 07 '20 17:10

Marcelo Luiz Onhate


1 Answers

I managed to make it work

serverless.base.yml file:

service: my-app

provider:
  name: aws
  runtime: nodejs12.x
  timeout: 10 # seconds
  memorySize: 1792 # Mb

custom:
  webpack:
    packager: yarn
    includeModules:
      forceInclude:
        - chalk

functions:
  nextJsApp:
    handler: server.handler
    events:
      - http: 'ANY /'
      - http: 'ANY {proxy+}'

server.js:

const { parse } = require('url');
const next = require('next');
const serverless = require('serverless-http');

const app = next({
  dev: false
});

const requestHandler = app.getRequestHandler();

export const handler = serverless(async (req, res) => {
  const parsedUrl = parse(req.url, true);
  await requestHandler(req, res, parsedUrl);
});

wepback.config.js:

const CopyWebpackPlugin = require('copy-webpack-plugin');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  ...

  externals: [nodeExternals()],
  plugins: [
    new CopyWebpackPlugin({
      patterns: [
        { from: '.next', to: '.next' },
        { from: 'public', to: 'public' }
      ]
    })
  ]
};

and here is the trick for working with serverless and webpack, use a serverless.js that modifies the serverless.base.yml and add all dependencies to the required dependencies to be included in the bundle:

const yaml = require('yaml-boost');
const minimist = require('minimist');
const path = require('path');

module.exports = (() => {
  const params = minimist(process.argv.slice(2));
  const serverless = yaml.load(path.join(__dirname, 'serverless.base.yml'), params);
  const packageJson = require(path.join(__dirname, 'package.json'));

  const dependencies = Object.keys(packageJson.dependencies);
  serverless.custom.webpack.includeModules.forceInclude.push(...dependencies);
  return serverless;
})();
like image 187
Marcelo Luiz Onhate Avatar answered Oct 21 '22 00:10

Marcelo Luiz Onhate