diff --git a/README.md b/README.md
index 2eb5b28..aae2949 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,45 @@ and is based on the following projects:
- [nextjs-fargate-demo](https://github.com/FormidableLabs/nextjs-fargate-demo): We deploy the same Next.js application.
- [aws-lambda-serverless-reference][]: The CloudFormation/Terraform infrastructure approach is basically identical to our reference Serverless project.
+### Goals
+
+The main goals of this demo project are as follows:
+
+1. **Slim down a Next.js Lambda deployment**: The Next.js `target: "serverless"` Node.js outputs are huge. Like really, really big because **each page** contains **all the dependencies**. This project adds a [custom externals handler](./server/util.js) to filter out almost all dependencies in `node_modules` and leave those as normal `require()` calls, thus dramatically decreasing the `pages` bundle sizes. The `node_modules` dependencies are included via `serverless-jetpack` trace mode to keep things tight.
+
+
+ If you want to see the difference, we've got an environment variable to skip the Node.js package external excludes, producing default bundles with tons of code per page. Try out the following to see (1) the size of the zip bundle and number of individual files in the zip, and a separate command to see (2) the size of the unzipped index page bundle.
+
+ ```sh
+ # Slimmer with packages in real node_modules and not bundle.
+ $ yarn clean && yarn build && yarn lambda:sls package --report
+ $ du -sh .serverless/blog.zip && zipinfo .serverless/blog.zip | wc -l
+ 2.1M .serverless/blog.zip
+ 1241
+ $ du -sh .next/serverless/pages/index.js
+ 52K .next/serverless/pages/index.js
+
+ # Bigger with packages in each page bundle
+ $ yarn clean && NEXT_SKIP_EXTERNALS=true yarn build && yarn lambda:sls package --report
+ $ du -sh .serverless/blog.zip && zipinfo .serverless/blog.zip | wc -l
+ 4.0M .serverless/blog.zip
+ 293
+ $ du -sh .next/serverless/pages/index.js
+ 2.7M .next/serverless/pages/index.js
+ ```
+
+ > ℹ️ **Note**: For a full optimization we'd probably want to see if we could split out application code that is shared across pages as well. For now, we're avoiding a big chunk of `node_modules`, which has a good punch for just 3 actual pages (plus supporting boilerplate).
+
+2. **Single Lambda/APIGW proxy**: `TODO(ROUTING): INSERT_NOTES`
+
+### Caveats
+
+Some caveats:
+
+1. **Static files**: To make this demo a whole lot easier to develop/deploy, we handle serve static assets _from_ the Lambda. This is not what you should do for a real application. Typically, you'll want to stick those assets in an S3 bucket behind a CDN or something. Look for the `TODO(STATIC)` comments variously throughout this repository to see all the shortcuts you should unwind to then reconfigure for static assets "the right way".
+2. **Deployment URL base path**: We have the Next.js blog up at sub-path `/blog`. A consumer app may go instead for root and that would simplify some of the code we have in this repo to make all the dev + prod experience work the same.
+3. **Lambda SSR + CDN**: Our React SSR hasn't been tuned at all yet for caching in the CDN like a real world app would want to do.
+
## Local development
Start with:
@@ -25,33 +64,51 @@ Start with:
$ yarn install
```
-### Next.js Development server
+Then we provide a lot of different ways to develop the server. Here is a table of options with current working status:
+
+| Command | Status | URL |
+| ----------------- | ------ | ---------------------------------------------- |
+| `dev` | works | http://127.0.0.1:3000/blog/ |
+| | works | http://127.0.0.1:3000/blog/posts/ssg-ssr |
+| `start` | works | http://127.0.0.1:4000/blog/ |
+| | fails | http://127.0.0.1:4000/blog/posts/ssg-ssr |
+| `lambda:localdev` | works | http://127.0.0.1:5000/blog/ |
+| | fails | http://127.0.0.1:5000/blog/posts/ssg-ssr |
+| _deployed_ | works | https://nextjs-sls-sandbox.formidable.dev/blog/ |
+| | fails | https://nextjs-sls-sandbox.formidable.dev/blog/posts/ssg-ssr |
+
+### Next.js Development server (3000)
+
+The built-in Next.js dev server, compilation and all.
```sh
$ yarn dev
```
-and visit: http://127.0.0.1:3000/
+and visit: http://127.0.0.1:3000/blog/
-### Serverless development server
+### Node.js production server (4000)
-This uses `serverless-offline` to simulate the application running on Lambda.
+We have a Node.js custom `express` server that uses _almost_ all of the Lambda code, which is sometimes an easier development experience that `serverless-offline`. This also could theoretically serve as a real production server on a bare metal or containerized compute instance outside of Lambda.
```sh
-$ yarn lambda:localdev
+$ yarn clean && yarn build
+$ yarn start
```
-and visit: http://127.0.0.1:4000/localdev/blog/
+and visit: http://127.0.0.1:4000/blog/
-### Next.js Production server
+### Lambda development server (5000)
-This repo _doesn't_ use the prod server, but if you want to create it, here you go:
+This uses `serverless-offline` to simulate the application running on Lambda.
```sh
-$ yarn build
-$ yarn start
+$ yarn clean && yarn build
+$ yarn lambda:localdev
```
+and visit: http://127.0.0.1:5000/blog/
+
## Deployment
We target AWS via a simple command line deploy. For a real world application, you'd want to have this deployment come from your CI/CD pipeline with things like per-PR deployments, etc. However, this demo is just here to validate Next.js running on Lambda, so get yer laptop running and fire away!
@@ -172,6 +229,10 @@ We use AWS IAM users with different privileges for these commands. `FIRST.LAST-a
is required (to effect the underlying CloudFormation changes).
```sh
+# Build for production.
+$ yarn clean && yarn build
+
+# Deploy
$ STAGE=sandbox aws-vault exec FIRST.LAST-admin -- \
yarn lambda:deploy
@@ -184,9 +245,11 @@ $ STAGE=sandbox aws-vault exec FIRST.LAST-admin -- \
See the [aws-lambda-serverless-reference][] docs for additional Serverless/Lambda (`yarn lambda:*`) tasks you can run.
-`yarn lambda:info` gives the current APIGW endpoints. As a useful helper we've separately hooked up a custom domain for `STAGE=sandbox` at:
+As a useful helper we've separately hooked up a custom domain for `STAGE=sandbox` at:
https://nextjs-sls-sandbox.formidable.dev/blog/
+> ℹ️ **Note**: We set `BASE_PATH` to `/blog` and _not_ `/${STAGE}/blog` like API Gateway does for internal endpoints for our references to other static assets. It's kind of a moot point because frontend assets shouldn't be served via Lambda/APIGW like we do for this demo, but just worth noting that the internal endpoints will have incorrect asset paths.
+
[aws-lambda-serverless-reference]: https://github.com/FormidableLabs/aws-lambda-serverless-reference
[aws-vault]: https://github.com/99designs/aws-vault
diff --git a/components/layout.js b/components/layout.js
index 7c0f470..a9bf99a 100644
--- a/components/layout.js
+++ b/components/layout.js
@@ -10,6 +10,7 @@ export default function Layout({ children, home }) {
return (
+ {/* TODO: Favicon will need separately asset handling to be at root slot. */}
@@ -39,7 +40,7 @@ export default function Layout({ children, home }) {
diff --git a/lib/posts.js b/lib/posts.js
index 53d8653..28574c2 100644
--- a/lib/posts.js
+++ b/lib/posts.js
@@ -1,21 +1,25 @@
import fs from 'fs'
+import { promisify } from 'util'
import path from 'path'
import matter from 'gray-matter'
import remark from 'remark'
import html from 'remark-html'
+const readdir = promisify(fs.readdir);
+const readFile = promisify(fs.readFile);
const postsDirectory = path.join(process.cwd(), 'posts')
-export function getSortedPostsData() {
+export async function getSortedPostsData() {
// Get file names under /posts
- const fileNames = fs.readdirSync(postsDirectory)
- const allPostsData = fileNames.map(fileName => {
+ const fileNames = await readdir(postsDirectory)
+ const allPostsData = await Promise.all(fileNames.map(async fileName => {
// Remove ".md" from file name to get id
const id = fileName.replace(/\.md$/, '')
// Read markdown file as string
const fullPath = path.join(postsDirectory, fileName)
- const fileContents = fs.readFileSync(fullPath, 'utf8')
+ // TODO: On not found, wrap ENOENT and push back to a 404.
+ const fileContents = await readFile(fullPath, 'utf8')
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents)
@@ -25,7 +29,7 @@ export function getSortedPostsData() {
id,
...matterResult.data
}
- })
+ }))
// Sort posts by date
return allPostsData.sort((a, b) => {
if (a.date < b.date) {
@@ -36,8 +40,8 @@ export function getSortedPostsData() {
})
}
-export function getAllPostIds() {
- const fileNames = fs.readdirSync(postsDirectory)
+export async function getAllPostIds() {
+ const fileNames = await readdir(postsDirectory)
return fileNames.map(fileName => {
return {
params: {
@@ -49,7 +53,7 @@ export function getAllPostIds() {
export async function getPostData(id) {
const fullPath = path.join(postsDirectory, `${id}.md`)
- const fileContents = fs.readFileSync(fullPath, 'utf8')
+ const fileContents = await readFile(fullPath, 'utf8')
// Use gray-matter to parse the post metadata section
const matterResult = matter(fileContents)
diff --git a/next.config.js b/next.config.js
new file mode 100644
index 0000000..5e22f47
--- /dev/null
+++ b/next.config.js
@@ -0,0 +1,34 @@
+"use strict";
+
+const { nextExternals } = require("./server/util");
+
+// **NOTE**: We set a base path that assumes Lambda staging _and_ our
+// APIGW proxy base path (of `blog` by default). Many real world apps will
+// just have a root base path and it's probably easier than this.
+const { BASE_PATH, NEXT_SKIP_EXTERNALS = "false" } = process.env;
+if (!BASE_PATH) {
+ throw new Error("BASE_PATH is required");
+}
+
+module.exports = {
+ target: "serverless",
+ basePath: BASE_PATH,
+ assetPrefix: BASE_PATH,
+ env: {
+ BASE_PATH
+ },
+ webpack: (config, { isServer }) => {
+ if (isServer) {
+ // Add more information in the bundle.
+ config.output.pathinfo = true;
+
+ // TODO: Replace with `webpack-next-externals` when ready.
+ // // Keep `node_modules` as runtime requires to help slim down page bundles.
+ // config.externals = (config.externals || []).concat(
+ // NEXT_SKIP_EXTERNALS === "true" ? [] : nextExternals()
+ // );
+ }
+
+ return config;
+ }
+};
diff --git a/package.json b/package.json
index d32f970..8ca134b 100644
--- a/package.json
+++ b/package.json
@@ -8,10 +8,11 @@
"license": "MIT",
"private": true,
"scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "env": "echo export STAGE=${STAGE:-localdev}; echo export SERVICE_NAME=nextjs-serverless; echo export AWS_REGION=${AWS_REGION:-us-east-1}; echo export AWS_XRAY_CONTEXT_MISSING=LOG_ERROR",
+ "dev": "eval $(yarn -s env) && next dev",
+ "clean": "rm -rf .next",
+ "build": "eval $(yarn -s env) && next build",
+ "start": "eval $(yarn -s env) && node server/index.js",
+ "env": "echo export STAGE=${STAGE:-localdev}; echo export BASE_PATH=${BASE_PATH:-/blog}; echo export SERVICE_NAME=nextjs-serverless; echo export AWS_REGION=${AWS_REGION:-us-east-1}; echo export AWS_XRAY_CONTEXT_MISSING=LOG_ERROR",
"cf:_params": "eval $(yarn -s env) && echo --parameters ParameterKey=Stage,ParameterValue=${STAGE} ParameterKey=ServiceName,ParameterValue=${SERVICE_NAME}",
"cf:bootstrap:_stack": "eval $(yarn -s env) && echo --region ${AWS_REGION} --stack-name cf-${SERVICE_NAME}-${STAGE}-bootstrap",
"cf:bootstrap:_tmpl": "echo --template-body file://aws/bootstrap.yml ",
@@ -30,7 +31,7 @@
"tf:service:apply": "yarn run tf:terraform apply $(yarn -s tf:service:_vars)",
"tf:service:_delete": "yarn run tf:terraform destroy $(yarn -s tf:service:_vars)",
"lambda:sls": "eval $(yarn -s env) && sls -s ${STAGE}",
- "lambda:localdev": "yarn run lambda:sls offline start --httpPort ${SERVER_PORT:-4000} --host ${SERVER_HOST:-0.0.0.0}",
+ "lambda:localdev": "yarn run lambda:sls offline start --httpPort ${SERVER_PORT:-5000} --host ${SERVER_HOST:-0.0.0.0} --noPrependStageInUrl",
"lambda:deploy": "yarn run lambda:sls deploy",
"lambda:info": "yarn run lambda:sls info",
"lambda:logs": "yarn run lambda:sls logs",
@@ -40,16 +41,18 @@
},
"dependencies": {
"date-fns": "^2.11.1",
+ "express": "^4.17.1",
"gray-matter": "^4.0.2",
"next": "^10.0.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"remark": "^12.0.0",
- "remark-html": "^12.0.0"
+ "remark-html": "^12.0.0",
+ "serverless-http": "^2.7.0"
},
"devDependencies": {
"serverless": "^2.21.1",
- "serverless-jetpack": "^0.10.7",
+ "serverless-jetpack": "^0.10.8",
"serverless-offline": "^6.8.0"
}
}
diff --git a/pages/index.js b/pages/index.js
index f09aed3..7c5762c 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -5,6 +5,12 @@ import { getSortedPostsData } from '../lib/posts'
import Link from 'next/link'
import Date from '../components/date'
+// TODO: This _shouldn't need BASE_PATH as next/link is supposed to handle it.
+const isServer = () => {
+ return typeof window === "undefined";
+};
+const LINK_BASE = isServer() ? process.env.BASE_PATH : "";
+
export default function Home({ allPostsData }) {
return (
@@ -23,7 +29,8 @@ export default function Home({ allPostsData }) {
{allPostsData.map(({ id, date, title }) => (
-
+ {/* */}
+
{title}
@@ -39,7 +46,7 @@ export default function Home({ allPostsData }) {
}
export async function getStaticProps() {
- const allPostsData = getSortedPostsData()
+ const allPostsData = await getSortedPostsData()
return {
props: {
allPostsData
diff --git a/pages/posts/[id].js b/pages/posts/[id].js
index 28faaad..cebdf19 100644
--- a/pages/posts/[id].js
+++ b/pages/posts/[id].js
@@ -22,7 +22,7 @@ export default function Post({ postData }) {
}
export async function getStaticPaths() {
- const paths = getAllPostIds()
+ const paths = await getAllPostIds()
return {
paths,
fallback: false
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 0000000..5cfea92
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,157 @@
+"use strict";
+
+const fs = require("fs").promises;
+const path = require("path");
+const express = require("express");
+
+const manifests = {
+ routes: require("../.next/routes-manifest.json"),
+ pages: require("../.next/serverless/pages-manifest.json")
+};
+
+const DEFAULT_PORT = 4000;
+const PORT = parseInt(process.env.SERVER_PORT || DEFAULT_PORT, 10);
+const HOST = process.env.SERVER_HOST || "0.0.0.0";
+
+// TODO: REMOVE THIS AND USE MANIFEST???
+// Set up base path for both Node.js and Lambda.
+const { BASE_PATH } = process.env;
+if (typeof BASE_PATH === "undefined") {
+ throw new Error("BASE_PATH is required");
+}
+
+// Next locations.
+const NEXT_DIR = path.resolve(__dirname, "../.next");
+const NEXT_SLS_DIR = path.join(NEXT_DIR, "serverless");
+const NEXT_PAGES_DIR = path.join(NEXT_SLS_DIR, "pages");
+const NEXT_PUBLIC_DIR = path.resolve(__dirname, "../public");
+
+// Send response.
+const sendPage = ({ pagePath, req, res }) => {
+ const fullPath = path.join(NEXT_SLS_DIR, pagePath);
+ if (fullPath.endsWith(".html")) {
+ return res.sendFile(fullPath);
+ }
+
+ if (fullPath.endsWith(".js")) {
+ const page = require(fullPath);
+ return page.render(req, res);
+ }
+
+ throw new Error(`Unknown page format: ${pagePath}`);
+};
+
+// Create the server app.
+const getApp = async () => {
+ // Normalize appRoot.
+ const appRoot = BASE_PATH.replace(/\/*$/, "");
+
+ // Build stuff.
+ const NEXT_APP_ROOT = `${appRoot}/_next`;
+ const BUILD_ID = (await fs.readFile(path.join(NEXT_DIR, "BUILD_ID"))).toString().trim();
+ const NEXT_DATA_ROOT = `${NEXT_APP_ROOT}/data/${BUILD_ID}`;
+
+ // Stage, base path stuff.
+ const app = express();
+
+ // Development tweaks.
+ app.set("json spaces", 2);
+
+ // TODO(STATIC): For this demo only, we just handle serve static content
+ // directly through the express app. For a real app, you'll want to deploy
+ // static contents to somewhere to be directly served by the CDN.
+ app.use(`${NEXT_APP_ROOT}/static`, express.static(path.join(NEXT_DIR, "static")));
+
+ // Manually proxy JSON data requests to file system.
+ // _next/data/y-BRZHyY6b_T25zMSRPY0/posts/ssg-ssr.json ->
+ // _next/serverless/posts/ssg-ssr.json
+ //
+ // TODO(STATIC): This _also_ could be uploaded to a real static serve.
+ // It technically _could_ change from data, so possibly disable SSG and
+ // make this always dynamically generated.
+ app.get(`${NEXT_DATA_ROOT}/*`, (req, res, next) => {
+ // Only handle JSON.
+ if (req.url.endsWith(".json")) {
+ const filePath = req.url.replace(NEXT_DATA_ROOT, NEXT_PAGES_DIR);
+ return res.sendFile(filePath);
+ }
+
+ return next();
+ });
+
+ // Page handlers,
+ app.all(`${appRoot}(/*)?`, (req, res, next) => {
+ // Remove app root or switch to root ("/").
+ const relPath = req.url.replace(appRoot, "") || "/";
+
+ // Direct page match
+ let pagePath = manifests.pages[relPath];
+
+ // Dynamic routes
+ manifests.routes.dynamicRoutes.forEach(({ page, namedRegex }) => {
+ if (!pagePath && new RegExp(namedRegex).exec(relPath)) {
+ pagePath = manifests.pages[page];
+ }
+ });
+
+ // Render
+ if (pagePath) {
+ return sendPage({ pagePath, req, res });
+ }
+
+ return next();
+ });
+
+ // TODO(STATIC): User-added static assets. Should not be in Lambda.
+ app.use(`${appRoot}/`, express.static(NEXT_PUBLIC_DIR));
+
+ // Not found handling.
+ app.use((req, res) => sendPage({
+ pagePath: manifests.pages["/404"],
+ req,
+ res: res.status(404)
+ }));
+
+ // Error handler.
+ app.use((err, req, res, next) => {
+ console.error(err.stack);
+ return sendPage({
+ pagePath: manifests.pages["/_error"],
+ req,
+ res: res.status(500)
+ });
+ });
+
+ return app;
+};
+
+// LAMBDA: Export handler for lambda use.
+let handler;
+module.exports.handler = async (event, context) => {
+ // Lazy require `serverless-http` to allow non-Lambda targets to omit.
+ // eslint-disable-next-line global-require
+ handler = handler || require("serverless-http")(
+ await getApp(),
+ // TODO(STATIC): Again, shouldn't be serving images from the Lambda :)
+ {
+ binary: ["image/*"]
+ }
+ );
+
+ return handler(event, context);
+};
+
+// DOCKER/DEV/ANYTHING: Start the server directly.
+if (require.main === module) {
+ (async () => {
+ const server = (await getApp()).listen({
+ port: PORT,
+ host: HOST
+ }, () => {
+ const { address, port } = server.address();
+
+ // eslint-disable-next-line no-console
+ console.log(`Server started at http://${address}:${port}`);
+ });
+ })();
+}
diff --git a/server/util.js b/server/util.js
new file mode 100644
index 0000000..530f6a0
--- /dev/null
+++ b/server/util.js
@@ -0,0 +1,118 @@
+"use strict";
+
+const path = require("path");
+
+// ----------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------
+//
+// TODO: These are cribbed/tweaked from `trace-deps`. Should abstract / test / something.
+
+// Simple conversion to produce Linux/Mac style forward slash-based paths.
+const toPosix = (file) => !file ? file : file.replace(/\\/g, "/");
+
+// Extract top-level package name + relative file path from full path.
+//
+// E.g., `["pkg2", "index.js"]` =>
+// {
+// name: "pkg2",
+// file: pkg2/index.js
+// }
+const getPackageFromParts = (parts = []) => {
+ // Get first part of package.
+ const firstPart = parts[0];
+ if (!firstPart) { return null; }
+
+ // Default to unscoped.
+ let name = firstPart;
+ if (firstPart[0] === "@") {
+ // Detect if scoped and adjust / short-circuit if no match.
+ const secondPart = parts[1]; // eslint-disable-line no-magic-numbers
+ if (!secondPart) { return null; }
+
+ // Use posix path.
+ name = [firstPart, secondPart].join("/");
+ }
+
+ return {
+ name,
+ file: parts.join(path.sep)
+ };
+};
+
+// NOTE: Unused for now. In case we want context parsing, this is useful.
+const getPackageFromContext = (context = "") => {
+ const parts = toPosix(path.normalize(context)).split("/");
+ const nodeModulesIdx = parts.lastIndexOf("node_modules");
+ if (nodeModulesIdx === -1) { return null; }
+
+ return getPackageFromParts(parts.slice(nodeModulesIdx + 1));
+};
+
+const REQUEST_SKIP_LIST = [
+ // Loaders and synthetic files.
+ /^next-serverless-loader(\?|\/|$)/,
+ /^next-plugin-loader(\?|\/|$)/,
+ /^private-dot-next(\?|\/|$)/,
+ /^private-next-pages(\?|\/|$)/,
+
+ // This doesn't have an export and just patches Node.js `global`.
+ "next/dist/next-server/server/node-polyfill-fetch"
+];
+const getPackageFromRequest = (request = "") => {
+ // Must start with a valid package prefix. Notably, not:
+ // - Relative: `./foo.js`
+ // - Absolute: `/PATH/TO/foo.js`
+ if (!(/^[\@a-zA-Z]+/).test(request)) {
+ return null;
+ }
+
+ // TODO: Can we just infer all loaders/plugins that are needed at build-time?
+ // Skip Next.js loaders and things that need to be built in.
+ if (REQUEST_SKIP_LIST.some(
+ (strOrRe) => typeof strOrRe === "string" ? request.startsWith(strOrRe) : strOrRe.test(request)
+ )) {
+ return null;
+ }
+
+ const parts = toPosix(path.normalize(request)).split("/");
+ return getPackageFromParts(parts);
+};
+
+// ----------------------------------------------------------------------------
+// Exports
+// ----------------------------------------------------------------------------
+
+// Exclude all of node_modules with certain exceptions for Next.js
+// common usage.
+//
+// Modeled after: https://github.com/liady/webpack-node-externals
+// See: https://webpack.js.org/configuration/externals/#function
+//
+// Notes:
+// 1. **WARNING**: This is an incomplete solution for now. The list in
+// REQUEST_SKIP_LIST need to be either generalized to "all webpack
+// loaders" and/or configuration overrides need to be passed in as options.
+const nextExternals = () => (...args) => {
+ // Handle all versions of webpack externals function signature.
+ const isWebpack5 = !!(args[0] && args[0].context && args[0].request);
+ const context = isWebpack5 ? args[0].context : args[0];
+ const request = isWebpack5 ? args[0].request : args[1];
+ const callback = args[isWebpack5 ? 3 : 2];
+
+ // Somewhat different from `webpack-node-externals` we use `context` to
+ // find things in `node_modules` that we should exclude in addition to
+ // the module name itself. And we don't actually scan `node_modules`.
+ const requestPkg = getPackageFromRequest(request);
+ const externalName = requestPkg ? requestPkg.file : null;
+ if (externalName !== null) {
+ return void callback(null, `commonjs ${externalName}`);
+ }
+
+ callback();
+};
+
+
+module.exports = {
+ nextExternals
+};
diff --git a/serverless.yml b/serverless.yml
index 4e6b75c..43c550e 100644
--- a/serverless.yml
+++ b/serverless.yml
@@ -1,6 +1,9 @@
# CloudFormation output name: `sls-${SERVICE_NAME}-${STAGE}`
service: sls-${self:custom.service}
+package:
+ individually: true
+
custom:
service: ${env:SERVICE_NAME}
region: ${opt:region, env:AWS_REGION}
@@ -9,10 +12,45 @@ custom:
preInclude:
- "!**" # Start with no files at all.
trace:
- # Use trace mode for speed and ignore aws-sdk + all deps
ignores:
+ # Provided on Lambda
- "aws-sdk"
+ # Ignore real deps in Next.js that we shouldn't need at runtime.
+ - "webpack"
+ - "sass-loader"
+ - "pnp-webpack-plugin"
+
+ # Ignore some build time webpack-y things.
+ - "next-plugin-loader?middleware=document-head-tags-server!"
+
+ allowMissing:
+ "node-fetch":
+ - "encoding"
+ "next":
+ - "critters" # for CSS optimization
+ - "pnpapi" # for PnP usage
+
+ dynamic:
+ resolutions:
+ # Our server does lazy requires of pages.
+ "./server/index.js": []
+
+ # [169:22]: require(`./transformers/${Transformer}.js`)
+ "@ampproject/toolbox-optimizer/lib/DomTransformer.js": []
+
+ # express/lib/view.js [81:13]: require(mod)
+ "express/lib/view.js": []
+
+ # Next.js lazy-loading of manifests and server page bundles.
+ # next/dist/next-server/server/load-components.js [1:1034]: require((0,_path.join)(distDir,_constants.BUILD_MANIFEST))
+ # next/dist/next-server/server/load-components.js [1:1093]: require((0,_path.join)(distDir,_constants.REACT_LOADABLE_MANIFEST))
+ "next/dist/next-server/server/load-components.js": []
+ # next/dist/next-server/server/require.js [1:656]: require((0,_path.join)(serverBuildPath,_constants.PAGES_MANIFEST))
+ # next/dist/next-server/server/require.js [1:1183]: require(pagePath)
+ # next/dist/next-server/server/require.js [1:1387]: require((0,_path.join)(serverBuildPath,_constants.FONT_MANIFEST))
+ "next/dist/next-server/server/require.js": []
+
plugins:
- serverless-jetpack
- serverless-offline
@@ -44,10 +82,32 @@ provider:
Stage: ${self:custom.stage}
Service: ${self:custom.service}
+ # TODO(STATIC): Allows serving of binary media. Shouldn't use this for real.
+ apiGateway:
+ binaryMediaTypes:
+ - "*/*"
+
functions:
# SCENARIO - base: The simplest, vanilla Serverless app.
blog:
- handler: temp/index.handler # TODO: REPLACE WITH NEXT APP
+ handler: server/index.handler
+ environment:
+ BASE_PATH: /blog
events: # Use a generic proxy to allow Express app to route.
- http: ANY /blog
- http: 'ANY /blog/{proxy+}'
+ package:
+ trace:
+ include:
+ # Next.js-generated files: gather dependencies
+ - ".next/serverless/**/*.js"
+ include:
+ # Raw data for posts is read from disk outside `.next` build directory.
+ - "posts/**/*.md"
+ # Needed built Next.js assets and info. (Some of these are also traced).
+ - ".next/BUILD_ID"
+ - ".next/*.json"
+ - ".next/serverless/**"
+ # TODO(STATIC): Add a note about this.
+ - ".next/static/**"
+ - "public/**"
diff --git a/yarn.lock b/yarn.lock
index 7b68e50..ffd1f2e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -825,6 +825,11 @@
request "^2.88.0"
request-promise-native "^1.0.8"
+"@types/aws-lambda@^8.10.56":
+ version "8.10.71"
+ resolved "https://registry.yarnpkg.com/@types/aws-lambda/-/aws-lambda-8.10.71.tgz#ab3084038411ce42f63b975e67aafb163f3aa353"
+ integrity sha512-l0Lag6qq06AlKllprAJ3pbgVUbXCjRGRb7VpHow8IMn2BMHTPR0t5OD97/w8CR1+wA5XZuWQoXLjYvdlk2kQrQ==
+
"@types/cacheable-request@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
@@ -883,9 +888,9 @@
"@types/unist" "*"
"@types/minimatch@*":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
- integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
+ integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
"@types/node@*":
version "14.14.22"
@@ -1098,6 +1103,14 @@ abort-controller@3.0.0:
dependencies:
event-target-shim "^5.0.0"
+accepts@~1.3.7:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+ integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+ dependencies:
+ mime-types "~2.1.24"
+ negotiator "0.6.2"
+
acorn-node@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-2.0.1.tgz#4a93ba32335950da9250175c654721f20f3375a7"
@@ -1345,6 +1358,11 @@ arr-union@^3.1.0:
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
array-flatten@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-3.0.0.tgz#6428ca2ee52c7b823192ec600fa3ed2f157cd541"
@@ -1624,6 +1642,22 @@ bn.js@^5.0.0, bn.js@^5.1.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
+body-parser@1.19.0:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+ integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+ dependencies:
+ bytes "3.1.0"
+ content-type "~1.0.4"
+ debug "2.6.9"
+ depd "~1.1.2"
+ http-errors "1.7.2"
+ iconv-lite "0.4.24"
+ on-finished "~2.3.0"
+ qs "6.7.0"
+ raw-body "2.4.0"
+ type-is "~1.6.17"
+
boxen@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
@@ -2400,13 +2434,18 @@ constants-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
-content-disposition@^0.5.2:
+content-disposition@0.5.3, content-disposition@^0.5.2:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
dependencies:
safe-buffer "5.1.2"
+content-type@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+ integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
convert-source-map@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
@@ -2419,6 +2458,16 @@ convert-source-map@^0.3.3:
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190"
integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA=
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+ integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
cookiejar@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c"
@@ -2659,6 +2708,13 @@ dayjs@^1.10.4:
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2"
integrity sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==
+debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
debug@4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
@@ -2666,13 +2722,6 @@ debug@4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
dependencies:
ms "2.1.2"
-debug@^2.1.3, debug@^2.2.0, debug@^2.3.3:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
debug@^3.1.0, debug@^3.1.1:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@@ -2849,6 +2898,11 @@ des.js@^1.0.0:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
+destroy@~1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+ integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
@@ -3033,6 +3087,11 @@ ecdsa-sig-formatter@1.0.11:
dependencies:
safe-buffer "^5.0.1"
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
electron-to-chromium@^1.3.585:
version "1.3.645"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.645.tgz#c0b269ae2ecece5aedc02dd4586397d8096affb1"
@@ -3078,6 +3137,11 @@ enabled@1.0.x:
dependencies:
env-variable "0.0.x"
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -3238,6 +3302,11 @@ escape-goat@^2.0.0:
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@@ -3291,7 +3360,7 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-etag@1.8.1:
+etag@1.8.1, etag@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
@@ -3370,6 +3439,42 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
+express@^4.17.1:
+ version "4.17.1"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+ integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+ dependencies:
+ accepts "~1.3.7"
+ array-flatten "1.1.1"
+ body-parser "1.19.0"
+ content-disposition "0.5.3"
+ content-type "~1.0.4"
+ cookie "0.4.0"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "~1.1.2"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "~1.1.2"
+ fresh "0.5.2"
+ merge-descriptors "1.0.1"
+ methods "~1.1.2"
+ on-finished "~2.3.0"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.7"
+ proxy-addr "~2.0.5"
+ qs "6.7.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.1.2"
+ send "0.17.1"
+ serve-static "1.14.1"
+ setprototypeof "1.1.1"
+ statuses "~1.5.0"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
ext-list@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
@@ -3593,6 +3698,19 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
+finalhandler@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+ integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.3"
+ statuses "~1.5.0"
+ unpipe "~1.0.0"
+
find-cache-dir@3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880"
@@ -3685,6 +3803,11 @@ formidable@^1.2.0:
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9"
integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==
+forwarded@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+ integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
fragment-cache@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
@@ -3692,6 +3815,11 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
from2@^2.1.0, from2@^2.1.1:
version "2.3.0"
resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
@@ -4201,7 +4329,18 @@ http-cache-semantics@^4.0.0:
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
-http-errors@1.7.3:
+http-errors@1.7.2:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+ integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.1"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.0"
+
+http-errors@1.7.3, http-errors@~1.7.2:
version "1.7.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
@@ -4419,6 +4558,11 @@ into-stream@^3.1.0:
from2 "^2.1.1"
p-is-promise "^1.1.0"
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
is-accessor-descriptor@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
@@ -4492,7 +4636,7 @@ is-ci@^2.0.0:
dependencies:
ci-info "^2.0.0"
-is-core-module@^2.1.0:
+is-core-module@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
@@ -5403,6 +5547,11 @@ mdurl@^1.0.0:
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
mem@^6.0.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/mem/-/mem-6.1.1.tgz#ea110c2ebc079eca3022e6b08c85a795e77f6318"
@@ -5441,6 +5590,11 @@ memory-fs@^0.5.0:
errno "^0.1.3"
readable-stream "^2.0.1"
+merge-descriptors@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+ integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -5451,7 +5605,7 @@ merge2@^1.2.3, merge2@^1.3.0:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-methods@^1.1.1:
+methods@^1.1.1, methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
@@ -5496,14 +5650,14 @@ mime-db@1.45.0, mime-db@1.x.x, mime-db@^1.28.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.45.0.tgz#cceeda21ccd7c3a745eba2decd55d4b73e7879ea"
integrity sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==
-mime-types@^2.1.12, mime-types@~2.1.19:
+mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.28"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.28.tgz#1160c4757eab2c5363888e005273ecf79d2a0ecd"
integrity sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==
dependencies:
mime-db "1.45.0"
-mime@^1.4.1:
+mime@1.6.0, mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
@@ -5645,6 +5799,11 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+ms@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+ integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@@ -5727,6 +5886,11 @@ ncjsm@^4.1.0:
fs2 "^0.3.8"
type "^2.0.0"
+negotiator@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+ integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
@@ -6006,6 +6170,13 @@ object.pick@^1.3.0:
dependencies:
isobject "^3.0.1"
+on-finished@~2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+ integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+ dependencies:
+ ee-first "1.1.1"
+
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -6232,6 +6403,11 @@ parseuri@0.0.6:
resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a"
integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==
+parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
pascalcase@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
@@ -6290,6 +6466,11 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+path-to-regexp@0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+ integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -6611,6 +6792,14 @@ protobufjs@^6.9.0:
"@types/node" "^13.7.0"
long "^4.0.0"
+proxy-addr@~2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
+ integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
+ dependencies:
+ forwarded "~0.1.2"
+ ipaddr.js "1.9.1"
+
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -6693,6 +6882,11 @@ qrcode-terminal@^0.12.0:
resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==
+qs@6.7.0:
+ version "6.7.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
+ integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+
qs@^6.5.1:
version "6.9.6"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee"
@@ -6757,6 +6951,21 @@ randomfill@^1.0.3:
randombytes "^2.0.5"
safe-buffer "^5.1.0"
+range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+ integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+ dependencies:
+ bytes "3.1.0"
+ http-errors "1.7.2"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
raw-body@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c"
@@ -7031,11 +7240,11 @@ resolve-url@^0.2.1:
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
resolve@^1.19.0:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c"
- integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
+ version "1.20.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
+ integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
- is-core-module "^2.1.0"
+ is-core-module "^2.2.0"
path-parse "^1.0.6"
responselike@1.0.2, responselike@^1.0.2:
@@ -7267,6 +7476,25 @@ semver@^7.1.3, semver@^7.3.2, semver@^7.3.4:
dependencies:
lru-cache "^6.0.0"
+send@0.17.1:
+ version "0.17.1"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+ integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+ dependencies:
+ debug "2.6.9"
+ depd "~1.1.2"
+ destroy "~1.0.4"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "~1.7.2"
+ mime "1.6.0"
+ ms "2.1.1"
+ on-finished "~2.3.0"
+ range-parser "~1.2.1"
+ statuses "~1.5.0"
+
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
@@ -7274,10 +7502,27 @@ serialize-javascript@^4.0.0:
dependencies:
randombytes "^2.1.0"
-serverless-jetpack@^0.10.7:
- version "0.10.7"
- resolved "https://registry.yarnpkg.com/serverless-jetpack/-/serverless-jetpack-0.10.7.tgz#2eadba6b66807224bf05e447247bbdea6bc2a7c8"
- integrity sha512-Ra/6Swp86fGq7XxCyhQMVpCA+EYjdmJnClNBK2aQoSzDSc9c7iQ6J/5RG6RjcgDRp1K/oNbMkhgLfQjyJuKfHw==
+serve-static@1.14.1:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+ integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+ dependencies:
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.17.1"
+
+serverless-http@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/serverless-http/-/serverless-http-2.7.0.tgz#352ca38cbbba58dc71dcfb11bb27c92c3c81fe69"
+ integrity sha512-iWq0z1X2Xkuvz6wL305uCux/SypbojHlYsB5bzmF5TqoLYsdvMNIoCsgtWjwqWoo3AR2cjw3zAmHN2+U6mF99Q==
+ optionalDependencies:
+ "@types/aws-lambda" "^8.10.56"
+
+serverless-jetpack@^0.10.8:
+ version "0.10.8"
+ resolved "https://registry.yarnpkg.com/serverless-jetpack/-/serverless-jetpack-0.10.8.tgz#61ddc35a9562b2ce287a079afa8ce8ca68fbedf9"
+ integrity sha512-QlDoC7RMD791KptkD1/mDJfH+x07iuy/qnWitEAIfPO/2SlDOxFknZqB/eG3bdIRCCjYCuqT/ffbXt9ysmWNuw==
dependencies:
archiver "^3.1.1"
globby "^9.2.0"
@@ -7286,7 +7531,7 @@ serverless-jetpack@^0.10.7:
make-dir "^3.0.2"
nanomatch "^1.2.13"
p-limit "^2.3.0"
- trace-deps "^0.3.3"
+ trace-deps "^0.3.8"
serverless-offline@^6.8.0:
version "6.8.0"
@@ -7752,7 +7997,7 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"
-"statuses@>= 1.5.0 < 2":
+"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
@@ -8259,10 +8504,10 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
-trace-deps@^0.3.3:
- version "0.3.7"
- resolved "https://registry.yarnpkg.com/trace-deps/-/trace-deps-0.3.7.tgz#940a1c4358dfda2fdd3e3f2c51563d7b69628ee2"
- integrity sha512-R4scNNMV/+/l+pbPHvF6mmh4/4UnAT4GwGr8ColzlaqJwroLtxbg0xHEC7fFoKcKXxKepAion+nry7fy9Nq0Tg==
+trace-deps@^0.3.8:
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/trace-deps/-/trace-deps-0.3.9.tgz#85714d19444d67bd28bc9447919fa68655f744ef"
+ integrity sha512-85uDbKTm4ygcLCcnHO7FfchgrXi24s5bLloptSx565kblrv9lbaBi/bnWLEkLk2FHEC7m0BJb4QoOoshoSs9LQ==
dependencies:
acorn-node "^2.0.1"
resolve "^1.19.0"
@@ -8351,6 +8596,14 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+type-is@~1.6.17, type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
type@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
@@ -8498,7 +8751,7 @@ universalify@^2.0.0:
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
-unpipe@1.0.0:
+unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
@@ -8623,6 +8876,11 @@ util@^0.11.0:
dependencies:
inherits "2.0.3"
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
uuid@3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
@@ -8638,6 +8896,11 @@ uuid@^8.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
velocityjs@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/velocityjs/-/velocityjs-2.0.3.tgz#cc772f687061997127b7d8a827dbef3af8a0bbe6"