#aws-lambda #dioxus #aws #serverless #full-stack

dioxus-aws

Library for deploying Dioxus apps to AWS Serverless (AWS Lambda, S3, CloudFront, Route53)

5 releases

0.6.0-alpha.2 Sep 29, 2024
0.5.3 Sep 18, 2024
0.5.2 Sep 18, 2024
0.5.1 Sep 18, 2024
0.5.0 Sep 18, 2024

#923 in Network programming

Download history 270/week @ 2024-09-13 80/week @ 2024-09-20 101/week @ 2024-09-27 23/week @ 2024-10-04 15/week @ 2024-10-11

272 downloads per month

MIT license

15KB
112 lines

Dioxus AWS

dioxus-aws crate provides a launch function to make dioxus run on AWS Serverless Stack (AWS Lambda, CloudFront and S3).

Development

Creating a project

  • Use dx command.
    • Currently, dioxus-cli v0.5, which is stable version of dioxus, is supported.
cargo install dioxus-cli --version ^0.5
dx new --subtemplate Fullstack project-name

Re-Writing main function

Installing dependancy

  • Add dioxus-aws.
cargo add dioxus-aws

main function

  • Change launch(App) to dioxus_aws::launch(App).
dioxus_aws::launch(App); // launch(App);

Running and testing the project

  • It is same with usage of dioxus-cli.
cargo add dioxus-aws
dx serve --platform fullstack

Deployment

It uses AWS Lambda, S3 and CloudFront to deploy dixous application.

Setup AWS CDK

  • Setup AWS CDK to deploy application.
npm install -g aws-cdk
mkdir -p fixtures/aws-cdk
cd fixtures/aws-cdk
cdk init app --language=typescript

Writing CDK Stack

  • Route53 sets up a domain to CloudFront.
  • CloudFront distributes requests to API Gateway or S3.
  • API Gateway is bound to AWS Lambda.
  • S3 stores assets like js, html, images and so on.
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";

import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as origins from "aws-cdk-lib/aws-cloudfront-origins";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as acm from "aws-cdk-lib/aws-certificatemanager";
import * as route53 from "aws-cdk-lib/aws-route53";
import * as targets from "aws-cdk-lib/aws-route53-targets";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as apigateway from "aws-cdk-lib/aws-apigateway";

export class AwsCdkStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const domain = process.env.DOMAIN || "";
    const acmId = process.env.ACM_ID || "";
    const hostedZoneId = process.env.HOSTED_ZONE_ID || "";
    const projectRoot = process.env.PROJECT_ROOT || "";

    const assetsBucket = new s3.Bucket(this, "Bucket", {
      bucketName: domain,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const certificate = acm.Certificate.fromCertificateArn(
      this,
      "Certificate",
      acmId,
    );

    const func = new lambda.Function(this, "Function", {
      runtime: lambda.Runtime.PROVIDED_AL2023,
      code: lambda.Code.fromAsset(projectRoot + "/dist"),
      handler: "bootstrap",
      environment: {
        NO_COLOR: "true",
        ASSETS_PATH: "./",
      },
      memorySize: 128,
    });

    const api = new apigateway.LambdaRestApi(this, "Api", {
      handler: func,
      proxy: true,
    });

    const s3Origin = new origins.S3Origin(assetsBucket);
    const apiOrigin = new origins.RestApiOrigin(api);

    const cf = new cloudfront.Distribution(this, "Distribution", {
      defaultBehavior: {
        origin: apiOrigin,
        cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED,
        allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL,
        cachedMethods: cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS,
        originRequestPolicy:
          cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
      },
      additionalBehaviors: {
        "/assets/*": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/*.js": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/*.css": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/*.html": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/*.ico": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/*.svg": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/icons/*": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
        "/images/*": {
          origin: s3Origin,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
        },
      },
      domainNames: [domain],
      certificate,
    });

    const zone = route53.HostedZone.fromHostedZoneAttributes(
      this,
      "zone-attribute",
      {
        zoneName: domain,
        hostedZoneId,
      },
    );

    new route53.ARecord(this, "IpV4Record", {
      zone,
      target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(cf)),
    });

    new route53.AaaaRecord(this, "IpV6Record", {
      zone,
      target: route53.RecordTarget.fromAlias(new targets.CloudFrontTarget(cf)),
    });
  }
}

Build and deploy application

Building a binary for AWS Lambda

  • Note that server-feature is set to lambda instead of server.
  • Then, rename binary to bootstrap.
    • Usually, SERVICE might be basename $(git rev-parse --show-toplevel).
export SERVICE=$(cargo tree | head -n 1 | awk '{print $1}')
dx build --release --platform fullstack --server-feature lambda
mv dist/$SERVICE dist/bootstrap

Deploy AWS CDK

  • Let you remember environments in CDK Stack.
    • DOMAIN is FQDN including subdomain.
    • ACM_ID must be placed in us-east-1 for CloudFront.
    • HOSTED_ZONE_ID is a zone ID of Route53.
    • PROJECT_ROOT is a path of project root.
export DOMAIN="dioxus.example.com"
export ACM_ID="arn:aws:acm:us-east-1:---"
export HOSTED_ZONE_ID="Z--"
export PROJECT_ROOT=$(pwd)
export AWS_PROFILE=default

cd fixtures/aws-cdk
npm run build
cdk synth
cdk bootstrap --profile $AWS_PROFILE

# AWS Stack deployment
cdk deploy --require-approval never --profile $AWS_PROFILE

# S3 Assets sync
aws s3 sync $PROJECT_ROOT/dist s3://$DOMAIN --delete --profile $AWS_PROFILE

Dependencies

~17–32MB
~500K SLoC