Skip to main content

Multiline strings in .env files

· One min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

I love using .env files to configure my applications. They're a great way to keep configuration in one place and to keep it out of the codebase. They're also a great way to keep secrets out of the codebase.

But what if you need to use a multiline string in a .env file? How do you do that? You just do it:

SINGLE_LINE="you know what..."
MULTI_LINE="you know what you did
LAST SUMMER"

That's right, you just use a newline character. It's that simple. Oddly, searching for that on the internet didn't yield the answer I was looking for. So I'm writing it down here for posterity.

With your .env file in place, you can then consume it in your application using a package like dotenv. Or if you'd like to use a bash script to consume the .env file, you can do it like this:

#!/usr/bin/env bash
set -a
source test.env
set +a

npm run start # or whatever you need to do

ESLint no-unused-vars: _ ignore prefix

· 6 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

I'm a longtime user of TypeScripts noUnusedLocals and noUnusedParameters settings. I like to avoid leaving unused variables in my code; these compiler options help me do that.

I use ESLint alongside TypeScript. The no-unused-vars rule provides similar functionality to TypeScripts noUnusedLocals and noUnusedParameters settings, but has more power and more flexibility. For instance, no-unused-vars can catch unused error variables; TypeScript's noUnusedLocals and noUnusedParameters cannot.

One thing that I missed when switching to the ESLint option is that, with noUnusedLocals and noUnusedParameters, you can simply ignore unused variables by prefixing a variable with the _ character. That's right, sometimes I want to declare a variable that I know I'm not going to use, and I want to do that without getting shouted at by the linter.

It turns out you can get ESLint to respect the TypeScript default of ignoring variables prefixed with _; it's just not the default configuration for no-unused-vars. But with a little configuration we can have it. This post is a quick guide to how to implement that configuration.

title image reading "From TypeScript noUnusedLocals and noUnusedParameters to ESLint no-unused-vars (with _ prefix)" with the ESLint and TypeScript logo

Using Bun in Azure Pipelines

· 2 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

I'm a keen user of Bun. Bun is a fast TypeScript / JavaScript runtime which can be used to speed up the TypeScript / JavaScript you have. It's a drop-in replacement for Node.js, and it's compatible with the vast majority of the Node.js ecosystem. (There are still rough edges that have issues.) In this post we'll look at how to use it in Azure Pipelines.

title image reading "Using Bun in Azure Pipelines" with the Bun and Azure Pipelines logos

Bicep lint with Azure Pipelines and GitHub Actions

· 10 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Bicep has had linting since version 0.4.1. It's a great way to ensure that your bicep files conform to best practices. Interestingly, when the linting feature first shipped, there wasn't an explicit lint command as part of the CLI. Instead, you had to run bicep build and it would run the linter as part of the build process. This was a little confusing as it was not obvious that the linter was running.

As of version 0.21.1 there is a dedicated bicep lint command. This is a nice step forwards; it allows you to explicitly lint your your code, rather than have it happen as a side effect of build. And it is useful if you want to run the linter as part of a CI/CD pipeline. What's more the bicep lint command is now available in the Azure CLI as well. You can run az bicep lint to lint your bicep files.

In this post we'll look at how to run lint Bicep in Azure Pipelines and GitHub Actions, and surface the output in the UI.

title image reading "Bicep lint with Azure Pipelines and GitHub Actions" with the Bicep logo

Schemar: a GitHub Action to validate structured data

· 7 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Of late, I've found myself getting more and more into structured data. Structured data is a way of adding machine-readable information to web pages. To entertain myself, I liken it to static typing for websites. I've written about structured data before, but in this post I want to focus on how to validate structured data.

Specifically, how can we validate structured data in the context of a GitHub workflow? I've created a GitHub Action called Schemar that facilitates just that. In this post we'll see how to use it.

title image reading "Schemar: a GitHub Action to validate structured data" with the GitHub Action logo

Snapshot log tests in .NET

· 8 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Writing tests is important. The easier it is to write tests, the more likely they'll be written. I've long loved snapshot testing for this reason. Snapshot testing takes away the need to manually write verification code in your tests. Instead, you write tests that compare the output of a call to your method with JSON serialised output you've generated on a previous occasion. This approach takes less time to write, less time to maintain, and the solid readability of JSON makes it more likely you'll pick up on bugs. It's so much easier to scan JSON than it is a list of assertions.

Loving snapshot testing as I do, I want to show you how to write high quality and low effort log assertions using snapshot testing. The behaviour of logging code is really important; it's this that we tend to rely upon when debugging production issues. But how do you test logging code? Well, you could write a bunch of assertions that check how your logger is used. But that's a lot of work, it's not super readable and it's not fun. (Always remember: if it's not fun, you're doing it wrong.)

Instead, we'll achieve this using snapshot testing.

title image reading "Snapshot log tests in .NET" with the .NET logo

