From b070fbf91099edcbf72d107998b0389c7acd8a92 Mon Sep 17 00:00:00 2001 From: Denis Grankin Date: Thu, 27 Aug 2020 15:24:52 +0300 Subject: [PATCH 001/451] Fixes for shared distribution --- .../lambda-at-edge/src/default-handler.ts | 2 +- .../aws-cloudfront/lib/index.js | 18 +++++-- .../nextjs-component/src/component.ts | 48 ++++++++++++------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/packages/libs/lambda-at-edge/src/default-handler.ts b/packages/libs/lambda-at-edge/src/default-handler.ts index f95c80bea6..e92e66b5c8 100644 --- a/packages/libs/lambda-at-edge/src/default-handler.ts +++ b/packages/libs/lambda-at-edge/src/default-handler.ts @@ -48,7 +48,7 @@ const isDataRequest = (uri: string): boolean => uri.startsWith("/_next/data"); const normaliseUri = (uri: string): string => { if (basePath) uri = uri.slice(basePath.length); - return uri === "" ? "/index" : uri; + return uri === "" ? "/" : uri; }; const normaliseS3OriginDomain = (s3Origin: CloudFrontS3Origin): string => { diff --git a/packages/serverless-components/aws-cloudfront/lib/index.js b/packages/serverless-components/aws-cloudfront/lib/index.js index 2d1ec03118..cc82760245 100644 --- a/packages/serverless-components/aws-cloudfront/lib/index.js +++ b/packages/serverless-components/aws-cloudfront/lib/index.js @@ -127,13 +127,16 @@ const updateCloudFrontDistribution = async (cf, s3, distributionId, inputs) => { await updateBucketsPolicies(s3, Origins, s3CanonicalUserId); } - params.DistributionConfig.DefaultCacheBehavior = getDefaultCacheBehavior( - Origins.Items[0].Id, - inputs.defaults - ); + if(inputs.defaults) { + params.DistributionConfig.DefaultCacheBehavior = getDefaultCacheBehavior( + Origins.Items[0].Id, + inputs.defaults + ); + } const origins = params.DistributionConfig.Origins; const inputOrigins = Origins; + const inputOriginIds = inputOrigins.Items.map((origin) => origin.Id); const existingOriginIds = origins.Items.map((origin) => origin.Id); inputOrigins.Items.forEach((inputOrigin) => { @@ -149,7 +152,12 @@ const updateCloudFrontDistribution = async (cf, s3, distributionId, inputs) => { }); if (CacheBehaviors) { - params.DistributionConfig.CacheBehaviors = CacheBehaviors; + const existingCacheBehaviors = params.DistributionConfig.CacheBehaviors ? params.DistributionConfig.CacheBehaviors.Items.filter((behavior) => !inputOriginIds.includes(behavior.TargetOriginId)) : []; + const inputCacheBehaviours = CacheBehaviors.Items.concat(existingCacheBehaviors); + params.DistributionConfig.CacheBehaviors = { + Quantity: inputCacheBehaviours.length, + Items: inputCacheBehaviours + }; } // 6. then finally update! diff --git a/packages/serverless-components/nextjs-component/src/component.ts b/packages/serverless-components/nextjs-component/src/component.ts index 85c3c272d6..fc32014591 100644 --- a/packages/serverless-components/nextjs-component/src/component.ts +++ b/packages/serverless-components/nextjs-component/src/component.ts @@ -208,6 +208,7 @@ class NextjsComponent extends Component { defaults: cloudFrontDefaultsInputs, origins: cloudFrontOriginsInputs, priceClass: cloudFrontPriceClassInputs, + distributionId: cloudFrontDistributionIdInput, ...cloudFrontOtherInputs } = inputs.cloudfront || {}; @@ -491,24 +492,37 @@ class NextjsComponent extends Component { }; delete defaultLambdaAtEdgeConfig["origin-response"]; - const cloudFrontOutputs = await cloudFront({ - defaults: { - ttl: 0, - ...cloudFrontDefaults, - forward: { - cookies: "all", - queryString: true, - ...cloudFrontDefaults.forward - }, - // everything after here cant be overridden - allowedHttpMethods: ["HEAD", "GET"], - "lambda@edge": { - ...defaultLambdaAtEdgeConfig, - "origin-request": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}`, - "origin-response": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}` - }, - compress: true + const defaultBehaviour = { + ttl: 86400, + ...cloudFrontDefaults, + forward: { + cookies: "all", + queryString: true, + ...cloudFrontDefaults.forward }, + // everything after here cant be overridden + allowedHttpMethods: ["HEAD", "GET"], + "lambda@edge": { + ...defaultLambdaAtEdgeConfig, + "origin-request": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}`, + "origin-response": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}` + }, + compress: true, + smoothStreaming: false, + viewerProtocolPolicy: "redirect-to-https" + }; + + const defaults = !routesManifest.basePath && defaultBehaviour; + + if (!defaults) { + cloudFrontOrigins[0].pathPatterns[ + `${routesManifest.basePath.substr(1)}*` + ] = defaultBehaviour; + } + + const cloudFrontOutputs = await cloudFront({ + distributionId: cloudFrontDistributionIdInput, + defaults, origins: cloudFrontOrigins, ...(cloudFrontPriceClassInputs && { priceClass: cloudFrontPriceClassInputs From 0b60b302fcee5457edf4b523470f511ba950cce3 Mon Sep 17 00:00:00 2001 From: Denis Grankin Date: Thu, 27 Aug 2020 15:24:52 +0300 Subject: [PATCH 002/451] Fixes for shared distribution --- .../lambda-at-edge/src/default-handler.ts | 15 +----- .../aws-cloudfront/lib/index.js | 18 +++++-- .../nextjs-component/src/component.ts | 48 ++++++++++++------- 3 files changed, 45 insertions(+), 36 deletions(-) diff --git a/packages/libs/lambda-at-edge/src/default-handler.ts b/packages/libs/lambda-at-edge/src/default-handler.ts index 98244afd69..067ddb5f8b 100644 --- a/packages/libs/lambda-at-edge/src/default-handler.ts +++ b/packages/libs/lambda-at-edge/src/default-handler.ts @@ -72,21 +72,8 @@ const addS3HostHeader = ( const isDataRequest = (uri: string): boolean => uri.startsWith("/_next/data"); const normaliseUri = (uri: string): string => { - if (basePath) { - if (uri.startsWith(basePath)) { - uri = uri.slice(basePath.length); - } else { - // basePath set but URI does not start with basePath, return 404 - return "/404"; - } - } - - // Remove trailing slash for all paths - if (uri.endsWith("/")) { - uri = uri.slice(0, -1); - } - // Empty path should be normalised to "/" as there is no Next.js route for "" + if (basePath) uri = uri.slice(basePath.length); return uri === "" ? "/" : uri; }; diff --git a/packages/serverless-components/aws-cloudfront/lib/index.js b/packages/serverless-components/aws-cloudfront/lib/index.js index 2d1ec03118..cc82760245 100644 --- a/packages/serverless-components/aws-cloudfront/lib/index.js +++ b/packages/serverless-components/aws-cloudfront/lib/index.js @@ -127,13 +127,16 @@ const updateCloudFrontDistribution = async (cf, s3, distributionId, inputs) => { await updateBucketsPolicies(s3, Origins, s3CanonicalUserId); } - params.DistributionConfig.DefaultCacheBehavior = getDefaultCacheBehavior( - Origins.Items[0].Id, - inputs.defaults - ); + if(inputs.defaults) { + params.DistributionConfig.DefaultCacheBehavior = getDefaultCacheBehavior( + Origins.Items[0].Id, + inputs.defaults + ); + } const origins = params.DistributionConfig.Origins; const inputOrigins = Origins; + const inputOriginIds = inputOrigins.Items.map((origin) => origin.Id); const existingOriginIds = origins.Items.map((origin) => origin.Id); inputOrigins.Items.forEach((inputOrigin) => { @@ -149,7 +152,12 @@ const updateCloudFrontDistribution = async (cf, s3, distributionId, inputs) => { }); if (CacheBehaviors) { - params.DistributionConfig.CacheBehaviors = CacheBehaviors; + const existingCacheBehaviors = params.DistributionConfig.CacheBehaviors ? params.DistributionConfig.CacheBehaviors.Items.filter((behavior) => !inputOriginIds.includes(behavior.TargetOriginId)) : []; + const inputCacheBehaviours = CacheBehaviors.Items.concat(existingCacheBehaviors); + params.DistributionConfig.CacheBehaviors = { + Quantity: inputCacheBehaviours.length, + Items: inputCacheBehaviours + }; } // 6. then finally update! diff --git a/packages/serverless-components/nextjs-component/src/component.ts b/packages/serverless-components/nextjs-component/src/component.ts index 3033ae16b3..74b4cb4733 100644 --- a/packages/serverless-components/nextjs-component/src/component.ts +++ b/packages/serverless-components/nextjs-component/src/component.ts @@ -208,6 +208,7 @@ class NextjsComponent extends Component { defaults: cloudFrontDefaultsInputs, origins: cloudFrontOriginsInputs, priceClass: cloudFrontPriceClassInputs, + distributionId: cloudFrontDistributionIdInput, ...cloudFrontOtherInputs } = inputs.cloudfront || {}; @@ -496,24 +497,37 @@ class NextjsComponent extends Component { }; delete defaultLambdaAtEdgeConfig["origin-response"]; - const cloudFrontOutputs = await cloudFront({ - defaults: { - ttl: 0, - ...cloudFrontDefaults, - forward: { - cookies: "all", - queryString: true, - ...cloudFrontDefaults.forward - }, - // everything after here cant be overridden - allowedHttpMethods: ["HEAD", "GET"], - "lambda@edge": { - ...defaultLambdaAtEdgeConfig, - "origin-request": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}`, - "origin-response": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}` - }, - compress: true + const defaultBehaviour = { + ttl: 86400, + ...cloudFrontDefaults, + forward: { + cookies: "all", + queryString: true, + ...cloudFrontDefaults.forward }, + // everything after here cant be overridden + allowedHttpMethods: ["HEAD", "GET"], + "lambda@edge": { + ...defaultLambdaAtEdgeConfig, + "origin-request": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}`, + "origin-response": `${defaultEdgeLambdaOutputs.arn}:${defaultEdgeLambdaPublishOutputs.version}` + }, + compress: true, + smoothStreaming: false, + viewerProtocolPolicy: "redirect-to-https" + }; + + const defaults = !routesManifest.basePath && defaultBehaviour; + + if (!defaults) { + cloudFrontOrigins[0].pathPatterns[ + `${routesManifest.basePath.substr(1)}*` + ] = defaultBehaviour; + } + + const cloudFrontOutputs = await cloudFront({ + distributionId: cloudFrontDistributionIdInput, + defaults, origins: cloudFrontOrigins, ...(cloudFrontPriceClassInputs && { priceClass: cloudFrontPriceClassInputs From a6f62609a129c5d19bc275784caf2a822d45c796 Mon Sep 17 00:00:00 2001 From: Denis Grankin Date: Tue, 8 Sep 2020 20:43:22 +0300 Subject: [PATCH 003/451] Change org to getjerry, added custom aws-iam-role component, removed deprecated plugin code --- README.md | 2 +- documentation/docs/installation.md | 2 +- package.json | 7 +- .../apigw-lambda-compat/README.md | 4 +- .../apigw-lambda-compat/package.json | 2 +- .../lambda-at-edge-compat/package.json | 2 +- .../deprecated/serverless-plugin/.npmignore | 3 - .../deprecated/serverless-plugin/CHANGELOG.md | 128 - .../deprecated/serverless-plugin/README.md | 407 - .../serverless-plugin/__mocks__/aws-sdk.js | 126 - .../__tests__/fixtures/.gitignore | 1 - .../.next/serverless/pages/about.html | 1 - .../.serverless_plugins/index.js | 1 - .../serverless.yml | 17 - .../.serverless_plugins/index.js | 1 - .../app/.next/serverless/pages/blog/post.js | 1 - .../app/.next/serverless/pages/hello.js | 1 - .../app/.next/static/placeholder.js | 0 .../nested-next-config/serverless.yml | 22 - .../.next/serverless/pages/blog/post.js | 1 - .../.next/static/placeholder.js | 0 .../.serverless_plugins/index.js | 1 - .../fixtures/nested-page-app/serverless.yml | 17 - .../.next/serverless/pages/hello.js | 1 - .../one-page-app/.next/static/client.js | 1 - .../one-page-app/.serverless_plugins/index.js | 1 - .../fixtures/one-page-app/serverless.yml | 22 - .../.next/serverless/pages/api/api.js | 5 - .../single-api/.serverless_plugins/index.js | 1 - .../fixtures/single-api/serverless.yml | 17 - .../serverless-plugin/__tests__/index.test.js | 81 - .../__tests__/nested-next-config.test.js | 133 - .../__tests__/nested-page-app.test.js | 112 - .../__tests__/one-page-app.test.js | 130 - .../__tests__/single-api.test.js | 100 - .../serverless-plugin/classes/NextPage.js | 155 - .../classes/PluginBuildDir.js | 32 - .../classes/__tests__/NextPage.test.js | 397 - .../classes/__tests__/PluginBuildDir.test.js | 85 - .../deprecated/serverless-plugin/demo.gif | Bin 2190454 -> 0 bytes .../examples/app-basic/README.md | 35 - .../examples/app-basic/next.config.js | 8 - .../examples/app-basic/package.json | 37 - .../examples/app-basic/pages/_error.js | 9 - .../examples/app-basic/pages/about.js | 14 - .../app-basic/pages/categories/uno/dos.js | 13 - .../examples/app-basic/pages/index.js | 12 - .../examples/app-basic/pages/post.js | 12 - .../examples/app-basic/pages/styles/about.css | 9 - .../examples/app-basic/pages/styles/home.css | 9 - .../examples/app-basic/public/robots.txt | 2 - .../examples/app-basic/serverless.yml | 29 - .../examples/app-basic/static/nextjs.png | Bin 35551 -> 0 bytes .../examples/app-basic/yarn.lock | 10221 ---------------- .../examples/app-using-cloudfront/README.md | 22 - .../app-using-cloudfront/next.config.js | 7 - .../app-using-cloudfront/package.json | 36 - .../app-using-cloudfront/pages/_error.js | 9 - .../app-using-cloudfront/pages/about.js | 7 - .../app-using-cloudfront/pages/index.js | 22 - .../pages/styles/about.css | 9 - .../pages/styles/home.css | 9 - .../app-using-cloudfront/public/robots.txt | 2 - .../app-using-cloudfront/serverless.yml | 24 - .../app-using-cloudfront/static/nextjs.png | Bin 35551 -> 0 bytes .../app-with-custom-lambda-handler/README.md | 29 - .../my-lambda-handler.js | 14 - .../next.config.js | 3 - .../package.json | 31 - .../pages/home.js | 7 - .../serverless.yml | 22 - .../deprecated/serverless-plugin/index.js | 107 - .../__tests__/addCustomStackResources.test.js | 377 - .../lib/__tests__/build.test.js | 280 - .../lib/__tests__/checkForChanges.test.js | 49 - .../lib/__tests__/copyBuildFiles.test.js | 50 - .../lib/__tests__/displayServiceInfo.test.js | 69 - .../lib/__tests__/getAssetsBucketName.test.js | 89 - .../__tests__/getFactoryHandlerCode.test.js | 62 - .../getNextPagesFromBuildDir.test.js | 293 - .../__tests__/parseNextConfiguration.test.js | 79 - .../lib/__tests__/rewritePageHandlers.js | 114 - .../lib/__tests__/uploadStaticAssets.test.js | 137 - .../lib/addCustomStackResources.js | 270 - .../deprecated/serverless-plugin/lib/build.js | 78 - .../serverless-plugin/lib/checkForChanges.js | 25 - .../serverless-plugin/lib/copyBuildFiles.js | 12 - .../lib/displayServiceInfo.js | 38 - .../lib/getAssetsBucketName.js | 28 - .../lib/getFactoryHandlerCode.js | 38 - .../lib/getNextPagesFromBuildDir.js | 79 - .../lib/parseNextConfiguration.js | 44 - .../lib/rewritePageHandlers.js | 31 - .../lib/uploadStaticAssets.js | 61 - .../deprecated/serverless-plugin/package.json | 41 - .../resources/api-gw-next.yml | 41 - .../resources/api-gw-proxy.yml | 28 - .../resources/api-gw-static.yml | 41 - .../resources/assets-bucket.yml | 27 - .../resources/cloudfront.yml | 75 - .../utils/__tests__/logger.test.js | 29 - .../serverless-plugin/utils/createError.js | 5 - .../serverless-plugin/utils/logger.js | 13 - .../serverless-plugin/utils/pathToPosix.js | 1 - .../utils/s3/__tests__/get.test.js | 119 - .../utils/s3/__tests__/upload.test.js | 385 - .../serverless-plugin/utils/s3/get.js | 65 - .../serverless-plugin/utils/s3/upload.js | 120 - .../utils/test/ServerlessPluginBuilder.js | 74 - .../utils/test/getServerlessExec.js | 19 - .../serverless-plugin/utils/test/httpGet.js | 24 - .../utils/test/packageTestService.js | 9 - .../test/parsedNextConfigurationFactory.js | 12 - .../utils/test/readServerlessCFTemplate.js | 20 - .../utils/test/serverlessOfflineStart.js | 27 - .../utils/test/testableServerless.js | 101 - .../serverless-plugin/utils/yml/cfSchema.js | 70 - .../serverless-plugin/utils/yml/load.js | 14 - .../deprecated/serverless-plugin/yarn.lock | 258 - packages/libs/cloudfront/package.json | 2 +- packages/libs/lambda-at-edge/README.md | 2 +- packages/libs/lambda-at-edge/package.json | 2 +- packages/libs/lambda-at-edge/rollup.config.js | 2 +- .../libs/lambda-at-edge/src/api-handler.ts | 2 +- packages/libs/lambda-at-edge/src/build.ts | 4 +- .../lambda-at-edge/src/default-handler.ts | 3 +- packages/libs/s3-static-assets/package.json | 2 +- .../aws-cloudfront/package.json | 2 +- .../aws-iam-role/README.md | 11 + .../__tests__/aws-aim-role.test.js | 7 + .../aws-iam-role/package.json | 46 + .../aws-iam-role/serverless.js | 134 + .../aws-iam-role/utils.js | 153 + .../aws-lambda/package.json | 4 +- .../aws-lambda/serverless.js | 2 +- .../aws-lambda/yarn.lock | 15 +- .../serverless-components/domain/package.json | 2 +- .../nextjs-component/.d.ts | 2 +- .../__tests__/basepath.test.ts | 4 +- .../__tests__/custom-inputs.test.ts | 8 +- .../nextjs-component/__tests__/deploy.test.ts | 6 +- .../nextjs-component/package.json | 18 +- .../nextjs-component/src/component.ts | 20 +- .../nextjs-component/src/lib/obtainDomains.ts | 2 +- .../nextjs-component/types.d.ts | 2 +- .../nextjs-component/yarn.lock | 14 +- yarn.lock | 9 +- 147 files changed, 423 insertions(+), 16768 deletions(-) delete mode 100644 packages/deprecated/serverless-plugin/.npmignore delete mode 100644 packages/deprecated/serverless-plugin/CHANGELOG.md delete mode 100644 packages/deprecated/serverless-plugin/README.md delete mode 100644 packages/deprecated/serverless-plugin/__mocks__/aws-sdk.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/.gitignore delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.next/serverless/pages/about.html delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.serverless_plugins/index.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/.serverless_plugins/index.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/blog/post.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/hello.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/static/placeholder.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/serverless/pages/blog/post.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/static/placeholder.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.serverless_plugins/index.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/serverless/pages/hello.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/static/client.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.serverless_plugins/index.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.next/serverless/pages/api/api.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.serverless_plugins/index.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/__tests__/index.test.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/nested-next-config.test.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/nested-page-app.test.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/one-page-app.test.js delete mode 100644 packages/deprecated/serverless-plugin/__tests__/single-api.test.js delete mode 100644 packages/deprecated/serverless-plugin/classes/NextPage.js delete mode 100644 packages/deprecated/serverless-plugin/classes/PluginBuildDir.js delete mode 100644 packages/deprecated/serverless-plugin/classes/__tests__/NextPage.test.js delete mode 100644 packages/deprecated/serverless-plugin/classes/__tests__/PluginBuildDir.test.js delete mode 100644 packages/deprecated/serverless-plugin/demo.gif delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/README.md delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/next.config.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/package.json delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/_error.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/about.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/categories/uno/dos.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/index.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/post.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/styles/about.css delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/pages/styles/home.css delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/public/robots.txt delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/static/nextjs.png delete mode 100644 packages/deprecated/serverless-plugin/examples/app-basic/yarn.lock delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/README.md delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/next.config.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/package.json delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/pages/_error.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/pages/about.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/pages/index.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/pages/styles/about.css delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/pages/styles/home.css delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/public/robots.txt delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/examples/app-using-cloudfront/static/nextjs.png delete mode 100644 packages/deprecated/serverless-plugin/examples/app-with-custom-lambda-handler/README.md delete mode 100644 packages/deprecated/serverless-plugin/examples/app-with-custom-lambda-handler/my-lambda-handler.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-with-custom-lambda-handler/next.config.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-with-custom-lambda-handler/package.json delete mode 100644 packages/deprecated/serverless-plugin/examples/app-with-custom-lambda-handler/pages/home.js delete mode 100644 packages/deprecated/serverless-plugin/examples/app-with-custom-lambda-handler/serverless.yml delete mode 100644 packages/deprecated/serverless-plugin/index.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/addCustomStackResources.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/build.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/checkForChanges.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/copyBuildFiles.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/displayServiceInfo.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/getAssetsBucketName.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/getFactoryHandlerCode.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/getNextPagesFromBuildDir.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/parseNextConfiguration.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/rewritePageHandlers.js delete mode 100644 packages/deprecated/serverless-plugin/lib/__tests__/uploadStaticAssets.test.js delete mode 100644 packages/deprecated/serverless-plugin/lib/addCustomStackResources.js delete mode 100644 packages/deprecated/serverless-plugin/lib/build.js delete mode 100644 packages/deprecated/serverless-plugin/lib/checkForChanges.js delete mode 100644 packages/deprecated/serverless-plugin/lib/copyBuildFiles.js delete mode 100644 packages/deprecated/serverless-plugin/lib/displayServiceInfo.js delete mode 100644 packages/deprecated/serverless-plugin/lib/getAssetsBucketName.js delete mode 100644 packages/deprecated/serverless-plugin/lib/getFactoryHandlerCode.js delete mode 100644 packages/deprecated/serverless-plugin/lib/getNextPagesFromBuildDir.js delete mode 100644 packages/deprecated/serverless-plugin/lib/parseNextConfiguration.js delete mode 100644 packages/deprecated/serverless-plugin/lib/rewritePageHandlers.js delete mode 100644 packages/deprecated/serverless-plugin/lib/uploadStaticAssets.js delete mode 100644 packages/deprecated/serverless-plugin/package.json delete mode 100644 packages/deprecated/serverless-plugin/resources/api-gw-next.yml delete mode 100644 packages/deprecated/serverless-plugin/resources/api-gw-proxy.yml delete mode 100644 packages/deprecated/serverless-plugin/resources/api-gw-static.yml delete mode 100644 packages/deprecated/serverless-plugin/resources/assets-bucket.yml delete mode 100644 packages/deprecated/serverless-plugin/resources/cloudfront.yml delete mode 100644 packages/deprecated/serverless-plugin/utils/__tests__/logger.test.js delete mode 100644 packages/deprecated/serverless-plugin/utils/createError.js delete mode 100644 packages/deprecated/serverless-plugin/utils/logger.js delete mode 100644 packages/deprecated/serverless-plugin/utils/pathToPosix.js delete mode 100644 packages/deprecated/serverless-plugin/utils/s3/__tests__/get.test.js delete mode 100644 packages/deprecated/serverless-plugin/utils/s3/__tests__/upload.test.js delete mode 100644 packages/deprecated/serverless-plugin/utils/s3/get.js delete mode 100644 packages/deprecated/serverless-plugin/utils/s3/upload.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/ServerlessPluginBuilder.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/getServerlessExec.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/httpGet.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/packageTestService.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/parsedNextConfigurationFactory.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/readServerlessCFTemplate.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/serverlessOfflineStart.js delete mode 100644 packages/deprecated/serverless-plugin/utils/test/testableServerless.js delete mode 100644 packages/deprecated/serverless-plugin/utils/yml/cfSchema.js delete mode 100644 packages/deprecated/serverless-plugin/utils/yml/load.js delete mode 100644 packages/deprecated/serverless-plugin/yarn.lock create mode 100644 packages/serverless-components/aws-iam-role/README.md create mode 100644 packages/serverless-components/aws-iam-role/__tests__/aws-aim-role.test.js create mode 100644 packages/serverless-components/aws-iam-role/package.json create mode 100644 packages/serverless-components/aws-iam-role/serverless.js create mode 100644 packages/serverless-components/aws-iam-role/utils.js diff --git a/README.md b/README.md index 891b8fe5ca..74728cd6c5 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ Add your next application to the serverless.yml: # serverless.yml myNextApplication: - component: "@sls-next/serverless-component@{version_here}" # it is recommended you pin the latest stable version of serverless-next.js + component: "@getjerry/serverless-component@{version_here}" # it is recommended you pin the latest stable version of serverless-next.js ``` Set your AWS credentials as environment variables: diff --git a/documentation/docs/installation.md b/documentation/docs/installation.md index 7f9df94bcf..a5430c4a15 100644 --- a/documentation/docs/installation.md +++ b/documentation/docs/installation.md @@ -15,7 +15,7 @@ See the steps below to get started and install the Serverless Nextjs component i # serverless.yml myNextApplication: - component: "@sls-next/serverless-component@1.15.2-alpha.1" #specify latest stable version + component: "@getjerry/serverless-component@1.15.2-alpha.1" #specify latest stable version ``` 5. It is recommended you pin the latest stable version of serverless-next.js component. Check out the versions [here](https://github.com/serverless-nextjs/serverless-next.js/releases) diff --git a/package.json b/package.json index f087462014..4284a1a098 100644 --- a/package.json +++ b/package.json @@ -39,8 +39,8 @@ "homepage": "https://github.com/danielcondemarin/serverless-next.js#readme", "devDependencies": { "@babel/preset-typescript": "^7.10.4", - "@sls-next/lambda-at-edge": "link:./packages/libs/lambda-at-edge", - "@sls-next/next-aws-cloudfront": "link:./packages/compat-layers/lambda-at-edge-compat", + "@getjerry/lambda-at-edge": "link:./packages/libs/lambda-at-edge", + "@getjerry/next-aws-cloudfront": "link:./packages/compat-layers/lambda-at-edge-compat", "@types/fs-extra": "^9.0.1", "@types/jest": "^26.0.3", "@types/react": "^16.9.41", @@ -78,8 +78,6 @@ }, "coverageDirectory": "/coverage/", "coveragePathIgnorePatterns": [ - "/packages/deprecated/serverless-plugin/utils/yml/cfSchema.js", - "/packages/deprecated/serverless-plugin/utils/test", "/.serverless_nextjs/", "/fixtures/", "/fixture/", @@ -92,7 +90,6 @@ "/fixtures/" ], "testPathIgnorePatterns": [ - "/packages/deprecated/serverless-plugin/*", "/.next/", "/node_modules/", "/fixtures/", diff --git a/packages/compat-layers/apigw-lambda-compat/README.md b/packages/compat-layers/apigw-lambda-compat/README.md index c9a490b510..f8d49dbd8e 100644 --- a/packages/compat-layers/apigw-lambda-compat/README.md +++ b/packages/compat-layers/apigw-lambda-compat/README.md @@ -6,12 +6,12 @@ Lambda Proxy Integration event structure documentation can be found [here](https ## Installation -`npm install @sls-next/next-aws-lambda` +`npm install @getjerry/next-aws-lambda` ## Usage ```js -const compat = require("@sls-next/next-aws-lambda"); +const compat = require("@getjerry/next-aws-lambda"); const page = require(".next/serverless/pages/somePage.js"); // using callback diff --git a/packages/compat-layers/apigw-lambda-compat/package.json b/packages/compat-layers/apigw-lambda-compat/package.json index 9cb02c4fc4..b53e674b11 100644 --- a/packages/compat-layers/apigw-lambda-compat/package.json +++ b/packages/compat-layers/apigw-lambda-compat/package.json @@ -1,5 +1,5 @@ { - "name": "@sls-next/next-aws-lambda", + "name": "@getjerry/next-aws-lambda", "publishConfig": { "access": "public" }, diff --git a/packages/compat-layers/lambda-at-edge-compat/package.json b/packages/compat-layers/lambda-at-edge-compat/package.json index 436e4d28d1..cd53fc788e 100644 --- a/packages/compat-layers/lambda-at-edge-compat/package.json +++ b/packages/compat-layers/lambda-at-edge-compat/package.json @@ -1,5 +1,5 @@ { - "name": "@sls-next/next-aws-cloudfront", + "name": "@getjerry/next-aws-cloudfront", "version": "1.5.0-alpha.2", "publishConfig": { "access": "public" diff --git a/packages/deprecated/serverless-plugin/.npmignore b/packages/deprecated/serverless-plugin/.npmignore deleted file mode 100644 index c3e24d38a9..0000000000 --- a/packages/deprecated/serverless-plugin/.npmignore +++ /dev/null @@ -1,3 +0,0 @@ -__mocks__ -__tests__ -examples diff --git a/packages/deprecated/serverless-plugin/CHANGELOG.md b/packages/deprecated/serverless-plugin/CHANGELOG.md deleted file mode 100644 index 35df39de11..0000000000 --- a/packages/deprecated/serverless-plugin/CHANGELOG.md +++ /dev/null @@ -1,128 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [2.6.3-alpha.1](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.3-alpha.0...@sls-next/serverless-plugin@2.6.3-alpha.1) (2020-08-14) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -## [2.6.3-alpha.0](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.2...@sls-next/serverless-plugin@2.6.3-alpha.0) (2020-08-14) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -## [2.6.2](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.2-alpha.1...@sls-next/serverless-plugin@2.6.2) (2020-08-01) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -## [2.6.2-alpha.1](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.2-alpha.0...@sls-next/serverless-plugin@2.6.2-alpha.1) (2020-07-30) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -## [2.6.2-alpha.0](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.1...@sls-next/serverless-plugin@2.6.2-alpha.0) (2020-07-14) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -## [2.6.1](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.0...@sls-next/serverless-plugin@2.6.1) (2020-07-11) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -# [2.6.0](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.0-alpha.3...@sls-next/serverless-plugin@2.6.0) (2020-07-11) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -# [2.6.0-alpha.3](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.0-alpha.2...@sls-next/serverless-plugin@2.6.0-alpha.3) (2020-07-05) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -# [2.6.0-alpha.2](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.0-alpha.1...@sls-next/serverless-plugin@2.6.0-alpha.2) (2020-06-30) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -# [2.6.0-alpha.1](https://github.com/danielcondemarin/serverless-next.js/compare/@sls-next/serverless-plugin@2.6.0-alpha.0...@sls-next/serverless-plugin@2.6.0-alpha.1) (2020-06-29) - -**Note:** Version bump only for package @sls-next/serverless-plugin - -# 2.6.0-alpha.0 (2020-06-29) - -### Bug Fixes - -- **serverless-component:** don't overwrite the cloudfront default.forward config ([#460](https://github.com/danielcondemarin/serverless-next.js/issues/460)) ([12da1de](https://github.com/danielcondemarin/serverless-next.js/commit/12da1de31855b68b9addef801ec21dffd3202a21)) - -### Features - -- **lambda-at-edge:** add serverless trace target support ([#405](https://github.com/danielcondemarin/serverless-next.js/issues/405)) ([d800951](https://github.com/danielcondemarin/serverless-next.js/commit/d800951673474965c386ab94b2d8db18790099f7)) - -## [2.5.2-alpha.0](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.5.1...serverless-nextjs-plugin@2.5.2-alpha.0) (2020-06-24) - -### Bug Fixes - -- **serverless-component:** don't overwrite the cloudfront default.forward config ([#460](https://github.com/danielcondemarin/serverless-next.js/issues/460)) ([12da1de](https://github.com/danielcondemarin/serverless-next.js/commit/12da1de31855b68b9addef801ec21dffd3202a21)) - -## [2.5.1](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.5.1-alpha.0...serverless-nextjs-plugin@2.5.1) (2020-06-16) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.5.1-alpha.0](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.5.0...serverless-nextjs-plugin@2.5.1-alpha.0) (2020-06-12) - -**Note:** Version bump only for package serverless-nextjs-plugin - -# [2.5.0](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.5.0-alpha.0...serverless-nextjs-plugin@2.5.0) (2020-06-05) - -**Note:** Version bump only for package serverless-nextjs-plugin - -# [2.5.0-alpha.0](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.4.11...serverless-nextjs-plugin@2.5.0-alpha.0) (2020-05-17) - -### Features - -- **lambda-at-edge:** add serverless trace target support ([#405](https://github.com/danielcondemarin/serverless-next.js/issues/405)) ([d800951](https://github.com/danielcondemarin/serverless-next.js/commit/d800951673474965c386ab94b2d8db18790099f7)) - -## [2.4.11](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.4.10...serverless-nextjs-plugin@2.4.11) (2020-05-06) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.10](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.4.10-alpha.0...serverless-nextjs-plugin@2.4.10) (2020-04-25) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.10-alpha.0](https://github.com/danielcondemarin/serverless-next.js/compare/serverless-nextjs-plugin@2.4.9...serverless-nextjs-plugin@2.4.10-alpha.0) (2020-04-23) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.9](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.8...serverless-nextjs-plugin@2.4.9) (2020-03-29) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.8](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.7...serverless-nextjs-plugin@2.4.8) (2020-03-29) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.7](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.6...serverless-nextjs-plugin@2.4.7) (2020-03-22) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.6](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.5...serverless-nextjs-plugin@2.4.6) (2020-03-14) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.5](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.4...serverless-nextjs-plugin@2.4.5) (2020-02-29) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.4](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.3...serverless-nextjs-plugin@2.4.4) (2019-12-22) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.3](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.2...serverless-nextjs-plugin@2.4.3) (2019-11-30) - -### Bug Fixes - -- **plugin:** move config referencing out of plugin constructor ([#248](https://github.com/danielcondemarin/serverless-nextjs-plugin/issues/248)) ([16d66a2](https://github.com/danielcondemarin/serverless-nextjs-plugin/commit/16d66a209a47adf799f8ac1ca8efb6cc7a38e68f)) - -## [2.4.2](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.1...serverless-nextjs-plugin@2.4.2) (2019-11-03) - -**Note:** Version bump only for package serverless-nextjs-plugin - -## [2.4.1](https://github.com/danielcondemarin/serverless-nextjs-plugin/compare/serverless-nextjs-plugin@2.4.0...serverless-nextjs-plugin@2.4.1) (2019-11-03) - -**Note:** Version bump only for package serverless-nextjs-plugin diff --git a/packages/deprecated/serverless-plugin/README.md b/packages/deprecated/serverless-plugin/README.md deleted file mode 100644 index c9a5ef8af5..0000000000 --- a/packages/deprecated/serverless-plugin/README.md +++ /dev/null @@ -1,407 +0,0 @@ -# UPDATE! - -A new iteration of this project has been released powered by the amazing [Serverless Components](https://github.com/serverless/components). -Check it out [here](https://github.com/danielcondemarin/serverless-next.js/tree/master/packages/serverless-nextjs-component). As you can see, it lives in the same monorepo. -The new version has feature parity with nextjs 9.0 and does not use CloudFormation, allowing faster deployments and no [resource limit issues](https://github.com/danielcondemarin/serverless-next.js/issues/17). - -It is recommended for both existing and new users to try the new version. Obviously existing users of the next plugin don't have to migrate over straight away, the plan is to continue maintaining the plugin until the new component is more mature. - -# Serverless Nextjs Plugin - -[![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com) -[![Build Status](https://travis-ci.org/danielcondemarin/serverless-next.js.svg?branch=master)](https://travis-ci.org/danielcondemarin/serverless-nextjs-plugin) -[![Financial Contributors on Open Collective](https://opencollective.com/serverless-nextjs-plugin/all/badge.svg?label=financial+contributors)](https://opencollective.com/serverless-nextjs-plugin) [![npm version](https://badge.fury.io/js/serverless-nextjs-plugin.svg)](https://badge.fury.io/js/serverless-nextjs-plugin) -[![Coverage Status](https://coveralls.io/repos/github/danielcondemarin/serverless-next.js/badge.svg?branch=master)](https://coveralls.io/github/danielcondemarin/serverless-nextjs-plugin?branch=master) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/c0d3aa2a86cb4ce98772a02015f46314)](https://www.codacy.com/app/danielcondemarin/serverless-nextjs-plugin?utm_source=github.com&utm_medium=referral&utm_content=danielcondemarin/serverless-nextjs-plugin&utm_campaign=Badge_Grade) - -A [serverless framework](https://serverless.com/) plugin to deploy nextjs apps. - -The plugin targets [Next 8 serverless mode](https://nextjs.org/blog/next-8/#serverless-nextjs) - -![demo](./demo.gif) - -## Contents - -- [Motivation](#motivation) -- [Getting Started](#getting-started) -- [Hosting static assets](#hosting-static-assets) -- [Serving static assets](#serving-static-assets) -- [Deploying](#deploying) -- [Overriding page configuration](#overriding-page-configuration) -- [Custom page routing](#custom-page-routing) -- [Custom error page](#custom-error-page) -- [Custom lambda handler](#custom-lambda-handler) -- [All plugin configuration options](#all-plugin-configuration-options) -- [Examples](#examples) -- [Caveats](#caveats) -- [Contributing](#contributing) - -## Motivation - -Next 8 released [official support](https://nextjs.org/blog/next-8/#serverless-nextjs) for serverless! It doesn't work out of the box with AWS Lambdas, instead, next provides a low level API which this plugin uses to deploy the serverless pages. - -Nextjs serverless page handler signature: - -```js -exports.render = function(req, res) => {...} -``` - -AWS Lambda handler: - -```js -exports.handler = function(event, context, callback) {...} -``` - -A compat layer between the nextjs page bundles and AWS Lambda is added at build time: - -```js -const compat = require("@sls-next/next-aws-lambda"); -const page = require(".next/serverless/pages/somePage.js"); - -module.exports.render = (event, context, callback) => { - compat(page)(event, context, callback); -}; -``` - -## Getting started - -### Installing - -`npm install --save-dev @sls-next/serverless-plugin` - -Out of the box, the plugin won't require any configuration. If you need to override any defaults check [this](#all-plugin-configuration-options). - -For example: - -``` -nextApp -│ next.config.js -│ serverless.yml -└───pages -│ │ home.js -│ │ about.js -│ │ admin.js -``` - -Edit the serverless.yml and add: - -```yml -plugins: - - serverless-nextjs-plugin - -package: - exclude: - - ./** -``` - -You can exclude everything. The plugin makes sure the page handlers are included in the artifacts. - -## Hosting static assets - -If you don't want to manage uploading the next static assets yourself, like uploading them to a CDN, the plugin can do this for you by hosting the asset files on S3. - -The easiest way is to use a [valid bucket URL](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro) in the `assetPrefix` field of your next configuration: - -```js -// next.config.js -module.exports = { - assetPrefix: "https://s3.amazonaws.com/your-bucket-name" -}; -``` - -The plugin will create a new S3 Bucket using the parsed name. On deployment, static assets will be uploaded to the bucket provisioned. - -Alternatively, if you just want the assets to get uploaded to S3, you can provide the bucket name via the plugin config: - -```yml -# serverless.yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - assetsBucketName: "your-bucket-name" -``` - -## Serving static assets - -Static files can be served by [following the NextJs convention](https://github.com/zeit/next.js/#static-file-serving-eg-images) of using a `static` and `public` folder. - -From your code you can then reference those files with a `/static` URL: - -``` -function MyImage() { - return my image -} - -export default MyImage -``` - -To serve static files from the root directory you can add a folder called public and reference those files from the root, e.g: /robots.txt. - -Note that for this to work, an S3 bucket needs to be provisioned as per [hosting-static-assets](#hosting-static-assets). - -**For production deployments, enabling CloudFront is recommended:** - -```yml -# serverless.yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - assetsBucketName: "your-bucket-name" - cloudFront: true -``` - -By doing this, a CloudFront distribution will be created in front of your next application to serve any static assets from S3 and the pages from Api Gateway. - -Note that deploying the stack for the first time will take considerably longer, as CloudFront takes time propagating the changes, typically 10 - 20mins. - -You can provide your own configuration for the CloudFront distribution: - -```yml -# serverless.yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - assetsBucketName: "your-bucket-name" - cloudFront: ${file(cloudfront-override.yml)} -``` - -```yml -# cloudfront-override.yml -# e.g. add custom domain name -Properties: - DistributionConfig: - Aliases: - - my.alias.com - ViewerCertificate: - AcmCertificateArn: arn:aws:acm:xxxx - ... -``` - -The configuration provided will be merged onto the defaults in `packages/serverless-plugin/resources/cloudfront.yml`. - -## Deploying - -`serverless deploy` - -When running `serverless deploy` all your next pages will be automatically compiled, packaged and deployed. - -The Lambda functions created for each page have by default the following configuration: - -```yml -handler: /path/to/page/handler.render -events: - - http: - path: pageName # home, about, etc. Unless is the index page which is served at / - method: get - - http: - path: pageName # home, about, etc. Unless is the index page which is served at / - method: head -``` - -## Overriding page configuration - -You may want to have a different configuration for one or more of your page functions. This is possible by setting the `pageConfig` key in the plugin config: - -```yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - pageConfig: - about: - memorySize: 512 # default is 1024 - home: - timeout: 10 # default is 6 -``` - -If you need to change the default configuration, such as `memorySize`, `timeout` etc. use the top level `provider` which will override all the functions configuration. For example, to change the memorySize to 512MB: - -```yml -provider: - name: aws - runtime: nodejs8.10 - memorySize: 512 - ... -``` - -You can also add configuration for all page functions by adding an asterisk entry (`*`) to `pageConfig`. This is particularly useful when you have other functions in your service (i.e. an `api`) aside from the page functions and you only want to apply configuration changes to the latter: - -```yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - pageConfig: - "*": - layers: - - arn:aws:lambda:${self:provider.region}:553035198032:layer:nodejs12:1 -``` - -You can set any function property described [here](https://serverless.com/framework/docs/providers/aws/guide/functions#configuration). - -## Custom page routing - -The default page routes follow the same convention as next `useFileSystemPublicRoutes` documented [here](https://nextjs.org/docs/#routing). - -E.g. - -| page | path | -| --------------------------- | ------------------- | -| pages/index.js | / | -| pages/post.js | /post | -| pages/blog/index.js | /blog | -| pages/categories/uno/dos.js | /categories/uno/dos | - -You may want to serve your page from a different path. This is possible by setting your own http path in the `routes` config. For example for `pages/post.js`: - -```js -class Post extends React.Component { - static async getInitialProps({ query }) { - return { - slug: query.slug - }; - } - render() { - return

Post page: {this.props.slug}

; - } -} - -export default Post; -``` - -```yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - routes: - - src: post - path: posts/{slug} - request: - parameters: - paths: - slug: true -``` - -## Custom error page - -404 or 500 errors are handled both client and server side by a default component `error.js`, same as documented [here](https://github.com/zeit/next.js/#custom-error-handling). - -Simply add `pages/_error.js`: - -```js -class Error extends React.Component { - static getInitialProps({ res, err }) { - const statusCode = res ? res.statusCode : err ? err.statusCode : null; - return { statusCode }; - } - - render() { - return ( -

- {this.props.statusCode - ? `An error ${this.props.statusCode} occurred on server (╯°□°)╯︵ ┻━┻` - : "An error occurred on client"} -

- ); - } -} - -export default Error; -``` - -## Custom lambda handler - -If you need to customize the lambda handler you can do so by providing a path to your own handler in the `customHandler` field. Note that it resolves the path to the custom handler relative to your `next.config.js`. - -```yml -plugins: - - serverless-nextjs-plugin - -custom: - serverless-nextjs: - customHandler: ./handler.js -``` - -The custom handler needs to look something like this: - -```js -const compat = require("@sls-next/next-aws-lambda"); - -module.exports = (page) => { - const handler = (event, context) => { - // do any stuff you like - - // this makes sure the next page renders - const responsePromise = compat(page)(event, context); - - // do any other stuff you like - - return responsePromise; - }; - return handler; -}; -``` - -## All plugin configuration options - -| Plugin config key | Type | Default Value | Description | -| ----------------- | ------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| nextConfigDir | `string` | ./ | Path to parent directory of `next.config.js`. | -| assetsBucketName | `string` | \ | Creates an S3 bucket with the name provided. The bucket will be used for uploading next static assets. | -| cloudFront | `bool` \| `object` | false | Set to `true` to create a cloud front distribution in front of your nextjs application. Also can be set to an `object` if you need to override CloudFront configuration, see [serving static assets](#serving-static-assets). | -| routes | `[]object` | [] | Array of custom routes for the next pages. | -| customHandler | `string` | \ | Path to your own lambda handler. | -| uploadBuildAssets | `bool` | true | In the unlikely event that you only want to upload `static` or `public` dirs, set this to `false`. | -| createAssetBucket | `bool` | true | Set to false if you want to manage next assets yourself. | - -## Caveats - -Beware this plugin relies on CloudFormation which has a hard limit of 200 resources. If you have a large number of pages in your application it is very likely that you will hit this limit. Use https://github.com/danielcondemarin/serverless-next.js/tree/master/packages/serverless-nextjs-component which solves this problem by not using CloudFormation. - -## Examples - -See the `examples/` directory. - -## Contributing - -Please see the [contributing](./CONTRIBUTING.md) guide. - -## Contributors - -### Code Contributors - -This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. - - -### Financial Contributors - -Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/serverless-nextjs-plugin/contribute)] - -#### Individuals - - - -#### Organizations - -Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/serverless-nextjs-plugin/contribute)] - - - - - - - - - - - diff --git a/packages/deprecated/serverless-plugin/__mocks__/aws-sdk.js b/packages/deprecated/serverless-plugin/__mocks__/aws-sdk.js deleted file mode 100644 index 3f8da90626..0000000000 --- a/packages/deprecated/serverless-plugin/__mocks__/aws-sdk.js +++ /dev/null @@ -1,126 +0,0 @@ -const promisify = (mockFunction) => { - const mockPromise = jest.fn(() => Promise.resolve()); - mockFunction.mockReturnValue({ - promise: mockPromise - }); - - return { - mockFunction, - mockPromise - }; -}; - -const MockCloudWatchLogs = function () {}; -function MockEnvironmentCredentials() {} -function MockCloudFormation() {} - -const { - mockFunction: mockDescribeStacks, - mockPromise: mockDescribeStacksPromise -} = promisify(jest.fn()); - -const { - mockFunction: mockCreateStack, - mockPromise: mockCreateStackPromise -} = promisify(jest.fn()); - -const { - mockFunction: mockDescribeStackEvents, - mockPromise: mockDescribeStackEventsPromise -} = promisify(jest.fn()); - -const { - mockFunction: mockDescribeStackResource, - mockPromise: mockDescribeStackResourcePromise -} = promisify(jest.fn()); - -const { - mockFunction: mockValidateTemplate, - mockPromise: mockValidateTemplatePromise -} = promisify(jest.fn()); - -const { - mockFunction: mockUpdateStack, - mockPromise: mockUpdateStackPromise -} = promisify(jest.fn()); - -const { - mockFunction: mockListStackResources, - mockPromise: mockListStackResourcesPromise -} = promisify(jest.fn()); - -MockCloudFormation.prototype.describeStacks = mockDescribeStacks; -MockCloudFormation.prototype.createStack = mockCreateStack; -MockCloudFormation.prototype.describeStackEvents = mockDescribeStackEvents; -MockCloudFormation.prototype.describeStackResource = mockDescribeStackResource; -MockCloudFormation.prototype.validateTemplate = mockValidateTemplate; -MockCloudFormation.prototype.updateStack = mockUpdateStack; -MockCloudFormation.prototype.listStackResources = mockListStackResources; - -const { - mockFunction: mockListObjectsV2, - mockPromise: mockListObjectsV2Promise -} = promisify(jest.fn()); - -const S3MockUpload = promisify(jest.fn()); - -const MockSTS = function () {}; -const { - mockFunction: mockGetCallerIdentity, - mockPromise: mockGetCallerIdentityPromise -} = promisify(jest.fn()); -MockSTS.prototype.getCallerIdentity = mockGetCallerIdentity; - -const MockAPIGateway = function () {}; -const { - mockFunction: mockGetRestApis, - mockPromise: mockGetRestApisPromise -} = promisify(jest.fn()); -MockAPIGateway.prototype.getRestApis = mockGetRestApis; - -const MockSharedIniFileCredentials = function () {}; - -const MockMetadataService = function () {}; -const mockMetadataRequest = jest - .fn() - .mockImplementation((path, cb) => cb(null, {})); -MockMetadataService.prototype.request = mockMetadataRequest; - -module.exports = { - EnvironmentCredentials: MockEnvironmentCredentials, - S3: jest.fn(() => { - return { - upload: S3MockUpload.mockFunction, - listObjectsV2: mockListObjectsV2 - }; - }), - CloudFormation: MockCloudFormation, - CloudWatchLogs: MockCloudWatchLogs, - STS: MockSTS, - APIGateway: MockAPIGateway, - SharedIniFileCredentials: MockSharedIniFileCredentials, - MetadataService: MockMetadataService, - - mockDescribeStacks, - mockDescribeStacksPromise, - mockCreateStack, - mockCreateStackPromise, - mockDescribeStackEvents, - mockDescribeStackEventsPromise, - mockDescribeStackResource, - mockDescribeStackResourcePromise, - mockListObjectsV2, - mockListObjectsV2Promise, - mockGetCallerIdentity, - mockGetCallerIdentityPromise, - mockUpload: S3MockUpload.mockFunction, - mockUploadPromise: S3MockUpload.mockPromise, - mockUpdateStack, - mockUpdateStackPromise, - mockListStackResources, - mockListStackResourcesPromise, - mockGetRestApis, - mockGetRestApisPromise, - mockValidateTemplate, - mockValidateTemplatePromise -}; diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/.gitignore b/packages/deprecated/serverless-plugin/__tests__/fixtures/.gitignore deleted file mode 100644 index 665599776e..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!.next \ No newline at end of file diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.next/serverless/pages/about.html b/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.next/serverless/pages/about.html deleted file mode 100644 index 18ecdcb795..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.next/serverless/pages/about.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.serverless_plugins/index.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.serverless_plugins/index.js deleted file mode 100644 index 4007146446..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/.serverless_plugins/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("../../../../index"); diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/serverless.yml b/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/serverless.yml deleted file mode 100644 index 47a60477f4..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/automatic-static-optimised-app/serverless.yml +++ /dev/null @@ -1,17 +0,0 @@ -service: automatic-static-optimised-app-fixture - -provider: - name: aws - runtime: nodejs8.10 - -stage: dev -region: eu-west-1 - -plugins: - - index - -package: - # exclude everything - # page handlers are automatically included by the plugin - exclude: - - ./** diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/.serverless_plugins/index.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/.serverless_plugins/index.js deleted file mode 100644 index 4007146446..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/.serverless_plugins/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("../../../../index"); diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/blog/post.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/blog/post.js deleted file mode 100644 index 6661ba119d..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/blog/post.js +++ /dev/null @@ -1 +0,0 @@ -module.exports.render = () => {}; diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/hello.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/hello.js deleted file mode 100644 index 6661ba119d..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/serverless/pages/hello.js +++ /dev/null @@ -1 +0,0 @@ -module.exports.render = () => {}; diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/static/placeholder.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/app/.next/static/placeholder.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/serverless.yml b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/serverless.yml deleted file mode 100644 index 8daddd6e3c..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-next-config/serverless.yml +++ /dev/null @@ -1,22 +0,0 @@ -service: nested-next-config-fixture - -provider: - name: aws - runtime: nodejs8.10 - memorySize: 512 - -stage: dev -region: eu-west-1 - -plugins: - - index - -custom: - serverless-nextjs: - nextConfigDir: ./app - -package: - # exclude everything - # page handlers are automatically included by the plugin - exclude: - - ./** diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/serverless/pages/blog/post.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/serverless/pages/blog/post.js deleted file mode 100644 index 6661ba119d..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/serverless/pages/blog/post.js +++ /dev/null @@ -1 +0,0 @@ -module.exports.render = () => {}; diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/static/placeholder.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.next/static/placeholder.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.serverless_plugins/index.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.serverless_plugins/index.js deleted file mode 100644 index 4007146446..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/.serverless_plugins/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("../../../../index"); diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/serverless.yml b/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/serverless.yml deleted file mode 100644 index bac0ba82e2..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/nested-page-app/serverless.yml +++ /dev/null @@ -1,17 +0,0 @@ -service: nested-page-app-fixture - -provider: - name: aws - runtime: nodejs8.10 - -stage: dev -region: eu-west-1 - -plugins: - - index - -package: - # exclude everything - # page handlers are automatically included by the plugin - exclude: - - ./** diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/serverless/pages/hello.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/serverless/pages/hello.js deleted file mode 100644 index 6661ba119d..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/serverless/pages/hello.js +++ /dev/null @@ -1 +0,0 @@ -module.exports.render = () => {}; diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/static/client.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/static/client.js deleted file mode 100644 index 535868fbb0..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.next/static/client.js +++ /dev/null @@ -1 +0,0 @@ -// the contents of this file don't actually matter diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.serverless_plugins/index.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.serverless_plugins/index.js deleted file mode 100644 index 4007146446..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/.serverless_plugins/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("../../../../index"); diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/serverless.yml b/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/serverless.yml deleted file mode 100644 index f239913aab..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/one-page-app/serverless.yml +++ /dev/null @@ -1,22 +0,0 @@ -service: one-page-app-fixture - -provider: - name: aws - runtime: nodejs8.10 - memorySize: 512 - -stage: dev -region: eu-west-1 - -plugins: - - index - -custom: - serverless-nextjs: - assetsBucketName: onepageappbucket - -package: - # exclude everything - # page handlers are automatically included by the plugin - exclude: - - ./** diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.next/serverless/pages/api/api.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.next/serverless/pages/api/api.js deleted file mode 100644 index 56f177bb19..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.next/serverless/pages/api/api.js +++ /dev/null @@ -1,5 +0,0 @@ -export default (req, res) => { - { - test: "test"; - } -}; diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.serverless_plugins/index.js b/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.serverless_plugins/index.js deleted file mode 100644 index 4007146446..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/.serverless_plugins/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("../../../../index"); diff --git a/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/serverless.yml b/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/serverless.yml deleted file mode 100644 index 54694057f4..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/fixtures/single-api/serverless.yml +++ /dev/null @@ -1,17 +0,0 @@ -service: single-api-fixture - -provider: - name: aws - runtime: nodejs8.10 - -stage: dev -region: eu-west-1 - -plugins: - - index - -package: - # exclude everything - # page handlers are automatically included by the plugin - exclude: - - ./** diff --git a/packages/deprecated/serverless-plugin/__tests__/index.test.js b/packages/deprecated/serverless-plugin/__tests__/index.test.js deleted file mode 100644 index b3371fa32e..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/index.test.js +++ /dev/null @@ -1,81 +0,0 @@ -const ServerlessPluginBuilder = require("../utils/test/ServerlessPluginBuilder"); -const displayServiceInfo = require("../lib/displayServiceInfo"); -const ServerlessNextJsPlugin = require("../index"); - -jest.mock("../lib/displayServiceInfo"); - -describe("ServerlessNextJsPlugin", () => { - let pluginBuilder; - - beforeEach(() => { - pluginBuilder = new ServerlessPluginBuilder(); - }); - - describe("#constructor", () => { - it.each` - hook | method - ${"before:offline:start"} | ${"build"} - ${"before:package:initialize"} | ${"build"} - ${"before:deploy:function:initialize"} | ${"build"} - ${"after:aws:deploy:deploy:checkForChanges"} | ${"checkForChanges"} - ${"after:aws:deploy:deploy:uploadArtifacts"} | ${"uploadStaticAssets"} - ${"after:aws:info:displayStackOutputs"} | ${"printStackOutput"} - ${"after:package:createDeploymentArtifacts"} | ${"removePluginBuildDir"} - ${"before:aws:package:finalize:mergeCustomProviderResources"} | ${"addCustomStackResources"} - `("should hook to $hook with method $method", ({ hook, method }) => { - const spy = jest - .spyOn(ServerlessNextJsPlugin.prototype, "hookWrapper") - .mockImplementation(() => {}); - const plugin = new ServerlessPluginBuilder().build(); - plugin.hooks[hook](); - expect(spy).toHaveBeenCalledWith(plugin[method]); - }); - }); - - describe("#printStackOutput", () => { - it("should call displayStackOutput with awsInfo", () => { - const awsInfo = { - constructor: { - name: "AwsInfo" - } - }; - const getPlugins = jest.fn().mockReturnValueOnce([awsInfo]); - - const plugin = new ServerlessPluginBuilder() - .withPluginManager({ - getPlugins - }) - .build(); - - plugin.printStackOutput(); - - expect(displayServiceInfo).toBeCalledWith(awsInfo); - }); - }); - - describe("#removePluginBuildDir", () => { - it("should call pluginBuildDir.removeBuildDir", () => { - const plugin = new ServerlessPluginBuilder().build(); - const mockRemoveBuildDir = jest.fn().mockResolvedValueOnce(); - plugin.pluginBuildDir.removeBuildDir = mockRemoveBuildDir; - - return plugin.removePluginBuildDir().then(() => { - expect(mockRemoveBuildDir).toBeCalled(); - }); - }); - }); - - describe("#getPluginConfigValue", () => { - it("uses default values when config key not provided", () => { - const plugin = pluginBuilder - .withPluginConfig({ - routes: undefined, - uploadBuildAssets: undefined - }) - .build(); - - expect(plugin.getPluginConfigValue("routes")).toEqual([]); - expect(plugin.getPluginConfigValue("uploadBuildAssets")).toEqual(true); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/__tests__/nested-next-config.test.js b/packages/deprecated/serverless-plugin/__tests__/nested-next-config.test.js deleted file mode 100644 index 7241747142..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/nested-next-config.test.js +++ /dev/null @@ -1,133 +0,0 @@ -const nextBuild = require("next/dist/build"); -const path = require("path"); -const AdmZip = require("adm-zip"); -const { - readUpdateTemplate -} = require("../utils/test/readServerlessCFTemplate"); -const testableServerless = require("../utils/test/testableServerless"); - -jest.mock("next/dist/build"); - -jest.setTimeout(10000); - -describe("nested next config", () => { - const fixturePath = path.join(__dirname, "./fixtures/nested-next-config"); - - let cloudFormationUpdateResources; - - beforeAll(async () => { - nextBuild.default.mockResolvedValue(); - - await testableServerless(fixturePath, "package"); - - const cloudFormationUpdateTemplate = await readUpdateTemplate(fixturePath); - - cloudFormationUpdateResources = cloudFormationUpdateTemplate.Resources; - }); - - describe("Page lambda function", () => { - let pageLambda; - - beforeAll(() => { - pageLambda = cloudFormationUpdateResources.HelloLambdaFunction; - }); - - it("creates lambda resource", () => { - expect(pageLambda).toBeDefined(); - }); - - it("has correct handler", () => { - expect(pageLambda.Properties.Handler).toEqual( - "app/sls-next-build/hello.render" - ); - }); - - describe("nested page", () => { - let blogPostPageLambda; - - beforeAll(() => { - blogPostPageLambda = - cloudFormationUpdateResources.BlogDashpostLambdaFunction; - }); - - it("creates lambda resource", () => { - expect(blogPostPageLambda).toBeDefined(); - }); - - it("has correct handler", () => { - expect(blogPostPageLambda.Properties.Handler).toEqual( - "app/sls-next-build/blog/post.render" - ); - }); - }); - }); - - describe("Api Gateway", () => { - let apiGateway; - - beforeAll(() => { - apiGateway = cloudFormationUpdateResources.ApiGatewayRestApi; - }); - - it("creates api resource", () => { - expect(apiGateway).toBeDefined(); - }); - - describe("Page route", () => { - it("creates page route resource with correct path", () => { - const routeResource = - cloudFormationUpdateResources.ApiGatewayResourceHello; - - expect(routeResource).toBeDefined(); - expect(routeResource.Properties.PathPart).toEqual("hello"); - }); - - describe("nested page", () => { - it("creates page route resource with correct path", () => { - const blogResource = - cloudFormationUpdateResources.ApiGatewayResourceBlog; - - const blogPostResource = - cloudFormationUpdateResources.ApiGatewayResourceBlogPost; - - expect(blogResource).toBeDefined(); - expect(blogPostResource).toBeDefined(); - expect(blogResource.Properties.PathPart).toEqual("blog"); - expect(blogPostResource.Properties.PathPart).toEqual("post"); - }); - }); - }); - }); - - describe("Zip artifact", () => { - let zipEntryNames; - - beforeAll(() => { - const zip = new AdmZip( - `${fixturePath}/.serverless/nested-next-config-fixture.zip` - ); - const zipEntries = zip.getEntries(); - zipEntryNames = zipEntries.map((ze) => ze.entryName); - }); - - it("contains next compiled page", () => { - expect(zipEntryNames).toContain(`app/sls-next-build/hello.original.js`); - }); - - it("contains plugin handler", () => { - expect(zipEntryNames).toContain(`app/sls-next-build/hello.js`); - }); - - describe("nested page", () => { - it("contains next compiled page", () => { - expect(zipEntryNames).toContain( - `app/sls-next-build/blog/post.original.js` - ); - }); - - it("contains plugin handler", () => { - expect(zipEntryNames).toContain(`app/sls-next-build/blog/post.js`); - }); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/__tests__/nested-page-app.test.js b/packages/deprecated/serverless-plugin/__tests__/nested-page-app.test.js deleted file mode 100644 index 22ad9a5d13..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/nested-page-app.test.js +++ /dev/null @@ -1,112 +0,0 @@ -const nextBuild = require("next/dist/build"); -const path = require("path"); -const AdmZip = require("adm-zip"); -const { - readUpdateTemplate -} = require("../utils/test/readServerlessCFTemplate"); -const testableServerless = require("../utils/test/testableServerless"); - -jest.mock("next/dist/build"); - -describe("nested page app", () => { - const fixturePath = path.join(__dirname, "./fixtures/nested-page-app"); - - let cloudFormationUpdateResources; - - beforeAll(async () => { - nextBuild.default.mockResolvedValue(); - - await testableServerless(fixturePath, "package"); - - const cloudFormationUpdateTemplate = await readUpdateTemplate(fixturePath); - - cloudFormationUpdateResources = cloudFormationUpdateTemplate.Resources; - }); - - describe("Page lambda function", () => { - let pageLambda; - - beforeAll(() => { - pageLambda = cloudFormationUpdateResources.BlogDashpostLambdaFunction; - }); - - it("creates lambda resource", () => { - expect(pageLambda).toBeDefined(); - }); - - it("has correct handler", () => { - expect(pageLambda.Properties.Handler).toEqual( - "sls-next-build/blog/post.render" - ); - }); - }); - - describe("Api Gateway", () => { - let apiGateway; - - beforeAll(() => { - apiGateway = cloudFormationUpdateResources.ApiGatewayRestApi; - }); - - it("creates api resource", () => { - expect(apiGateway).toBeDefined(); - }); - - describe("Page route", () => { - it("creates page route resource with correct path", () => { - const blogResource = - cloudFormationUpdateResources.ApiGatewayResourceBlog; - - const blogPostResource = - cloudFormationUpdateResources.ApiGatewayResourceBlogPost; - - expect(blogResource).toBeDefined(); - expect(blogPostResource).toBeDefined(); - expect(blogResource.Properties.PathPart).toEqual("blog"); - expect(blogPostResource.Properties.PathPart).toEqual("post"); - }); - - it("creates GET http method", () => { - const httpMethod = - cloudFormationUpdateResources.ApiGatewayMethodBlogPostGet; - - expect(httpMethod).toBeDefined(); - expect(httpMethod.Properties.HttpMethod).toEqual("GET"); - expect(httpMethod.Properties.ResourceId.Ref).toEqual( - "ApiGatewayResourceBlogPost" - ); - }); - - it("creates HEAD http method", () => { - const httpMethod = - cloudFormationUpdateResources.ApiGatewayMethodBlogPostHead; - - expect(httpMethod).toBeDefined(); - expect(httpMethod.Properties.HttpMethod).toEqual("HEAD"); - expect(httpMethod.Properties.ResourceId.Ref).toEqual( - "ApiGatewayResourceBlogPost" - ); - }); - }); - }); - - describe("Zip artifact", () => { - let zipEntryNames; - - beforeAll(() => { - const zip = new AdmZip( - `${fixturePath}/.serverless/nested-page-app-fixture.zip` - ); - const zipEntries = zip.getEntries(); - zipEntryNames = zipEntries.map((ze) => ze.entryName); - }); - - it("contains next compiled page", () => { - expect(zipEntryNames).toContain(`sls-next-build/blog/post.original.js`); - }); - - it("contains plugin handler", () => { - expect(zipEntryNames).toContain(`sls-next-build/blog/post.js`); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/__tests__/one-page-app.test.js b/packages/deprecated/serverless-plugin/__tests__/one-page-app.test.js deleted file mode 100644 index d1a03ecb20..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/one-page-app.test.js +++ /dev/null @@ -1,130 +0,0 @@ -const fs = require("fs"); -const nextBuild = require("next/dist/build"); -const path = require("path"); -const AdmZip = require("adm-zip"); -const { - readUpdateTemplate -} = require("../utils/test/readServerlessCFTemplate"); -const testableServerless = require("../utils/test/testableServerless"); - -jest.mock("next/dist/build"); - -describe("one page app", () => { - const fixturePath = path.join(__dirname, "./fixtures/one-page-app"); - - let cloudFormationUpdateResources; - - beforeAll(async () => { - nextBuild.default.mockResolvedValue(); - - await testableServerless(fixturePath, "package"); - - const cloudFormationUpdateTemplate = await readUpdateTemplate(fixturePath); - - cloudFormationUpdateResources = cloudFormationUpdateTemplate.Resources; - }); - - describe("Assets Bucket", () => { - describe("CF Update resources", () => { - let assetsBucket; - - beforeAll(() => { - assetsBucket = cloudFormationUpdateResources.NextStaticAssetsS3Bucket; - }); - - it("is added to the resources", () => { - expect(assetsBucket).toBeDefined(); - }); - - it("has correct bucket name", () => { - expect(assetsBucket.Properties.BucketName).toEqual("onepageappbucket"); - }); - }); - }); - - describe("Page lambda function", () => { - let pageLambda; - - beforeAll(() => { - pageLambda = cloudFormationUpdateResources.HelloLambdaFunction; - }); - - it("creates lambda resource", () => { - expect(pageLambda).toBeDefined(); - }); - - it("has correct handler", () => { - expect(pageLambda.Properties.Handler).toEqual( - "sls-next-build/hello.render" - ); - }); - - it("has user defined memory size", () => { - expect(pageLambda.Properties.MemorySize).toEqual(512); - }); - }); - - describe("Api Gateway", () => { - let apiGateway; - - beforeAll(() => { - apiGateway = cloudFormationUpdateResources.ApiGatewayRestApi; - }); - - it("creates api resource", () => { - expect(apiGateway).toBeDefined(); - }); - - describe("Page route", () => { - it("creates page route resource with correct path", () => { - const routeResource = - cloudFormationUpdateResources.ApiGatewayResourceHello; - - expect(routeResource).toBeDefined(); - expect(routeResource.Properties.PathPart).toEqual("hello"); - }); - - it("creates GET http method", () => { - const httpMethod = - cloudFormationUpdateResources.ApiGatewayMethodHelloGet; - - expect(httpMethod).toBeDefined(); - expect(httpMethod.Properties.HttpMethod).toEqual("GET"); - expect(httpMethod.Properties.ResourceId.Ref).toEqual( - "ApiGatewayResourceHello" - ); - }); - - it("creates HEAD http method", () => { - const httpMethod = - cloudFormationUpdateResources.ApiGatewayMethodHelloHead; - - expect(httpMethod).toBeDefined(); - expect(httpMethod.Properties.HttpMethod).toEqual("HEAD"); - expect(httpMethod.Properties.ResourceId.Ref).toEqual( - "ApiGatewayResourceHello" - ); - }); - }); - }); - - describe("Zip artifact", () => { - let zipEntryNames; - - beforeAll(() => { - const zip = new AdmZip( - `${fixturePath}/.serverless/one-page-app-fixture.zip` - ); - const zipEntries = zip.getEntries(); - zipEntryNames = zipEntries.map((ze) => ze.entryName); - }); - - it("contains next compiled page", () => { - expect(zipEntryNames).toContain(`sls-next-build/hello.original.js`); - }); - - it("contains plugin handler", () => { - expect(zipEntryNames).toContain(`sls-next-build/hello.js`); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/__tests__/single-api.test.js b/packages/deprecated/serverless-plugin/__tests__/single-api.test.js deleted file mode 100644 index 18bed4dc1a..0000000000 --- a/packages/deprecated/serverless-plugin/__tests__/single-api.test.js +++ /dev/null @@ -1,100 +0,0 @@ -const nextBuild = require("next/dist/build"); -const path = require("path"); -const AdmZip = require("adm-zip"); -const { - readUpdateTemplate -} = require("../utils/test/readServerlessCFTemplate"); -const testableServerless = require("../utils/test/testableServerless"); - -jest.mock("next/dist/build"); - -describe("single api", () => { - const fixturePath = path.join(__dirname, "./fixtures/single-api"); - - let cloudFormationUpdateResources; - - beforeAll(async () => { - nextBuild.default.mockResolvedValue(); - - await testableServerless(fixturePath, "package"); - - const cloudFormationUpdateTemplate = await readUpdateTemplate(fixturePath); - - cloudFormationUpdateResources = cloudFormationUpdateTemplate.Resources; - }); - - describe("Page lambda function", () => { - let pageLambda; - - beforeAll(() => { - pageLambda = cloudFormationUpdateResources.ApiDashapiLambdaFunction; - }); - - it("creates lambda resource", () => { - expect(pageLambda).toBeDefined(); - }); - - it("has correct handler", () => { - expect(pageLambda.Properties.Handler).toEqual( - "sls-next-build/api/api.render" - ); - }); - }); - - describe("Api Gateway", () => { - let apiGateway; - - beforeAll(() => { - apiGateway = cloudFormationUpdateResources.ApiGatewayRestApi; - }); - - it("creates api resource", () => { - expect(apiGateway).toBeDefined(); - }); - - describe("Page route", () => { - it("creates page route resource with correct path", () => { - const apiResource = cloudFormationUpdateResources.ApiGatewayResourceApi; - - const apiPostResource = - cloudFormationUpdateResources.ApiGatewayResourceApiApi; - - expect(apiResource).toBeDefined(); - expect(apiPostResource).toBeDefined(); - expect(apiResource.Properties.PathPart).toEqual("api"); - expect(apiPostResource.Properties.PathPart).toEqual("api"); - }); - - it("creates ANY http method", () => { - const httpMethod = - cloudFormationUpdateResources.ApiGatewayMethodApiApiAny; - - expect(httpMethod).toBeDefined(); - expect(httpMethod.Properties.HttpMethod).toEqual("ANY"); - expect(httpMethod.Properties.ResourceId.Ref).toEqual( - "ApiGatewayResourceApiApi" - ); - }); - }); - }); - - describe("Zip artifact", () => { - let zipEntryNames; - - beforeAll(() => { - const zip = new AdmZip( - `${fixturePath}/.serverless/single-api-fixture.zip` - ); - const zipEntries = zip.getEntries(); - zipEntryNames = zipEntries.map((ze) => ze.entryName); - }); - - it("contains next compiled page", () => { - expect(zipEntryNames).toContain(`sls-next-build/api/api.original.js`); - }); - - it("contains plugin handler", () => { - expect(zipEntryNames).toContain(`sls-next-build/api/api.js`); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/classes/NextPage.js b/packages/deprecated/serverless-plugin/classes/NextPage.js deleted file mode 100644 index 8dd06a3607..0000000000 --- a/packages/deprecated/serverless-plugin/classes/NextPage.js +++ /dev/null @@ -1,155 +0,0 @@ -const path = require("path"); -const merge = require("lodash.merge"); -const clone = require("lodash.clonedeep"); -const toPosix = require("../utils/pathToPosix"); -const PluginBuildDir = require("./PluginBuildDir"); - -class NextPage { - constructor(pagePath, { serverlessFunctionOverrides, routes } = {}) { - this.isApi = pagePath.indexOf(path.join("sls-next-build", "api")) === 0; - this.pagePath = pagePath; - this.serverlessFunctionOverrides = serverlessFunctionOverrides; - this.routes = routes; - } - - get pageOriginalPath() { - return path.join(this.pageDir, `${this.pageName}.original.js`); - } - - get pageCompatPath() { - return path.join(this.pageDir, `${this.pageName}.compat.js`); - } - - get pageDir() { - return path.dirname(this.pagePath); - } - - get pageId() { - const pathSegments = this.pagePath.split(path.sep); - - // strip out the parent build directory from path - // sls-next-build/foo/bar.js -> /foo/bar.js - const relativePathSegments = pathSegments.slice( - pathSegments.indexOf(PluginBuildDir.BUILD_DIR_NAME) + 1, - pathSegments.length - ); - - // remove extension - // foo/bar.js -> /foo/bar - const parsed = path.parse(relativePathSegments.join(path.posix.sep)); - return path.posix.join(parsed.dir, parsed.name); - } - - get pageName() { - return path.basename(this.pagePath, ".js"); - } - - get pageHandler() { - const dir = path.dirname(this.pagePath); - const handler = path.join(dir, this.pageName + ".render"); - const posixHandler = toPosix(handler); - return posixHandler; - } - - get functionName() { - if (this.pageId === "_error") { - return "not-found"; - } - - return this.pageId - .replace(new RegExp(path.posix.sep, "g"), "-") - .replace(/^-/, "") - .replace(/[^\w-]/g, "_"); - } - - get pageRoute() { - switch (this.pageId) { - case "index": - return "/"; - case "_error": - return "/{proxy+}"; - default: - // handle pages at any subdir level - // e.g. sls-next-build/post.js - // sls-next-build/categories/post.js - // sls-next-build/categories/fridge/index.js - // app/sls-next-build/index.js - const pathSegments = this.pagePath.split(path.sep); - const buildDirIndex = pathSegments.indexOf( - PluginBuildDir.BUILD_DIR_NAME - ); - - const routeSegments = pathSegments - .slice(buildDirIndex + 1, pathSegments.length - 1) - .concat([this.pageName]); - - const originalPath = routeSegments.join("/"); - const pathWithReplacedBrackets = originalPath - .replace(/\[/g, "{") - .replace(/\]/g, "}"); - - return pathWithReplacedBrackets; - } - } - - get serverlessFunction() { - const configuration = { - handler: this.pageHandler, - events: [ - { - http: { - path: this.pageRoute, - method: this.isApi ? "any" : "get" - } - } - ] - }; - - if (this.serverlessFunctionOverrides) { - delete this.serverlessFunctionOverrides.handler; - delete this.serverlessFunctionOverrides.runtime; - - merge(configuration, this.serverlessFunctionOverrides); - } - - if (this.routes && this.routes.length > 0) { - configuration.events = []; - - this.routes.forEach((r) => { - const httpEvent = this.getHttpEventForRoute(r); - configuration.events.push(httpEvent); - }); - } - - const httpHeadEvents = this.getMatchingHttpHeadEvents( - configuration.events.filter((e) => e.http.method === "get") - ); - - configuration.events = configuration.events.concat(httpHeadEvents); - - return { - [this.functionName]: configuration - }; - } - - getMatchingHttpHeadEvents(httpGetEvents) { - return httpGetEvents.map((e) => { - const headEvent = clone(e); - headEvent.http.method = "head"; - return headEvent; - }); - } - - getHttpEventForRoute(route) { - const httpEvent = { - http: { - method: "get", - ...route - } - }; - - return httpEvent; - } -} - -module.exports = NextPage; diff --git a/packages/deprecated/serverless-plugin/classes/PluginBuildDir.js b/packages/deprecated/serverless-plugin/classes/PluginBuildDir.js deleted file mode 100644 index 7044b14826..0000000000 --- a/packages/deprecated/serverless-plugin/classes/PluginBuildDir.js +++ /dev/null @@ -1,32 +0,0 @@ -const path = require("path"); -const fs = require("fs-extra"); -const logger = require("../utils/logger"); - -class PluginBuildDir { - constructor(nextConfigDir) { - this.nextConfigDir = nextConfigDir; - } - - get buildDir() { - return path.join(this.nextConfigDir, PluginBuildDir.BUILD_DIR_NAME); - } - - get posixBuildDir() { - return path.posix.join(this.nextConfigDir, PluginBuildDir.BUILD_DIR_NAME); - } - - static get BUILD_DIR_NAME() { - return "sls-next-build"; - } - - setupBuildDir() { - return fs.emptyDir(this.buildDir); - } - - removeBuildDir() { - logger.log("Cleaning up tmp build folder ..."); - return fs.remove(this.buildDir); - } -} - -module.exports = PluginBuildDir; diff --git a/packages/deprecated/serverless-plugin/classes/__tests__/NextPage.test.js b/packages/deprecated/serverless-plugin/classes/__tests__/NextPage.test.js deleted file mode 100644 index 44bc163161..0000000000 --- a/packages/deprecated/serverless-plugin/classes/__tests__/NextPage.test.js +++ /dev/null @@ -1,397 +0,0 @@ -const path = require("path"); -const NextPage = require("../NextPage"); -const PluginBuildDir = require("../PluginBuildDir"); - -describe("NextPage", () => { - describe("#constructor", () => { - it("sets a pagePath", () => { - const pagePath = `${PluginBuildDir.BUILD_DIR_NAME}/home.js`; - const page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - - expect(page.pagePath).toEqual(pagePath); - }); - }); - - describe("Simple page", () => { - const buildDir = PluginBuildDir.BUILD_DIR_NAME; - const pagePath = path.join(buildDir, "admin.js"); - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - it("returns pageCompatPath", () => { - expect(page.pageCompatPath).toEqual( - path.join(buildDir, "admin.compat.js") - ); - }); - - it("returns pageOriginalPath", () => { - expect(page.pageOriginalPath).toEqual( - path.join(buildDir, "admin.original.js") - ); - }); - - it("returns pageDir", () => { - expect(page.pageDir).toEqual(buildDir); - }); - - it("returns pageName", () => { - expect(page.pageName).toEqual("admin"); - }); - - it("returns pageHandler", () => { - expect(page.pageHandler).toEqual( - `${PluginBuildDir.BUILD_DIR_NAME}/admin.render` - ); - }); - - it("returns pageFunctionName", () => { - expect(page.functionName).toEqual("admin"); - }); - - it("replaces non-alphanumeric chars in pageFunctionName", () => { - const pagePath = path.join(buildDir, "$home.js"); - const page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - expect(page.functionName).toEqual("_home"); - }); - - it("returns pageId", () => { - expect(page.pageId).toEqual("admin"); - }); - - describe("#serverlessFunction", () => { - it("returns function name", () => { - const pageFunction = page.serverlessFunction; - expect(pageFunction.admin).toBeDefined(); - }); - - it("returns function handler", () => { - const { handler } = page.serverlessFunction.admin; - expect(handler).toEqual(`${buildDir}/admin.render`); - }); - - it("returns 2 http events", () => { - const { events } = page.serverlessFunction.admin; - expect(events).toHaveLength(2); - }); - - it("returns function http GET event", () => { - const { events } = page.serverlessFunction.admin; - - const httpEvent = events[0].http; - - expect(httpEvent.path).toEqual("admin"); - expect(httpEvent.method).toEqual("get"); - }); - - it("returns function http HEAD event", () => { - const { events } = page.serverlessFunction.admin; - - const httpEvent = events[1].http; - - expect(httpEvent.path).toEqual("admin"); - expect(httpEvent.method).toEqual("head"); - }); - - describe("When pageConfig override is provided", () => { - it("creates identical HEAD route for custom GET route", () => { - const serverlessFunctionOverrides = { - events: [ - { - http: { - path: "admin/{id}", - request: { - parameters: { - id: true - } - } - } - } - ] - }; - - const pageWithCustomConfig = new NextPage(pagePath, { - serverlessFunctionOverrides, - routes: [] - }); - - const { events } = pageWithCustomConfig.serverlessFunction.admin; - expect(events).toHaveLength(2); - - const httpGet = events[0].http; - const httpHead = events[1].http; - - expect(httpGet.method).toBe("get"); - expect(httpHead.method).toBe("head"); - - expect(httpGet.path).toBe("admin/{id}"); - expect(httpHead.path).toBe("admin/{id}"); - - expect(httpGet.request.parameters.id).toBe(true); - expect(httpHead.request.parameters.id).toBe(true); - }); - - it("overrides serverlessFunction with provided pageConfig", () => { - const serverlessFunctionOverrides = { foo: "bar" }; - - const pageWithCustomConfig = new NextPage(pagePath, { - serverlessFunctionOverrides, - routes: [] - }); - - expect(pageWithCustomConfig.serverlessFunction.admin.foo).toBe("bar"); - }); - - it("doesn't change handler with provided pageConfig", () => { - const serverlessFunctionOverrides = { handler: "invalid/handler" }; - - const pageWithCustomConfig = new NextPage(pagePath, { - serverlessFunctionOverrides, - routes: [] - }); - - expect(pageWithCustomConfig.serverlessFunction.admin.handler).toBe( - pageWithCustomConfig.pageHandler - ); - }); - - it("doesn't change runtime with provided pageConfig", () => { - const serverlessFunctionOverrides = { runtime: "python2.7" }; - - const pageWithCustomConfig = new NextPage(pagePath, { - serverlessFunctionOverrides, - routes: [] - }); - - expect(pageWithCustomConfig.serverlessFunction.admin.runtime).toBe( - undefined - ); - }); - }); - }); - }); - - describe("When is the index page", () => { - const buildDir = PluginBuildDir.BUILD_DIR_NAME; - const pagePath = path.join(buildDir, "index.js"); - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - it("returns pageId", () => { - expect(page.pageId).toEqual("index"); - }); - - describe("#serverlessFunction", () => { - it("returns http GET event with path /", () => { - const { events } = page.serverlessFunction.index; - - const httpEvent = events[0].http; - expect(httpEvent.method).toEqual("get"); - expect(httpEvent.path).toEqual("/"); - }); - - it("returns http HEAD event with path /", () => { - const { events } = page.serverlessFunction.index; - - const httpEvent = events[1].http; - expect(httpEvent.method).toEqual("head"); - expect(httpEvent.path).toEqual("/"); - }); - }); - }); - - describe("When is the _error page", () => { - const buildDir = PluginBuildDir.BUILD_DIR_NAME; - const pagePath = path.join(buildDir, "_error.js"); - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - describe("#serverlessFunction", () => { - it("should name the function not-found", () => { - expect(page.serverlessFunction["not-found"]).toBeDefined(); - }); - - it("returns two events", () => { - const { events } = page.serverlessFunction["not-found"]; - expect(events).toHaveLength(2); - }); - - it("returns http event path /{proxy+} with GET method", () => { - const { events } = page.serverlessFunction["not-found"]; - - const httpGet = events[0].http; - - expect(httpGet.path).toEqual("/{proxy+}"); - expect(httpGet.method).toEqual("get"); - }); - - it("returns http event path /{proxy+} with HEAD method", () => { - const { events } = page.serverlessFunction["not-found"]; - - const httpHead = events[1].http; - - expect(httpHead.path).toEqual("/{proxy+}"); - expect(httpHead.method).toEqual("head"); - }); - }); - }); - - describe("When is a nested page", () => { - const buildDir = PluginBuildDir.BUILD_DIR_NAME; - const pagePath = path.join(buildDir, "categories/fridge/fridges.js"); - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - it("returns pageId", () => { - expect(page.pageId).toEqual("categories/fridge/fridges"); - }); - - describe("#serverlessFunction", () => { - it("returns URI path matching subdirectories", () => { - const { events } = page.serverlessFunction["categories-fridge-fridges"]; - - expect(events).toHaveLength(2); - - const httpGet = events[0].http; - const httpHead = events[1].http; - - expect(httpGet.path).toEqual("categories/fridge/fridges"); - expect(httpGet.method).toEqual("get"); - expect(httpHead.path).toEqual("categories/fridge/fridges"); - expect(httpHead.method).toEqual("head"); - }); - }); - }); - - describe("When pagePath has win format", () => { - const buildDir = PluginBuildDir.BUILD_DIR_NAME; - const pagePath = `${buildDir}\\admin.js`; - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - it("returns posix pageHandler", () => { - expect(page.pageHandler).toEqual( - `${PluginBuildDir.BUILD_DIR_NAME}/admin.render` - ); - }); - }); - - describe("When the build directory is a subdirectory", () => { - const buildDir = path.join("app", PluginBuildDir.BUILD_DIR_NAME); - const pagePath = path.join(buildDir, "admin.js"); - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - it("returns pageHandler", () => { - expect(page.pageHandler).toEqual( - `app/${PluginBuildDir.BUILD_DIR_NAME}/admin.render` - ); - }); - - it("returns pageRoute", () => { - expect(page.pageRoute).toEqual("admin"); - }); - - it("returns pageId", () => { - expect(page.pageId).toEqual("admin"); - }); - }); - - describe("When dynamic route with square brackets is defined", () => { - const buildDir = PluginBuildDir.BUILD_DIR_NAME; - const pagePath = `${buildDir}/[id].js`; - let page; - - beforeEach(() => { - page = new NextPage(pagePath, { - serverlessFunctionOverrides: {}, - routes: [] - }); - }); - - it("replaces square brackets with curly brackets", () => { - expect(page.pageRoute).toEqual("{id}"); - }); - }); - - describe("When custom routes are provided", () => { - let pageWithCustomRoutes; - - beforeEach(() => { - pageWithCustomRoutes = new NextPage( - path.join(PluginBuildDir.BUILD_DIR_NAME, "foo.js"), - { - routes: [ - { - path: "/custom/path/to/foo" - }, - { - path: "/another/custom/path/to/foo" - } - ] - } - ); - }); - - it("sets http GET and HEAD events for the route given", () => { - const { events } = pageWithCustomRoutes.serverlessFunction.foo; - expect(events).toHaveLength(4); - - const httpGetOne = events[0].http; - const httpGetTwo = events[1].http; - const httpHeadOne = events[2].http; - const httpHeadTwo = events[3].http; - - expect(httpGetOne.method).toBe("get"); - expect(httpHeadOne.method).toBe("head"); - expect(httpGetOne.path).toBe("/custom/path/to/foo"); - expect(httpHeadOne.path).toBe("/custom/path/to/foo"); - - expect(httpGetTwo.method).toBe("get"); - expect(httpHeadTwo.method).toBe("head"); - expect(httpGetTwo.path).toBe("/another/custom/path/to/foo"); - expect(httpHeadTwo.path).toBe("/another/custom/path/to/foo"); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/classes/__tests__/PluginBuildDir.test.js b/packages/deprecated/serverless-plugin/classes/__tests__/PluginBuildDir.test.js deleted file mode 100644 index 413485380c..0000000000 --- a/packages/deprecated/serverless-plugin/classes/__tests__/PluginBuildDir.test.js +++ /dev/null @@ -1,85 +0,0 @@ -const path = require("path"); -const fs = require("fs-extra"); -const PluginBuildDir = require("../PluginBuildDir"); -const logger = require("../../utils/logger"); - -jest.mock("fs-extra"); -jest.mock("../../utils/logger"); - -describe("PluginBuildDir", () => { - describe("#constructor", () => { - it("should set the next config directory", () => { - const nextConfigDir = "/path/to/nextApp"; - const pluginBuildDir = new PluginBuildDir(nextConfigDir); - - expect(pluginBuildDir.nextConfigDir).toEqual(nextConfigDir); - }); - }); - - describe("When a new instance is created", () => { - let pluginBuildDir; - let nextConfigDir; - - beforeEach(() => { - nextConfigDir = "path/to/nextApp"; - pluginBuildDir = new PluginBuildDir(nextConfigDir); - }); - - it("should have buildDir at same level as next config.", () => { - expect(pluginBuildDir.buildDir).toEqual( - path.join(nextConfigDir, PluginBuildDir.BUILD_DIR_NAME) - ); - }); - - it("should have posixBuildDir regardless the platform", () => { - expect(pluginBuildDir.posixBuildDir).toEqual( - `path/to/nextApp/${PluginBuildDir.BUILD_DIR_NAME}` - ); - }); - }); - - describe("#setupBuildDir", () => { - it("should call fs emptyDir to create dir if doesnt exist or cleanup", () => { - expect.assertions(1); - - fs.emptyDir.mockResolvedValueOnce(); - const nextConfigDir = "path/to/nextApp"; - - const pluginBuildDir = new PluginBuildDir(nextConfigDir); - - return pluginBuildDir.setupBuildDir().then(() => { - expect(fs.emptyDir).toBeCalledWith(pluginBuildDir.buildDir); - }); - }); - }); - - describe("#removeBuildDir", () => { - it("should log when it starts removing", () => { - expect.assertions(1); - - fs.remove.mockResolvedValueOnce(); - const nextConfigDir = "path/to/nextApp"; - - const pluginBuildDir = new PluginBuildDir(nextConfigDir); - - return pluginBuildDir.removeBuildDir().then(() => { - expect(logger.log).toBeCalledWith( - expect.stringContaining("Cleaning up") - ); - }); - }); - - it("should call fs remove", () => { - expect.assertions(1); - - fs.remove.mockResolvedValueOnce(); - const nextConfigDir = "path/to/nextApp"; - - const pluginBuildDir = new PluginBuildDir(nextConfigDir); - - return pluginBuildDir.removeBuildDir().then(() => { - expect(fs.remove).toBeCalledWith(pluginBuildDir.buildDir); - }); - }); - }); -}); diff --git a/packages/deprecated/serverless-plugin/demo.gif b/packages/deprecated/serverless-plugin/demo.gif deleted file mode 100644 index 7435f78234cd4cd110ded49196319bb1be463ac9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190454 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 z 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