Angular 6 application hosted on Azure Storage Static website

A few days ago Microsoft announced a new public preview feature for Azure Storage called Static website. It enables you to host a static web app using Azure Storage which is multiple times cheaper then a traditional required Web App. Reason enough to give it a try.

Create a Storage account

To use the Static website feature we need a general purpose V2 Storage Account. You can either manually create the resource within the Azure Portal or by using the following ARM Template:

Enable Static website feature

Unfortunately we can’t enable the Static website feature using an ARM Template (thanks to Gaurav Mantri) because it is not part of the Storage Resource Provider API. So we have to manually enable it after we’ve provisioned the Storage Account.

We can do that within our previous created Storage Account: Select Static website (preview) to configure a container for static website hosting:

enablestaticwebsite

Since our example applicaton will have an index.html,  we can leave the index document name field as it is.

Note: If you have to automate this process, it is still possible to enable this feature using the Azure Storage Services REST API.

After we save our changes we get the primary endpoint URL of our site:

spaurl.png

Create an Angular Single Page Application

We use the Angular CLI to scaffold an Angular sample applicaton that already has routing enabled. The name of our app will be spastore:

ng new spastore --routing

We also create a new component named subcomponent to demonstrate the routing capability:

ng g component subcomponent

And configure the routing module accordingly:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SubcomponentComponent } from './subcomponent/subcomponent.component';

const routes: Routes = [
  { path: 'subcomponent', component: SubcomponentComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { useHash: true })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Note that we use the HashLocationStrategy oppsed to the default PathLocationStrategy because the later will result in 404 errors. This is because we can’t define a rewrite URL for our static website and Azure will try to resolve the specified resource – e. g.:
https://spastore.z6.web.core.windows.net/subcomponent

The HashLocationStrategy represents its state in the hash fragment of the browser’s URL. So this will be the new route for our subcomponent:
https://spastore.z6.web.core.windows.net/#/subcomponent

Finally we add the router outlet to the app.component.html which displays our component and add a router link:


  <a>Subcomponent</a>

Now it’s time to compile the application and get a production build. Once again we use the Angular CLI:

ng build --prod

The build artefacts are stored within the dist folder and are ready to publish. We can do that by clicking on the $web link within the Static website (preview) blade. Then we have to click on the Upload button and select all files within the artefact (dist) folder:

angularupload

If we browse to the URL we can see our Angular App up and running and also the routing is working as expected:

angulardemo.png

You can test the site here: https://spastore.z6.web.core.windows.net

The source code including the ARM Template and the Angular sample application can be found in my GitHub repository.

Update:

You can actualy use the PathLocationStrategy by setting the error page to index.html (thanks to @nthonyChu). The first try to serve a URL like https://spastore.z6.web.core.windows.net/subcomponent will fail since it is not a valid resource. Then the path will get passed to the error page which is our index.html (page returns content with 404 status code). However, this is hack. I still recommend using the HashLocationStrategy until a rewrite mechanism is in place.

Serving a HTML Page from Azure PowerShell Function

The new PowerShell language (experimental) support in Azure Function is really handy. Especially if you want to use the Azure PowerShell cmdlets to retrieve any kind of Azure Resources and diplay them in a HTML page. Hosting the cmdlet in Azure Function eliminates the need of a local installed Azure PowerShell module.

Here is a simple PowerShell Function that returns a Hello world HTML page:

# POST method: $req
$requestBody = Get-Content $req -Raw | ConvertFrom-Json
$name = $requestBody.name

# GET method: each querystring parameter is its own variable
if ($req_query_name)
{
    $name = $req_query_name
}

$html = @'

<header>This is title</header>


Hello world


'@

Out-File -Encoding Ascii -FilePath $res -inputObject $html

Invoking the script in a browser doesn’t give us the desired result. The content gets interpreted as XML instead of HTML:

xmlresult

The reason for that is that the Content-Type is set to applicaton/xml:

xmlresponse

The output of an Azure PowerShell function is a file (called $res by default) – so how can we change the content type to text/html?

It turns out (thanks to Mikhail) that we can construct a Repsonse Object using a JSON string (here the node definition) where we can set the content and the content type:

$resp = [string]::Format('{{ "status": 200, "body": "{0}", "headers": {{
"content-type": "text/html" }} }}', $html)
Out-File -Encoding Ascii -FilePath $res -inputObject $resp

If we invoke the function in the browser again we get the desired result:
htmlresponse

And the content-type is set to text/html:
htmldebug

Note that if your HTML contains JSON characters like double quotes or backslashes you will have to escape them. Example:

$html -replace '"', '\"'