Code Monkey home page Code Monkey logo

aws-spa's Introduction

aws-spa

Deploy a single page app on AWS in one command.

CircleCI codecov

first deployment

Install & use

npm install --dev aws-spa

npx aws-spa deploy --help

Why?

Configuring the deployment of a single page app is harder than it should be. Most SPA configuration are very similar. aws-spa embodies this idea. It is meant to handle all the quirks associated with SPA configuration.

Features

  • Create AWS Bucket & CloudFront distribution & Route 53 record & ACM certificate and configure it
  • Serve gzipped file
  • Invalidate CloudFront after deployment
  • Basic Auth (recommended to avoid search engine indexation)
  • idempotent script

Get Started

With create-react-app

npx create-react-app hello-world && cd hello-world
yarn add aws-spa
yarn build

# read about [create-react-app static file caching](https://facebook.github.io/create-react-app/docs/production-build#static-file-cachin)
npx aws-spa deploy hello.example.com --cacheInvalidation "index.html" --cacheBustedPrefix "static/"

API

aws-spa deploy

Deploy a single page app on AWS

Positionals

  • domainName:

The domain name on which the SPA will be accessible. For example app.example.com.

You can also specify a path: app.example.com/something. This can be useful to deploy multiple versions of an app in the same s3 bucket. For example one could deploy a feature branch of the SPA like this:

aws-spa deploy app.example.com/$(git branch | grep * | cut -d ' ' -f2)

Options

  • --wait: Wait for CloudFront distribution to be deployed & cache invalidation to be completed. If you choose not to wait (default), you won't see site changes as soon as the command ends.
  • --directory: The directory where the static files have been generated. It must contain an index.html. Default is build.
  • --credentials: This option enables basic auth for the full s3 bucket (even if the domainName specifies a path). Credentials must be of the form "username:password". Basic auth is the recommended way to avoid search engine indexation of non-production apps (such as staging). You can also set credentials through the environment variable "AWS_SPA_CREDENTIALS" (the argument will override the environment variable if both are defined)
  • --cacheInvalidation: cache invalidation to be done in CloudFront. Default is *: all files are invalidated. For a create-react-app app you only need to invalidate /index.html
  • --cacheBustedPrefix: a folder where files are suffixed with a hash (cash busting). Their cache-control value is set to max-age=31536000. For a create-react-app app you can specify static/.
  • --noPrompt: Disable confirm message that prompts on non CI environments (env CI=true).

Migrate an existing SPA on aws-spa

aws-spa is aware of the resources it is managing thanks to tags.

If a S3 bucket named with the domain name already exists, a prompt will ask you if you want to deleguate the management of this bucket to aws-s3 (this will basically checks that s3 bucket is well configured to serve a static website).

If a CloudFront distribution with this S3 bucket already exists, the script will fail because CloudFront distribution update is quite complicated.

  • If you don't care about downtime, you can delete the CloudFront distribution first.
  • If you care about downtime, you can configure the CloudFront distribution by yourself (don't forget to gzip the files) and then add the tag key: managed-by-aws-spa, value: v1.

IAM

  • cloudfront:CreateDistribution
  • cloudfront:ListDistributions
  • cloudfront:ListTagsForResource
  • cloudfront:TagResource
  • cloudfront:GetDistributionConfig
  • cloudfront:CreateInvalidation

TODO: complete missing policies

If using simple auth

  • lambda:GetFunction
  • lambda:EnableReplication*
  • iam:CreateServiceLinkedRole
  • iam:CreateRole on resource: arn:aws:iam::<account_id>:role/aws-spa-basic-auth-*

FAQ

Why not using Ansible, Saltstack, Terraform, Cloudformation, Troposphere, etc?

If it better suits your use case, these tools are probably a very good choice because there are done for this. Meanwhile there are some reasons why it is written in javascript:

  • in my CI/CD installing Ansible, awscli or Terraform takes more than 1 minute. Since my SPA needs nodejs to be built, having a the same dependency to deploy is convenient & fast.
  • Developers would have to learn these tools while they have already tons of things to learn. Using a script in the same language that they develop is nice.
  • These tools are quite heavy while deploying a SPA requires only a couple of AWS API calls.

aws-spa's People

Contributors

ambreelmee avatar dependabot[bot] avatar edwandr avatar naitokenzo avatar nicgirault avatar octavelaventure avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

aws-spa's Issues

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can fix this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here are some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


No npm token specified.

An npm token must be created and set in the NPM_TOKEN environment variable on your CI environment.

Please make sure to create an npm token and to set it in the NPM_TOKEN environment variable on your CI environment. The token must allow to publish to the registry https://registry.npmjs.org/.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

[Bug] Access denied when allowing public reads on newly created bucket

Failure while deploying build using aws-spa

[S3] ✏️ Allow public read to "s3.bucket.domain"...
πŸ’₯ Access Denied

Reason due to initial bucket creation having the Block public access (bucket settings) - All setting enabled.

Can be fixed by adding a remove block public access step before the allow public read bucket policy update.

export const setBucketPolicy = async (bucketName: string) => {
  logger.info(`[S3] ✏️ Allow public read to "${bucketName}"...`);
  // remove public access block
  await s3
    .putPublicAccessBlock({
      Bucket: bucketName,
      PublicAccessBlockConfiguration: {
        BlockPublicAcls: false,
        IgnorePublicAcls: false,
        BlockPublicPolicy: false,
        RestrictPublicBuckets: false,
      },
    })
    .promise();
  // allow public reads
  return s3
    .putBucketPolicy({
      Bucket: bucketName,
      Policy: JSON.stringify({
        Statement: [
          {
            Sid: "AllowPublicRead",
            Effect: "Allow",
            Principal: {
              AWS: "*",
            },
            Action: "s3:GetObject",
            Resource: `arn:aws:s3:::${bucketName}/*`,
          },
        ],
      }),
    })
    .promise();
};

at

aws-spa/src/s3.ts

Lines 117 to 137 in 6031af3

export const setBucketPolicy = (bucketName: string) => {
logger.info(`[S3] ✏️ Allow public read to "${bucketName}"...`);
return s3
.putBucketPolicy({
Bucket: bucketName,
Policy: JSON.stringify({
Statement: [
{
Sid: "AllowPublicRead",
Effect: "Allow",
Principal: {
AWS: "*",
},
Action: "s3:GetObject",
Resource: `arn:aws:s3:::${bucketName}/*`,
},
],
}),
})
.promise();
};

[Feature request] Allow specification of `DefaultRootObject` when creating/updating cloudfront distribution

Specific use-case is deploying multiple versions of the app based on the the current git branch, as highlighted by the docs.

You can also specify a path: app.example.com/something. This can be useful to deploy multiple versions of an app in the same s3 bucket. For example one could deploy a feature branch of the SPA like this:

While it is possible to remove the branch name from app.example.com/<branch>, it would be helpful to allow configuring the default root object served when no branch path is given.

Example: Deploying and having the default release branch be main;

  • app.example.com -> main/index.html (default)
  • app.example.com/main -> main/index.html
  • app.example.com/next -> next/index.html
  • app.example.com/new-feature -> new-feature/index.html etc.

Open to putting up a PR for the changes needed

aws profiles

I can't find any way to specify which aws profile to use Named profiles. Since we work with multiple customers, each which their own aws account, it's a must have for us. Otherwise this looks like a really good package, have been looking for this!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.