serverless-nextjs / serverless-next.js

⚡ Deploy your Next.js apps on AWS Lambda@Edge via Serverless Components
MIT License
4.45k stars 455 forks source link

YAML config variables #199

Open mbenitezm opened 5 years ago

mbenitezm commented 5 years ago

Hi!

I'm migrating a project that used serverless-nextjs-plugin to this serverless-next.js but I'm having some issues with the serverless.yml file.

Previously I used this to assign the bucketName:

custom:
  serverless-nextjs:
    assetsBucketName: ${file(./s3BucketName.js):s3BucketName}

and now it looks like this:

appName:
  component: serverless-next.js
  inputs:
    bucketName: ${file(./s3BucketName.js):s3BucketName}

${file(./s3BucketName.js):s3BucketName} doesn't seem to be working any longer as I get the error: InvalidBucket: Bucket names cannot contain forward slashes. Bucket: ${file(./s3BucketName.js):s3BucketName}

After this I went through serverless components Readme and it said I could use env variables in the yaml, so I changed the bucketName assignment to: bucketName: ${env.BUCKET_NAME} and now get error: Error: invalid reference ${env.BUCKET_NAME}

The reason behind trying to do it this way is because I have multiple environments on which I want to deploy. So depending on the environment variable I set the name of the s3BucketName, but now I find no way to read this or the environment variable.

Also. I was able before to set the stage this way, but I no longer know where this config should be written, or if it should be written at all:

provider:
  name: aws
  runtime: nodejs10.x
  memorySize: 512
  stage: ${opt:stage, 'dev'}

I'm not sure if I'm missing something, as I can't find any docs or examples, or if this is an actual bug with variables.

Thanks!!

barrysteyn commented 5 years ago

Using serverless components is very different to using the old serverless plugins. For one thing, you cannot mix the "old" style with the "new" style. So instance, you cannot use a provider.

jepperip commented 4 years ago

I am having a similar problem. I want to create custom domains for different stages with the help of variables, like this:

nextApp:
  component: "serverless-next.js"
  inputs:
    domain:
      - ${opt:stage, 'dev'}
      - "mydomain.com"

This creates template-files where the domain is resolved to "domain": "${opt:stage, 'dev'}.mydomain.com, which is not want I want.

Like @mbenitezm I'm not sure if I am missing something or if this is a bug.

wzalazar commented 4 years ago

@jepperip do you find a solution for that?

hnprashanth commented 4 years ago

I am having a similar problem. I want to create custom domains for different stages with the help of variables, like this:

nextApp:
  component: "serverless-next.js"
  inputs:
    domain:
      - ${opt:stage, 'dev'}
      - "mydomain.com"

This creates template-files where the domain is resolved to "domain": "${opt:stage, 'dev'}.mydomain.com, which is not want I want.

Like @mbenitezm I'm not sure if I am missing something or if this is a bug.

Exactly in the same situation! Did you find any workaround?

SarKurd commented 4 years ago

You can only access environment variables in serverless.yml with severless components so you need to do something like this https://github.com/danielcondemarin/serverless-next.js/tree/master/packages/serverless-nextjs-component/examples/multiple-instance-environment

uclaeamsavino commented 4 years ago

UPDATE: ARGH - I was looking at the example on the serverless components page, which uses a colon. When I change it to a dot, it works. Leaving this up in case anyone else makes the same mistake.

@SarKurd - are you sure that even works? No matter what I try I get Error: invalid reference ${env:MYVAR} for any environment variable I try to use. Even though I know it's set on my computer.

Here's the stack trace:

node_modules/@serverless/template/utils.js:128:19)
node_modules/serverless/node_modules/traverse/index.js:190:22)
node_modules/serverless/node_modules/traverse/index.js:208:29
 at Array.forEach (<anonymous>)
SarKurd commented 4 years ago

that's V2 which was released a few days, severless-next.js only supports V1 atm

That's the supported V1 that serverless-next.js uses https://github.com/serverless/components/tree/v1

You either wait until serverless-nextjs adds support for V2 or you need to follow this example for now https://github.com/danielcondemarin/serverless-next.js/tree/master/packages/serverless-nextjs-component/examples/multiple-instance-environment

uclaeamsavino commented 4 years ago

