CI/CD with Angular, WebAssembly, Rust, GitHub, and Azure

Tomáš Horáček
8 min readSep 23, 2020

--

This article will show you how to create a web application with a framework around a WebAssembly component. I will use the Angular framework, but the steps will be similar for other frameworks, like React or Vue.js. You can create the UI in a mature framework, as you would in other modern websites, and do your heavy calculation in WASM.

I will use Rust because it is a modern low-level language with great support for WASM apps.

I will also automatically deploy the application from GitHub to Azure Storage Account via Azure DevOps. You can find the finished code in this repository.

I will assume that you know the basics of Angular, Rust, and Git in this guide.

Setting up the project

Start by creating an empty GitHub repository and clone it to your computer. I called mine rust-wasm-angular. If you haven’t already, install node.js, Angular CLI, and wasm-pack on your system.

Enter the repository folder and generate a new Angular project with ng init. This should be the result.

In the root of your project run command wasm-pack new wasm. This will create a new folder with a skeleton of your Rust application. It generates a new README and some YAML files. You can delete those since you will not need them. There is a single greet function in the src/lib.rs file that you will call from Angular. Your repository should contain these files.

Go to the AppComponent in /src/app/app.component.ts and add a ngOnInit function that will call the greet method from wasm:

ngOnInit(): void {
const rust = import(‘../../wasm/pkg’);

rust.then(m => m.greet()).catch(console.error);
}

You import the WASM files from wasm/pkg folder. But these do not exist yet. Go to the wasm folder and run command wasm-pack build to generate them. My IDE can now find those files and show me type hints thanks to Typescript. I also removed generated items from the component html template. All was done in this commit.

Let’s start the application. You already created WASM files with wasm-pack build. Run npm install and ng serve to start the app locally.

When you open the app in your browser, Angular will call a WASM function written in Rust, that will emit an alert.

These commands will generate new files for us in the wasm/pkg and dist folder. These auto-generated files should not be uploaded to git, just like files generated by your IDE.

This is a good starting point for your application. You have a scalable solution for writing the UI thanks to Angular, and you can do the heavy lifting in Rust.

Continuous integration and continuous delivery

Now let’s look into CI/CD. You will host our app publicly so to make it available to the world. You will set up the build process once, and then every time you commit to the master branch, the public version of the app will be updated.

There are many services available for this. This article will use Microsoft Azure for the integration. I will show you how use a Storage Account at https://portal.azure.com/ to store the dist files of our application. This service can host these files as a Static Website. For the build of the app, you will use Azure Pipelines at https://dev.azure.com/.

Preparing website hosting in Azure

Start by creating a free account on the Azure portal. When you create your account, you will also need a free Azure Subscription.

Create an Azure storage account

Before creating the Storage account itself, you need to create a Resource group for the Storage Account. The Resource group can also various resources related to the application, like an SQL database.

Create a new Resource group

Go to the https://portal.azure.com/ and click on Create a new Resource.

On the main page of Azure Portal, start by creating a new resource.
Search for Resource group and click Create
Now fill in your Azure Subscription and select a name for the Resource group. Then select a Region close to you and click Review + create. Finally, confirm by clicking the Create button.

Add Storage Account Resource

A toast message with a link to the resource group will pop up. Click on the link to see the Resource Group page. You can also search for the group by name in the search bar at the top.

Click on the Add button or Create a resources button. Search for Storage Account, select it, and click Create.
Select your subscription and the newly created Resource group. Then select the name of the Storage account and your location. Set Account kind to StorageV2. V1 will not work with our pipelines. LRS has the least replication but is also the cheapest. You can learn more about available replications in the documentation. Use any replication you want, but for a continuously integrated website, the LRS is enough. In the extremely improbable case that your data gets corrupted, you can just rebuild it.

Click on the Review + create button and then the Create button to deploy the Storage account. This will take a short time to create. When it is done, click on the Go to resource button.

Enable Static Website

Now you have a place where you can store our build files. Before doing that, you need to enable Static website service first.

Search for Static Website in the list on the left and click on the result.
In the Static Website setting for your Storage account click on the Disabled/Enabled switch. Fill index.html into the index document name field. Then click on Save. That will create a new container in your Storage Account called $web and give you a link to your website.

When you go to the URL, you will see a “The requested content does not exist.” error. That is because there are no files yet.

(Optional) Upload the website manually