Overview of Bun, a JavaScript runtime

· 14 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET
Megan Lee
Content Marketing Manager

Like Node.js and Deno, Bun is a JavaScript runtime that provides a faster development experience while you’re building frontend applications. It’s gaining ground as a competitor to these widely used runtime environments — and for good reason.

In this evaluation guide, we’ll explore the features that make Bun an excellent choice for developing fast, performant, error-free frontend apps. By the end of this article, you’ll have a clear understanding of when and why you should use Bun in your projects.

title image reading "Bun overview: whats cooking" with the Bun logo

How we fixed my SEO

· 33 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET
Growtika
A dedicated SEO and growth marketing firm for dev-focused, cybersecurity, fintech and deep tech startups

We might also call this:

I ruined my SEO and a stranger from Hacker News help me fix it

This is a follow up to my "How I ruined my SEO" post. That was about how my site stopped ranking in Google's search results around October 2022. This post is about how Growtika and I worked together to fix it.

As we'll see, the art of SEO (Search Engine Optimisation) is a mysterious one. We made a number of changes that we believe helped. All told, my site spent about a year out in the cold - barely surfacing in search results. But in October 2023 it started ranking again. And it's been ranking ever since.

I put that down to the assistance rendered by Growtika. What was the nature of that assistance? I'll tell you. This post is a biggie; so buckle up!

title image reading "How we fixed my SEO" with images of graphs trending upwards in the background

Graph API: getting users Active Directory group names and ids with the C# SDK

· 8 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

The Graph API is a great way to get information about users in Azure Active Directory. I recently needed to get the names and ids of the Active Directory groups that a user was a member of. Here's how to do it with the C# SDK.

I'm writing this post as, whilst it ends up being a relatively small amount of code and configuration required, if you don't know what that is, you can end up somewhat stuck. This should hopefully unstick you.

title image reading "Graph API: getting users AD group names and ids with the C# SDK" with the Azure Graph and C# logos

Migrating to v4 Azure Functions Node.js with TypeScript

· 9 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

There's a new programming model available for Node.js Azure Functions known as v4. There's documentation out there for how to migrate JavaScript Azure Functions from v3 to v4, but at the time of writing, TypeScript wasn't covered.

This post fills in the gaps for a TypeScript Azure Function. It's probably worth mentioning that my blog is an Azure Static Web App with a TypeScript Node.js Azure Functions back end. So, this post is based on my experience migrating my blog to v4.

title image reading "Link Azure Application Insights to Static Web Apps with Bicep" with the Bicep and Azure Static Web App logos

Bicep: Link Azure Application Insights to Static Web Apps

· 3 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

If you're looking into a Production issue with your Azure Static Web App, you'll want to be able to get to your logs as fast as possible. You can do this by linking your Static Web App to an Azure Application Insights instance. If you've used the Azure Portal to create your Static Web App, the setup phase will likely have done this for you already. But if you're using Bicep to create your Static Web App, you'll need to do this yourself.

This post will show you how to do that using Bicep.

title image reading "Link Azure Application Insights to Static Web Apps with Bicep" with the Bicep and Azure Static Web App logos

Docusaurus 3: how to migrate rehype plugins

· 13 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Docusaurus v3 is on the way. One of the big changes that is coming with Docusaurus 3 is MDX 3. My blog has been built with Docusaurus 2 and I have a number of rehype plugins that I use to improve the experience of the blog. These include:

I wanted to migrate these plugins to Docusaurus 3. This post is about how I did that - and if you've got a rehype plugin it could probably provide some guidance on the changes you'd need to make.

title image reading "Migrating rehype plugins to Docusaurus 3" with the Docusaurus logos

Azure Open AI: generate article metadata with TypeScript

· 10 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

This post grew out of my desire to improve the metadata for my blog posts. I have been blogging for more than ten years, and the majority of my posts lack descriptions. A description is meta tag that sits in a page and describes the contents of the page. This is what this posts description meta tag looks like in HTML:

<meta
name="description"
content="Use the TypeScript Azure Open AI SDK to generate article metadata."
/>

Descriptions are important for search engine optimisation (SEO) and for accessibility. You can read up more on the topic here. I wanted to have descriptions for all my blog posts. But writing around 230 descriptions for my existing posts was not something I wanted to do manually. I wanted to automate it.

title image reading &quot;Azure Open AI: generate article metadata with TypeScript&quot; with the Azure Open AI / TypeScript logos

TypeScript: The Movie

· One min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

I am excited to announce that a documentary has been made about TypeScript! It premiered on YouTube at 5pm British Summertime September 21st 2023.

I had the good fortune to be involved in the making of the documentary. In part this was thanks to my work on Definitely Typed. Another reason was my work on recording the history of DefinitelyTyped.

You can see it on YouTube here or hit play on the embedded video above. Thanks to the Keyboard Stories team for making this happen!

