From e42c3c3cbe201fac85f663883bd061a2548d8680 Mon Sep 17 00:00:00 2001 From: Jordan Laramie Date: Tue, 22 Oct 2019 17:56:03 -0400 Subject: [PATCH 1/6] Fix #214 Fully decouple next build from component - Removed `next build` - Updated README with changes - Added missing `inputs` to README - Clarified the use of `nextConfigDir` - Modified `deploy` step --- .../serverless-nextjs-component/README.md | 21 ++++++++++++++----- .../serverless-nextjs-component/serverless.js | 4 ---- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/serverless-nextjs-component/README.md b/packages/serverless-nextjs-component/README.md index a620037bbb..0f999d481d 100644 --- a/packages/serverless-nextjs-component/README.md +++ b/packages/serverless-nextjs-component/README.md @@ -75,10 +75,19 @@ AWS_ACCESS_KEY_ID=accesskey AWS_SECRET_ACCESS_KEY=sshhh ``` +Set next.js build target to `serverless`: +```js +// next.config.js + +module.exports = { + target: 'serverless' +} +``` + And simply deploy: ```bash -$ serverless +$ next-build && serverless ``` ### Custom domain name @@ -118,10 +127,12 @@ The fourth cache behaviour handles next API requests `api/*`. ### Inputs -| Name | Type | Default Value | Description | -| ---------- | -------- | ------------- | ------------------------------------------------------------------------------- | -| domain | `Array` | `null` | For example `['admin', 'portal.com']`. | -| bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | +| Name | Type | Default Value | Description | +| ------------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| domain | `Array` | `null` | For example `['admin', 'portal.com']`. | +| bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | +| nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | +| build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy | | Custom inputs can be configured like this: diff --git a/packages/serverless-nextjs-component/serverless.js b/packages/serverless-nextjs-component/serverless.js index 9d9ea51df2..eb004780aa 100644 --- a/packages/serverless-nextjs-component/serverless.js +++ b/packages/serverless-nextjs-component/serverless.js @@ -177,10 +177,6 @@ class NextjsComponent extends Component { ? path.resolve(inputs.nextConfigDir) : process.cwd(); - await execa("node_modules/.bin/next", ["build"], { - cwd: nextConfigPath - }); - await this.emptyBuildDirectory(nextConfigPath); const { From 067a7b2e67b6670d7577438d576bd2da0c791ae6 Mon Sep 17 00:00:00 2001 From: Jordan Laramie Date: Tue, 22 Oct 2019 18:09:37 -0400 Subject: [PATCH 2/6] Added a `nextStaticDir` input for determining where the next.js static resources folder lives --- packages/serverless-nextjs-component/README.md | 1 + packages/serverless-nextjs-component/serverless.js | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/serverless-nextjs-component/README.md b/packages/serverless-nextjs-component/README.md index 0f999d481d..7b2c769c52 100644 --- a/packages/serverless-nextjs-component/README.md +++ b/packages/serverless-nextjs-component/README.md @@ -133,6 +133,7 @@ The fourth cache behaviour handles next API requests `api/*`. | bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | | nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | | build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy | | +| staticDir | `string` | `./` | If your `static` or `public` directory is not a direct child of `nextConfigDir` this is needed. | Custom inputs can be configured like this: diff --git a/packages/serverless-nextjs-component/serverless.js b/packages/serverless-nextjs-component/serverless.js index eb004780aa..34fa550e33 100644 --- a/packages/serverless-nextjs-component/serverless.js +++ b/packages/serverless-nextjs-component/serverless.js @@ -199,6 +199,7 @@ class NextjsComponent extends Component { const nextConfigPath = inputs.nextConfigDir ? path.resolve(inputs.nextConfigDir) : process.cwd(); + const nextStaticPath = inputs.nextStaticDir || ""; const [defaultBuildManifest, apiBuildManifest] = await Promise.all([ this.readDefaultBuildManifest(nextConfigPath), @@ -239,14 +240,14 @@ class NextjsComponent extends Component { ]; const [publicDirExists, staticDirExists] = await Promise.all([ - fse.exists(join(nextConfigPath, "public")), - fse.exists(join(nextConfigPath, "static")) + fse.exists(join(nextConfigPath, nextStaticPath, "public")), + fse.exists(join(nextConfigPath, nextStaticPath, "static")) ]); if (publicDirExists) { assetsUpload.push( bucket.upload({ - dir: join(nextConfigPath, "public"), + dir: join(nextConfigPath, nextStaticPath, "public"), keyPrefix: "public" }) ); @@ -255,7 +256,7 @@ class NextjsComponent extends Component { if (staticDirExists) { assetsUpload.push( bucket.upload({ - dir: join(nextConfigPath, "static"), + dir: join(nextConfigPath, nextStaticPath, "static"), keyPrefix: "static" }) ); From e88bd9a5f3bb035be0f972a3b2748267efbdde7f Mon Sep 17 00:00:00 2001 From: Jordan Laramie Date: Tue, 22 Oct 2019 23:36:57 -0400 Subject: [PATCH 3/6] Modified `nextStaticDir` so that it replaces `nextConfigDir` instead of appending to it. I think this is clearer to configure. --- packages/serverless-nextjs-component/serverless.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/serverless-nextjs-component/serverless.js b/packages/serverless-nextjs-component/serverless.js index 34fa550e33..f8ac8a03df 100644 --- a/packages/serverless-nextjs-component/serverless.js +++ b/packages/serverless-nextjs-component/serverless.js @@ -200,6 +200,7 @@ class NextjsComponent extends Component { ? path.resolve(inputs.nextConfigDir) : process.cwd(); const nextStaticPath = inputs.nextStaticDir || ""; + const staticPath = nextStaticPath || nextConfigPath; const [defaultBuildManifest, apiBuildManifest] = await Promise.all([ this.readDefaultBuildManifest(nextConfigPath), @@ -240,14 +241,14 @@ class NextjsComponent extends Component { ]; const [publicDirExists, staticDirExists] = await Promise.all([ - fse.exists(join(nextConfigPath, nextStaticPath, "public")), - fse.exists(join(nextConfigPath, nextStaticPath, "static")) + fse.exists(join(staticPath, "public")), + fse.exists(join(staticPath, "static")) ]); if (publicDirExists) { assetsUpload.push( bucket.upload({ - dir: join(nextConfigPath, nextStaticPath, "public"), + dir: join(staticPath, "public"), keyPrefix: "public" }) ); @@ -256,7 +257,7 @@ class NextjsComponent extends Component { if (staticDirExists) { assetsUpload.push( bucket.upload({ - dir: join(nextConfigPath, nextStaticPath, "static"), + dir: join(staticPath, "static"), keyPrefix: "static" }) ); From a737546c3dbf47f9ff960764d2d90400a75e50ac Mon Sep 17 00:00:00 2001 From: Jordan Laramie Date: Sun, 15 Dec 2019 12:40:25 -0500 Subject: [PATCH 4/6] Fix #214 Fully decouple next build from component - Add buildScripts input - Updated README with changes --- .../serverless-nextjs-component/README.md | 30 ++++++++++------ .../serverless-nextjs-component/serverless.js | 34 +++++++++++++++++++ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/packages/serverless-nextjs-component/README.md b/packages/serverless-nextjs-component/README.md index 2dd1d4b956..aa114a8e6a 100644 --- a/packages/serverless-nextjs-component/README.md +++ b/packages/serverless-nextjs-component/README.md @@ -77,18 +77,19 @@ AWS_SECRET_ACCESS_KEY=sshhh ``` Set next.js build target to `serverless`: + ```js // next.config.js module.exports = { - target: 'serverless' -} + target: "serverless" +}; ``` And simply deploy: ```bash -$ next-build && serverless +$ serverless ``` ### Custom domain name @@ -154,13 +155,22 @@ The fourth cache behaviour handles next API requests `api/*`. ### Inputs -| Name | Type | Default Value | Description | -| ------------- | --------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| domain | `Array` | `null` | For example `['admin', 'portal.com']`. | -| bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | -| nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | -| build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy | | -| staticDir | `string` | `./` | If your `static` or `public` directory is not a direct child of `nextConfigDir` this is needed. | +| Name | Type | Default Value | Description | +| --------------------- | --------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| domain | `Array` | `null` | For example `['admin', 'portal.com']`. | +| bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | +| nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | +| nextStaticDir | `string` | `./` | If your `static` or `public` directory is not a direct child of `nextConfigDir` this is needed. | +| build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy. | | +| nextBuildArguments | `Array|string` | `[]` | Allows for additional arguments when calling `next build` . | +| **Advanced Usage** | +| buildScripts | `Array[Object]` | `Default Build` | Allows for overriding and adding additional scripts to run before deploy. The default values are below and are the parameters used if no `inputs.buildScripts` are passed. | +| buildScripts[name] | `string` | `NextJS Build` | Each script can have a name but it defaults to the `index` of the script. | +| buildScripts[cmd] | `string` | `node_modules/.bin/next` | Each script can have a name but it defaults to the `index` of the script. | +| buildScripts[args] | `Array|string` | `['build', ...inputs.nextBuildArguments]` | Arguments to pass to the build | +| buildScripts[cwd] | `string` | `./` | Override the current working directory | +| buildScripts[enabled] | `boolean` | `true` | Useful for disabling or conditionally enabling build scripts. | +| buildScripts[env] | `Object` | `{}` | Add additional environment variables to the script. | Custom inputs can be configured like this: diff --git a/packages/serverless-nextjs-component/serverless.js b/packages/serverless-nextjs-component/serverless.js index ba43121ecc..d8aad284f8 100644 --- a/packages/serverless-nextjs-component/serverless.js +++ b/packages/serverless-nextjs-component/serverless.js @@ -237,6 +237,40 @@ class NextjsComponent extends Component { ? path.resolve(inputs.nextConfigDir) : process.cwd(); + if (!inputs.buildScripts || inputs.buildScripts.length === 0) { + inputs.buildScripts = [ + { + name: "NextJS Build", + cmd: "node_modules/.bin/next", + args: ["build"].concat(inputs.nextBuildArguments || []), + cwd: nextConfigPath + } + ]; + } else { + inputs.buildScripts.forEach(buildScript => { + buildScript.cwd = buildScript.cwd + ? path.resolve(buildScript.cwd) + : process.cwd(); + }); + } + + for (var i = 0, len = inputs.buildScripts.length; i < len; i++) { + let { name, cmd, args, cwd, env, enabled } = inputs.buildScripts[i]; + + if (enabled === false) { + continue; + } + + this.context.status( + `Running Build Script: ${name || i} - ${i + 1} of ${len}` + ); + + await execa(cmd, args, { + cwd, + env + }); + } + await this.emptyBuildDirectory(nextConfigPath); const { From eef3ededd15df2252ca8b4ab5474925d2b4ca4e2 Mon Sep 17 00:00:00 2001 From: Jordan Laramie Date: Sun, 15 Dec 2019 13:10:55 -0500 Subject: [PATCH 5/6] Fixing readme --- packages/serverless-nextjs-component/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/serverless-nextjs-component/README.md b/packages/serverless-nextjs-component/README.md index 1c73d59fd5..8564deeda8 100644 --- a/packages/serverless-nextjs-component/README.md +++ b/packages/serverless-nextjs-component/README.md @@ -134,6 +134,7 @@ myNextApplication: Make sure you add CloudWatch log permissions to your custom policy. ### Lambda memory + Both **default** and **api** lambdas will be assigned 512mb of memory by default. This value can be altered by assigning a number to the `memory` input ```yml @@ -186,8 +187,8 @@ The fourth cache behaviour handles next API requests `api/*`. | bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | | nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | | nextStaticDir | `string` | `./` | If your `static` or `public` directory is not a direct child of `nextConfigDir` this is needed. | -| build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy. | | -| memory | `number` or `object` | `512` | When assigned a number, both the default and api lambdas will assigned memory of that value. When assigned to an object, values for the default and api lambdas can be separately defined | +| build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy. | +| memory | `number` or `object` | `512` | When assigned a number, both the default and api lambdas will assigned memory of that value. When assigned to an object, values for the default and api lambdas can be separately defined | | nextBuildArguments | `Array|string` | `[]` | Allows for additional arguments when calling `next build` . | | **Advanced Usage** | | buildScripts | `Array[Object]` | `Default Build` | Allows for overriding and adding additional scripts to run before deploy. The default values are below and are the parameters used if no `inputs.buildScripts` are passed. | From ebbf84debe7aed568c44faad9c99e41438757a6e Mon Sep 17 00:00:00 2001 From: Jordan Laramie Date: Sun, 22 Dec 2019 12:18:05 -0500 Subject: [PATCH 6/6] Fix #214-build-override - Replaced input.buildScripts with just input.build - Updated readme and provided an example for using --- .../serverless-nextjs-component/README.md | 46 ++++++++++++------- .../serverless-nextjs-component/serverless.js | 39 +++++----------- 2 files changed, 41 insertions(+), 44 deletions(-) diff --git a/packages/serverless-nextjs-component/README.md b/packages/serverless-nextjs-component/README.md index 8564deeda8..b764bb96a1 100644 --- a/packages/serverless-nextjs-component/README.md +++ b/packages/serverless-nextjs-component/README.md @@ -181,23 +181,19 @@ The fourth cache behaviour handles next API requests `api/*`. ### Inputs -| Name | Type | Default Value | Description | -| --------------------- | -------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| domain | `Array` | `null` | For example `['admin', 'portal.com']`. | -| bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | -| nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | -| nextStaticDir | `string` | `./` | If your `static` or `public` directory is not a direct child of `nextConfigDir` this is needed. | -| build | `boolean` | `true` | When true builds and deploys app, when false assume the app has been built and uses the .next .serverless_nextjs directories in nextConfigDir to deploy. | -| memory | `number` or `object` | `512` | When assigned a number, both the default and api lambdas will assigned memory of that value. When assigned to an object, values for the default and api lambdas can be separately defined | -| nextBuildArguments | `Array|string` | `[]` | Allows for additional arguments when calling `next build` . | -| **Advanced Usage** | -| buildScripts | `Array[Object]` | `Default Build` | Allows for overriding and adding additional scripts to run before deploy. The default values are below and are the parameters used if no `inputs.buildScripts` are passed. | -| buildScripts[name] | `string` | `NextJS Build` | Each script can have a name but it defaults to the `index` of the script. | -| buildScripts[cmd] | `string` | `node_modules/.bin/next` | Each script can have a name but it defaults to the `index` of the script. | -| buildScripts[args] | `Array|string` | `['build', ...inputs.nextBuildArguments]` | Arguments to pass to the build | -| buildScripts[cwd] | `string` | `./` | Override the current working directory | -| buildScripts[enabled] | `boolean` | `true` | Useful for disabling or conditionally enabling build scripts. | -| buildScripts[env] | `Object` | `{}` | Add additional environment variables to the script. | +| Name | Type | Default Value | Description | +| ------------- | --------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| domain | `Array` | `null` | For example `['admin', 'portal.com']`. | +| bucketName | `string` | `null` | Custom bucket name where static assets are stored. By default is autogenerated. | +| nextConfigDir | `string` | `./` | Directory where your application `next.config.js` file is. This input is useful when the `serverless.yml` is not in the same directory as the next app.
**Note:** `nextConfigDir` should be set if `next.config.js` `distDir` is used. | +| nextStaticDir | `string` | `./` | If your `static` or `public` directory is not a direct child of `nextConfigDir` this is needed. | +| memory | `number` or `object` | `512` | When assigned a number, both the default and api lambdas will assigned memory of that value. When assigned to an object, values for the default and api lambdas can be separately defined | | +| build | `boolean` or `Object` | `true` | When true builds and deploys app, when false assume the app has been built and uses the `.next` `.serverless_nextjs` directories in `nextConfigDir` to deploy. If an object is passed `build` allows for overriding what script gets called and with what arguments. | +| build.cmd | `string` | `node_modules/.bin/next` | Build command | +| build.args | `Array|string` | `['build']` | Arguments to pass to the build | +| build.cwd | `string` | `./` | Override the current working directory | +| build.enabled | `boolean` | `true` | Same as passing `build:false` but from within the config. | +| build.env | `Object` | `{}` | Add additional environment variables to the script. | Custom inputs can be configured like this: @@ -266,6 +262,22 @@ The serverless team is currently working on remote state storage so this won't b Serverless next.js is _regionless_. By design, `serverless-next.js` applications will be deployed across the globe to every CloudFront edge location. The lambda might look like is only deployed to `us-east-1` but behind the scenes, it is replicated to every other region. +#### I require passing additional information into my build + +See the sample below for an advanced `build` setup that includes passing additional arguments and environment variables to the build. + +```yml +# serverless.yml +myDatabase: + component: MY_DATABASE_COMPNENT +myNextApp: + component: serverless-next.js + build: + args: ["build", "custom/path/to/pages"] + env: + DATABASE_URL: ${myDatabase.databaseUrl} +``` + ## Contributing Please see the [contributing](./CONTRIBUTING.md) guide. diff --git a/packages/serverless-nextjs-component/serverless.js b/packages/serverless-nextjs-component/serverless.js index 05a3e2e97f..93da4e75e6 100644 --- a/packages/serverless-nextjs-component/serverless.js +++ b/packages/serverless-nextjs-component/serverless.js @@ -237,34 +237,19 @@ class NextjsComponent extends Component { ? path.resolve(inputs.nextConfigDir) : process.cwd(); - if (!inputs.buildScripts || inputs.buildScripts.length === 0) { - inputs.buildScripts = [ - { - name: "NextJS Build", - cmd: "node_modules/.bin/next", - args: ["build"].concat(inputs.nextBuildArguments || []), - cwd: nextConfigPath - } - ]; - } else { - inputs.buildScripts.forEach(buildScript => { - buildScript.cwd = buildScript.cwd - ? path.resolve(buildScript.cwd) - : process.cwd(); - }); - } - - for (var i = 0, len = inputs.buildScripts.length; i < len; i++) { - let { name, cmd, args, cwd, env, enabled } = inputs.buildScripts[i]; - - if (enabled === false) { - continue; - } - - this.context.status( - `Running Build Script: ${name || i} - ${i + 1} of ${len}` - ); + const buildConfig = { + enabled: inputs.build && inputs.build.enabled !== false, + cmd: "node_modules/.bin/next", + args: ["build"], + ...(typeof inputs.build === "object" ? inputs.build : {}), + cwd: + inputs.build && inputs.build.cwd + ? path.resolve(inputs.build.cwd) + : nextConfigPath + }; + if (buildConfig.enabled) { + let { cmd, args, cwd, env } = buildConfig; await execa(cmd, args, { cwd, env