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

dioxus-aws

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

15 releases

new 0.6.9 Dec 11, 2024
0.6.8 Dec 11, 2024
0.6.5 Nov 22, 2024
0.6.2 Oct 23, 2024
0.5.3 Sep 18, 2024

#1604 in Network programming

Download history 335/week @ 2024-09-16 73/week @ 2024-09-23 55/week @ 2024-09-30 19/week @ 2024-10-07 212/week @ 2024-10-14 229/week @ 2024-10-21 9/week @ 2024-10-28 279/week @ 2024-11-04 9/week @ 2024-11-11 175/week @ 2024-11-18 37/week @ 2024-11-25 187/week @ 2024-12-02

422 downloads per month
Used in by-axum

MIT license

20KB
228 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, , 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/public s3://$DOMAIN --delete --profile $AWS_PROFILE

Dependencies

~15–29MB
~447K SLoC