Thanks. I did a modified version of that example. I forget whether or not it was dotenv or something else that only allowed a pre-configured set of environments (development, staging, production). But that didn't work for us. We need 5 environments, and the ability to easily create another as need arises.

So a long time ago we ended up going with env-cmd instead, as it allowed any arbitrary environment you want. Since I know that works I went with it for serverless_next.

Also I didn't like the idea of installing a bunch of extra packages and using the serverless.js->load serverless.yml paradigm if I didn't have to.

So what I came up with for the moment looks like this:

buildspec.yml (invoked by AWS code pipeline):

version: 0.2

phases:
  install:
    commands:
      - echo CURRENT_ENVIRONMENT=${CURRENT_ENVIRONMENT}
      - npm install -g serverless
      - npm install

  pre_build:
    commands:
      - aws s3 sync s3://our-S3-bucket/our-repo/${CURRENT_ENVIRONMENT}/.serverless .serverless --delete
      # - npm run test-cicd

  build:
    commands:
      - npm run deploy-${CURRENT_ENVIRONMENT}
      - aws s3 sync .serverless s3://our-S3-bucket/our-repo/${CURRENT_ENVIRONMENT}/.serverless --delete

package.json:

  "scripts": {
    "deploy-local": "env-cmd .env.local serverless",
    "deploy-dev": "env-cmd .env.development serverless",
    "deploy-stage": "env-cmd .env.stage serverless"
    ...
  },
 "devDependencies": {
    "env-cmd": "^8.0.2",
    ...
},

.env.development:

REACT_APP_API_GATEWAY_HOST=https://ourapihost.com
REACT_APP_USER_POOL_ID=ouruserpoolid
...

next.config.js

module.exports = {
  env: {
    REACT_APP_API_GATEWAY_HOST: process.env.REACT_APP_API_GATEWAY_HOST || 'https://ourapihost.com,
    REACT_APP_USER_POOL_ID: process.env.REACT_APP_USER_POOL_ID || "ouruserpoolid",
    ...

I feel like I'll keep tweaking this to simplify it. But at least I know it works. The default (IE - || 'ouruserpolid') exists for the local dev environments, which never go through serverless.yml (I think I'l eventually land on a better solution for that like just loading .env.local or something).

We also don't commit the .serverless folder, as that really doesn't work for CICD. But we do cache the build state for each environment on S3 (as recommended by someone on here). It feels a little hacky to me. But as long as the build isn't generating something with persistent data like dynamo or cognito, I feel like it's ok risking losing or corrupting the build state somehow, as we can always recreate it if needed.

As an aside - the build/deploy job should always be idempotent - replicatable from basic properties checked into source control - and identical no matter where or how many times it's run. It should never involve a dev having to remember to run a build job before checking in their changes. If serverless components really doesn't support that, I can get an idea why they might have abandoned it.

Oh yeah the other non-standard thing we're doing is letting serverless_next build the initial cloudfront, but then adding a WAF and domain and some other settings after the fact. It seems to work but also feels weird.

Each dev also has their own personal instance on AWS which they can deploy and test any time.

Work in progress, but at least everything seems to work for us from a DevOps POV.

SarKurd commented 4 years ago

That's what we do, in our case the pipeline is much simpler since we have integrated the CI with our infra very well

But i'd advice you to not spend so much time on it as Serverless components V2 released, it's going to be much more easy to deploy after serverless-next.js supports V2

uclaeamsavino commented 4 years ago

Yeah that's what I'm hoping for. Caching the build state on S3 is not optimal.

dodiego commented 4 years ago

UPDATE: ARGH - I was looking at the example on the serverless components page, which uses a colon. When I change it to a dot, it works. Leaving this up in case anyone else makes the same mistake.

@SarKurd - are you sure that even works? No matter what I try I get Error: invalid reference ${env:MYVAR} for any environment variable I try to use. Even though I know it's set on my computer.

Here's the stack trace:

node_modules/@serverless/template/utils.js:128:19)
node_modules/serverless/node_modules/traverse/index.js:190:22)
node_modules/serverless/node_modules/traverse/index.js:208:29
 at Array.forEach (<anonymous>)

For anyone having this issue I was able to fix by replacing : with . as was said in this link: https://www.gitmemory.com/issue/danielcondemarin/serverless-next.js/278/571668779