You can upload the website files manually in Azure. In the left panel find the Storage Explorer, then open BLOB CONTAINERS, and select the newly created $web container. Then you can use the Upload button to upload a simple index.html file or the whole contents of your dist folder.

Building the website automatically

With the Storage Account prepared, you can use Azure pipelines to build the web app and upload it to the Storage every time someone commits to the master branch in the git repository. You can set up various checks, reviews, automated test etc., but that is out of scope of this article.

Adding Azure Pipelines to your GitHub account

Start by going to your GitHub and select Marketplace at the top menu. Then search for Azure Pipelines and select it.

Follow the forms to create a new Azure DevOps account and connect it with your GitHub repositories. Choose an organization name and project name. I set it the project name to rust-wasm-angular to match the repository and Storage Account name.

Create a pipeline

In the Azure DevOps, go to your project and select Pipelines. You should see this a page that looks like this:

Click on Create Pipeline, select GitHub, and authorize access for Azure Pipelines. You should now see a list of your repositories. Select the repository with your project. On the Configure your pipeline step, select the Starter Pipeline option.

This will generate a simple Hello World pipeline. Click on the Save and Run button. You can keep the default values and click Save and run again. This will add a new file azure-pipelines.yml to your repository. This YAML file specifies the steps that the Azure Pipeline should do. Since it is triggered by updating master, and you just pushed a new commit to master by creating this file, your fist pipeline Job just started!

You should see the Job on this Pipeline run summary page:

To get to this page, click on Pipelines, and select the only pipeline in the list. Then select the only item in the list of runs.

In the Pipeline run summary page, select your Job. You should see this page with all steps green:

Completing the pipeline

Lastly, set up the pipeline to build our project and send it to our Storage Account.

Click on Pipelines, select your new pipeline, and click the Edit button. You should see the YAML file again. If you do not know YAML, I recommend checking out Learn Yaml in Y minutes. Basically, you will just specify a list of steps that the pipeline should do.

Start by changing the vmImage to ‘windows-latest’. You need to use Windows because you will use the Azure File Copy tool that requires Powershell under the hood. Continue by deleting the two predefined script steps and finally Click on the Show assistant button to see available tasks.

Place your cursor on line 13 and search for theNode.js tool installer tool. Change the version to 10.x and click on the Add button. You can then manually add displayName: ‘Install Node.js’.

Then search for Command line task and use this script to install wasm-pack and build your Rust code with it:

curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
wasm-pack build

Under Advanced, set the Working directory to $(Build.SourcesDirectory)\wasm and click Add. $(Build.SourcesDirectory) is a variable for the location of your code that was pulled from GitHub.

Add two more Command line scripts, one for npm install and the other for npm run build. This will generate your dist folder.

The last task will be Azure file copy. Set the source to$(Build.SourcesDirectory)\dist\rust-wasm-angular\* The * means that the contents of the folder will be copied. Select your subscription and authorize it. Choose Destination Type Azure Blob, Storage account rustwasmangularaand Container name $web.

Your final YAML file should look like this

Click the Save button. The Pipeline job will start but will need permission to access GitHub. You can ignore that for now.

Enable Access Control

Before running the pipeline, you need to set Access Control to allow the uploading of files from azure pipelines to your Storage Account. If you don’t have this set up correctly, the Azure File Copy will fail on AuthorizationPermissionMismatch.

Go to your Storage Account in the Azure portal and in the left panel select Access Control.

Continue to Add role assignment.
In the Add role assignment panel, set the Role to Storage Blob Contributor. In the Select field search for your Organization name from DevOps (it will not find the project name). Finally, select the rust-wasm-angular project and click Save.

Start the Pipe

Go to Azure DevOps and click on Pipelines. Select your pipeline to see its runs. There should be 2 items on the list. One completed Hello World run and a second one that is waiting. Click on the waiting one. You should see message This pipeline needs permission to access a resource before this run can continue. Click on the View button and grand the permissions. When the job finishes, the site should be available online.

Next steps / Exercises

  • Run unit tests in your pipeline. When the tests fail, the pipeline will fail, so the broken build will not get to production.
  • Clean the $web container before the Azure File Copy action
  • Copy the .wasm files separately and set the MIME content type for them to application/wasm
  • Add more content to your application
  • Add the build Status badge to your README file

Summary

You have a basic, but scalable foundation for your project. You can use Angular to build the UI and Rust to write the parts of your application that benefit from the WASM speed. And your new features will be published automatically.

--

--