Azure Open AI: handling capacity and quota limits with Bicep

· 4 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

We're currently in the gold rush period of AI. The world cannot get enough. A consequence of this, is that rationing is in force. It's like the end of the second world war, but with GPUs. This is a good thing, because it means that we can't just spin up as many resources as we like. It's a bad thing, for the exact same reason.

If you're making use of Azure's Open AI resources for your AI needs, you'll be aware that there are limits known as "quotas" in place. If you're looking to control how many resources you're using, you'll want to be able to control the capacity of your deployments. This is possible with Bicep.

This post grew out of a GitHub issue around the topic where people were bumping on the message the capacity should be null for standard deployment as they attempted to deploy. At the time that issue was raised, there was very little documentation on how to handle this. Since then, things have improved, but I thought it would be useful to have a post on the topic.

title image reading &quot;Azure Open AI: handling capacity and quota limits with Bicep&quot; with the Azure Open AI / Bicep logos

Azure Pipelines meet Vitest

· 3 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

This post explains how to integrate the tremendous test runner Vitest with the continuous integration platform Azure Pipelines. If you read the post on integrating with Jest, you'll recognise a lot of common ground with this. Once again we want:

  1. Tests run as part of our pipeline
  2. A failing test fails the build
  3. Test results reported in Azure Pipelines UI

title image reading &quot;Azure Pipelines meet Vitest&quot; with the Pipelines and Vitest logos

Azure Container Apps, Bicep, bring your own certificates and custom domains

· 4 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Azure Container Apps supports custom domains via certificates. If you're looking to make use of the managed certificates in Azure Container Apps using Bicep, then you might want to take a look at this post on the topic.

This post will instead look at how we can use the "bring your own certificates" approach in Azure Container Apps using Bicep. Well, as much as that is possible; there appear to be limitations in what can be achieved with Bicep at the time of writing.

title image reading &quot;Azure Container Apps, Bicep, bring your own certificates and custom domains&quot; with the Azure Container App logos

TypeScript 5.1: declaring JSX element types

· 6 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

A new feature arrives with TypeScript 5.1, it is described as "Decoupled Type-Checking Between JSX Elements and JSX Tag Types".

It's all about handing control of JSX type definitions to libraries. With this feature, libraries can control what types are used for JSX elements. Why does this matter? Great question! Until version 5.1, TypeScript did an imperfect job of representing what is possible with JSX. This feature allows libraries to do a better job of that, and we'll look into it in this post.

It's probably worth saying, that this is a complicated feature. If you don't understand it (and as the author of this post I'll confess that I had to work quite hard to understand it), that is okay. This is a low level feature that is only likely to be used by library / type definition authors. It's a primitive that will unlock possibilites for people writing JSX - but it's something that people will mainly feel the benefit of, without directly doing anything themselves, or necessarily noticing that things have changed for the better.

title image reading &quot;TypeScript 5.1: declaring JSX element types&quot; with the TypeScript logo

Azure Container Apps, Bicep, managed certificates and custom domains

· 6 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Azure Container Apps support managed certificates and custom domains. However, deploying them with Bicep is not straightforward - although it is possible. It seems likely there's a bug in the implementation in Azure, but I'm not sure. Either way, it's possible to deploy managed certificates and custom domains using Bicep. You just need to know how.

If, instead, you're looking to make use of the "bring your own certificates" approach in Azure Container Apps using Bicep, then you might want to take a look at this post on the topic.

I've facetiously subtitled this post "a three pipe(line) problem" because it took three Azure Pipelines to get it working. This is not Azure Pipelines specific though, it's just that I was using Azure Pipelines to deploy the Bicep. Really, this applies to any way of deploying Bicep. GitHub Actions, Azure CLI or whatever.

If you're here because you've encountered the dread message:

Creating managed certificate requires hostname '....' added as a custom hostname to a container app in environment 'caenv-appname-dev'

Then you're in the right place. I'm going to explain how to get past that error message and get your custom domain working with your Azure Container App whilst still using Bicep. It's going to get ugly. But it will work.

title image reading &quot;Azure Container Apps, Bicep, managed certificates and custom domains&quot; with the Azure Container App logos

Azure Container Apps, Easy Auth and .NET authentication

· 8 min read
John Reilly
OSS Engineer - TypeScript, Azure, React, Node.js, .NET

Easy Auth is a great way to authenticate your users. However, when used in the context of Azure Container Apps, .NET applications do not, by default, recognise that Easy Auth is in place. You might be authenticated but .NET will still act as if you aren't. builder.Services.AddAuthentication() and app.UseAuthentication() doesn't change that. This post explains the issue and solves it through the implementation of an AuthenticationHandler.

title image reading &quot;Azure Container Apps, Easy Auth and .NET authentication&quot; with the Azure Container App logos