DEV Community

Cover image for Fast Static Website Deployment with Angular and Pulumi
Pranav jana
Pranav jana

Posted on

3 1

Fast Static Website Deployment with Angular and Pulumi

This is a submission for the Pulumi Deploy and Document Challenge: Fast Static Website Deployment

What I Built

I deployed an Angular application (SkillSwap) to AWS using infrastructure as code with Pulumi. The solution includes:

  • S3 bucket for static website hosting
  • CloudFront CDN for global content delivery with HTTPS
  • SPA routing support for Angular's client-side routing
  • Automated deployment process with a single command

SkillSwap is a skill-sharing platform where users can exchange services based on their skills. The Angular application features user profiles, messaging, skill search, and ratings.

Live Demo Link

SkillSwap Application (Example CloudFront URL - actual URL will be available after deployment)

Project Repo

The project repository contains both the Angular application and the infrastructure code:

skillswap/          # Angular application
skillswap-infra/    # Pulumi infrastructure code
Enter fullscreen mode Exit fullscreen mode

Repository Structure

The infrastructure portion includes:

  • index.ts - Main Pulumi infrastructure definition
  • deploy.js - Automated deployment script
  • README.md - Setup and usage instructions
  • architecture.puml - Architecture diagram source

My Journey

Choosing Technologies

For this challenge, I selected:

  • Angular as my static website framework for its robust TypeScript support and component architecture
  • AWS (S3 + CloudFront) as my cloud provider for its reliability and global presence
  • Pulumi as my IaC tool for its use of familiar programming languages (TypeScript)

Setup & Planning

I started by setting up a dedicated infrastructure directory separate from the Angular application code. This separation of concerns helps maintain clean architecture and allows the infrastructure to evolve independently.

mkdir skillswap-infra
cd skillswap-infra
npm init -y
npm install @pulumi/pulumi @pulumi/aws typescript @types/node mime @types/mime
npx tsc --init
Enter fullscreen mode Exit fullscreen mode

Infrastructure Definition

The core infrastructure is defined in index.ts, where I created:

  1. S3 Bucket configured for static website hosting:
const siteBucket = new aws.s3.Bucket("skillswap-website-bucket", {
    website: {
        indexDocument: "index.html",
        errorDocument: "index.html",
    },
});
Enter fullscreen mode Exit fullscreen mode
  1. Public access policy to allow website visitors to access content:
const bucketPolicy = new aws.s3.BucketPolicy("bucketPolicy", {
    bucket: siteBucket.id,
    policy: siteBucket.id.apply(bucketId => JSON.stringify({
        Version: "2012-10-17",
        Statement: [{
            Effect: "Allow",
            Principal: "*",
            Action: ["s3:GetObject"],
            Resource: [`arn:aws:s3:::${bucketId}/*`]
        }]
    }))
});
Enter fullscreen mode Exit fullscreen mode
  1. CloudFront distribution for global content delivery and HTTPS:
const cdn = new aws.cloudfront.Distribution("skillswap-cdn", {
    enabled: true,
    origins: [{
        originId: siteBucket.arn,
        domainName: siteBucket.websiteEndpoint,
        customOriginConfig: {
            originProtocolPolicy: "http-only",
            httpPort: 80,
            httpsPort: 443,
            originSslProtocols: ["TLSv1.2"],
        },
    }],
    // ... additional configuration ...
});
Enter fullscreen mode Exit fullscreen mode
  1. SPA routing support for Angular's client-side routing:
customErrorResponses: [
    {
        errorCode: 404,
        responseCode: 200,
        responsePagePath: "/index.html",
    },
],
Enter fullscreen mode Exit fullscreen mode

Challenges Faced

  1. SPA Routing Configuration

One of the main challenges was configuring CloudFront to properly handle Angular's client-side routing. When users navigate to a route directly (e.g., /profile/123), the server would typically return a 404 since there's no physical file at that path.

Solution: I configured CloudFront to redirect 404 errors to index.html, allowing Angular's router to handle the navigation:

   customErrorResponses: [
       {
           errorCode: 404,
           responseCode: 200,
           responsePagePath: "/index.html",
       },
   ],
Enter fullscreen mode Exit fullscreen mode
  1. File Upload Mechanism

Another challenge was efficiently syncing the Angular build files to S3 while preserving the correct content types.

Solution: I created a recursive directory walking function that:

  • Discovers all files in the build directory
  • Determines the correct MIME type for each file
  • Creates S3 bucket objects with appropriate metadata
  • Handles Windows path separators by converting to URL-compatible format
  1. Deployment Automation

To simplify the deployment process, I wanted a single command that would build the Angular app if needed and deploy the infrastructure.

Solution: I created a deploy.js script that:

  • Checks if the Angular app is already built
  • Builds the app if necessary
  • Dynamically updates the Pulumi code to enable file uploads
  • Runs the Pulumi deployment

Performance Optimizations

I implemented several performance optimizations:

  1. CloudFront Caching: Configured TTLs for different content types to optimize caching behavior
  2. Compression: Enabled gzip/Brotli compression for text-based assets
  3. Region Selection: CloudFront automatically uses edge locations closest to users

Using Pulumi

Pulumi provided several key advantages for this project:

  1. Familiar Language: Using TypeScript meant I could leverage the same language for both my application and infrastructure, reducing context switching.

  2. Programmatic Abstractions: I could create reusable functions for tasks like file uploading, making the code more maintainable.

  3. Resource Relationships: Pulumi's programming model made it easy to define relationships between resources (like the S3 bucket and CloudFront distribution).

  4. State Management: Pulumi handles the state management, tracking what resources are created and their properties, making updates safer.

  5. Preview Capabilities: The pulumi preview command let me see what changes would be made before applying them.

Key Benefits Over Traditional Methods

Compared to manual deployment or using CloudFormation/Terraform, Pulumi offered:

  • Easier Debugging: Using a full programming language made debugging more straightforward
  • Richer Abstractions: I could use loops, conditionals, and functions to generate resources
  • Better Developer Experience: IntelliSense and type checking helped prevent errors
  • Easier Integration: Working with the Angular build process was seamless

Architecture Diagram

The following diagram illustrates the architecture of the deployed solution:

[User] --> [CloudFront CDN] --> [S3 Bucket]
  ^                               ^
  |                               |
  +---------- [Pulumi] -----------+
Enter fullscreen mode Exit fullscreen mode

Next Steps

Future improvements could include:

  • Custom domain configuration with SSL certificates
  • CI/CD pipeline integration
  • Environment-specific configurations
  • Performance monitoring and analytics

Conclusion

This project demonstrates how Pulumi can be used to deploy a static website to AWS efficiently. The infrastructure-as-code approach provides repeatability, maintainability, and automation, while leveraging familiar programming languages and tools.

Top comments (0)