diff --git a/typescript/static-site-basic/README.md b/typescript/static-site-basic/README.md new file mode 100644 index 0000000000..b6536409da --- /dev/null +++ b/typescript/static-site-basic/README.md @@ -0,0 +1,28 @@ +# Static site + +## + +![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) + +> **This is an experimental example. It may not build out of the box** +> +> This example is built on Construct Libraries marked "Experimental" and may not be updated for latest breaking changes. +> +> If build is unsuccessful, please create an [issue](https://github.com/aws-samples/aws-cdk-examples/issues/new) so that we may debug the problem + +--- + + + +This example creates the infrastructure for hosting a static site, which uses an S3 bucket for storing the content. The site contents (located in the 'site-contents' sub-directory) are deployed to the bucket. As this is a basic example, it is not intended for production workloads. It does not use a CloudFront distribution or SSL. + +## Prep + +## Deploy + +```shell +$ npm install -g aws-cdk +$ npm install +$ npm run build +$ cdk deploy -c static-content-prefix=web/static +``` diff --git a/typescript/static-site-basic/cdk.json b/typescript/static-site-basic/cdk.json new file mode 100644 index 0000000000..a46c823a5e --- /dev/null +++ b/typescript/static-site-basic/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "ts-node index.ts" +} diff --git a/typescript/static-site-basic/index.ts b/typescript/static-site-basic/index.ts new file mode 100644 index 0000000000..d93711c7f6 --- /dev/null +++ b/typescript/static-site-basic/index.ts @@ -0,0 +1,34 @@ +#!/usr/bin/env node +import * as cdk from "aws-cdk-lib"; +import { StaticSiteBasic } from "./static-site-basic"; + +/** + * This stack allows the user to specify a prefix path for static content in their + * website hosting bucket. + * Use 'cdk synth -c static-content-prefix=web/static ' + * Or add the following to cdk.json: + * { + * "context": { + * "static-content-prefix": "web/static", + * } + * } + **/ +class MyStaticSiteBasicStack extends cdk.Stack { + constructor(parent: cdk.App, name: string, props: cdk.StackProps) { + super(parent, name, props); + + new StaticSiteBasic(this, "StaticSiteBasic", { + staticContentPrefix: this.node.tryGetContext("static-content-prefix"), + }); + } +} + +const app = new cdk.App(); + +new MyStaticSiteBasicStack(app, "MyStaticSite", { + env: { + account: app.node.tryGetContext("accountId"), + }, +}); + +app.synth(); diff --git a/typescript/static-site-basic/package.json b/typescript/static-site-basic/package.json new file mode 100644 index 0000000000..6aef547485 --- /dev/null +++ b/typescript/static-site-basic/package.json @@ -0,0 +1,26 @@ +{ + "name": "static-site-basic", + "version": "1.0.0", + "description": "Infrastructure for hosting an HTTP website in S3", + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "cdk": "cdk" + }, + "author": { + "name": "Amazon Web Services", + "url": "https://aws.amazon.com", + "organization": true + }, + "license": "Apache-2.0", + "devDependencies": { + "@types/node": "^10.17.0", + "aws-cdk": "*", + "typescript": "~5.1.6" + }, + "dependencies": { + "aws-cdk-lib": "^2.0.0", + "constructs": "^10.0.0", + "ts-node": "^10.9.2" + } +} diff --git a/typescript/static-site-basic/site-contents/error.html b/typescript/static-site-basic/site-contents/error.html new file mode 100644 index 0000000000..0240c8288b --- /dev/null +++ b/typescript/static-site-basic/site-contents/error.html @@ -0,0 +1,6 @@ + +
Hello world: Error
+ +Uh oh, you reached the error page! + + diff --git a/typescript/static-site-basic/site-contents/index.html b/typescript/static-site-basic/site-contents/index.html new file mode 100644 index 0000000000..139707c92c --- /dev/null +++ b/typescript/static-site-basic/site-contents/index.html @@ -0,0 +1,6 @@ + +
Hello world
+ +Hello, world! + + diff --git a/typescript/static-site-basic/static-site-basic.ts b/typescript/static-site-basic/static-site-basic.ts new file mode 100644 index 0000000000..553e27ce06 --- /dev/null +++ b/typescript/static-site-basic/static-site-basic.ts @@ -0,0 +1,61 @@ +#!/usr/bin/env node +import * as s3 from "aws-cdk-lib/aws-s3"; +import * as s3deploy from "aws-cdk-lib/aws-s3-deployment"; +import { CfnOutput, RemovalPolicy, Stack } from "aws-cdk-lib"; +import { Construct } from "constructs"; +import path = require("path"); + +export interface StaticSiteBasicProps { + staticContentPrefix: string; +} + +/** + * Static site infrastructure, which deploys site content to an S3 bucket. + */ +export class StaticSiteBasic extends Construct { + constructor(parent: Stack, name: string, props: StaticSiteBasicProps) { + super(parent, name); + + // Content bucket + const indexDocument = "index.html"; + + const websiteBucket = new s3.Bucket(this, "WebsiteBucket", { + websiteIndexDocument: indexDocument, + publicReadAccess: true, + blockPublicAccess: new s3.BlockPublicAccess({ + blockPublicAcls: false, + blockPublicPolicy: false, + ignorePublicAcls: false, + restrictPublicBuckets: false, + }), + /** + * The default removal policy is RETAIN, which means that cdk destroy will not attempt to delete + * the new bucket, and it will remain in your account until manually deleted. By setting the policy to + * DESTROY, cdk destroy will attempt to delete the bucket, but will error if the bucket is not empty. + */ + removalPolicy: RemovalPolicy.DESTROY, // NOT recommended for production code + + /** + * For sample purposes only, if you create an S3 bucket then populate it, stack destruction fails. This + * setting will enable full cleanup of the demo. + */ + autoDeleteObjects: true, // NOT recommended for production code + }); + + new CfnOutput(this, "Bucket", { value: websiteBucket.bucketName }); + new CfnOutput(this, "StaticSiteUrl", { + value: [ + websiteBucket.bucketWebsiteUrl, + props.staticContentPrefix, + indexDocument, + ].join("/"), + }); + + // Deploy site contents to S3 bucket + new s3deploy.BucketDeployment(this, "DeployWebsite", { + sources: [s3deploy.Source.asset(path.join(__dirname, "./site-contents"))], + destinationBucket: websiteBucket, + destinationKeyPrefix: props.staticContentPrefix, // optional prefix in destination bucket + }); + } +} diff --git a/typescript/static-site-basic/tsconfig.json b/typescript/static-site-basic/tsconfig.json new file mode 100644 index 0000000000..c0e3a1b91f --- /dev/null +++ b/typescript/static-site-basic/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "lib": [ + "es2016", + "es2017.object", + "es2017.string" + ], + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false + }, + "include": [ + "./*.ts" + ] +}