Develop with Dev Containers in Windows

I wanted to fix a bug in Tabliss that had been bothering me for some time, but I could not build the project on Windows without changing the NPM scripts. So I decided to try Visual Studio Code Dev Containers.

The project would not build with the following error message:

BUILD_TARGET is not recognized as an internal or external

I quickly traced the problem to the NPM script setting an environment variable with a syntax that does not work on Windows:

{
  "scripts": {
    "dev:web": "BUILD_TARGET=web webpack serve"
  }
}

I could fix the problem with cross-env, but it did not seem reasonable to change the build script since the project was not mine and I was just trying to fix a bug. I could build the project in WSL, but I wanted to avoid installing the right version of Node.js and possible other tools in my WSL instance just to do that. So I decided to try Visual Studio Code Dev Containers.

Since I already had Docker Desktop installed, all I had to do was install the Visual Studio Code Dev Containers extension in Visual Studio Code. The next step was to run the Open Folder in Container command from the command palette:

Open Folder in Container

After selecting the project folder, I could choose from a large list of pre-configured images. Node.js & TypeScript seemed to be the right choice for my needs:

List of pre-configured images

I could then choose from several versions of Node.js:

List of available Node versions

And install additional features if I wanted to:

List of Dev Container features

Based on my selection, a new .devcontainer/devcontainer.json file was created:

{
  "name": "Node.js & TypeScript",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:0-18"
}

Visual Studio Code status bar indicated that it was connected to my container. And when I opened a terminal, it ran a bash shell inside the container:

Visual Studio Code status bar and terminal

Visual Studio Code also warned me that it was treating the repository folder as unsafe because it was mounted from the host and was not in my home directory:

Unsafe repository warning notification

By clicking the Manage Unsafe Repositories button, I was able to mark the folder as safe and get rid of the warning:

Mark repository as safe

As soon as Git was initialized in Visual Studio Code, it recognized all files as modified:

Modified files in Visual Studio Code

This was because Git uses different line endings by default in different operating systems. Since I cloned the repository on Windows, all line endings were considered changed on Linux. The best way to fix this problem is to use the same line endings in both operating systems. You can do this by adding the following .gitattributes file to the repository:

* text=auto eol=lf

To my surprise, the build also failed in my dev container, with a rather useless error message:

Error: PostCSS received undefined instead of CSS string

Fortunately, my instincts were right: something was wrong with my node_modules folder, because I had installed the packages on Windows but wanted to use them on Linux. This can cause problems when using native modules. So I deleted the node_modules folder and reinstalled the packages:

rm -rf node_modules
npm i

This finally made the build successful and Visual Studio told me that it had automatically forwarded the port of the application running in the container:

Port forwarding notification

As I began navigating and modifying the code, I quickly discovered that some of my Visual Studio code extensions needed to be installed inside the container, which was clearly indicated by the following error message:

This extension is disabled in this workspace because it is defined to run in the Remote Extension Host. Please install the extension in 'Dev Container: Node.js & TypeScript' to enable. Learn More

The issue was fixed immediately by clicking the Install in Dev Container button:

Install extension in Dev Container

If you do this, it's usually a good idea to add the extension to .devcontainer/devcontainer.json as well, so that it will be installed automatically if the container ever needs to be rebuilt. There is a handy Add to devcontainer.json command in the context menu when you right-click the extension in the Extensions side panel.

This is what my .devcontainer/devcontainer.json file looked like after I added two extensions to it:

{
  "name": "Node.js & TypeScript",
  "image": "mcr.microsoft.com/devcontainers/typescript-node:0-18",
  "customizations": {
    "vscode": {
      "extensions": ["esbenp.prettier-vscode", "syler.sass-indented"]
    }
  }
}

It's a good idea to commit the two modified files (.devcontainer/devcontainer.json and .gitattributes) to the repository so that other developers can get a working dev container environment without having to configure it. If you want to test the configuration beforehand, open the Remote Explorer side panel, right-click your container, and run the Rebuild Container command:

Rebuild container

This will create a new container with all the Visual Studio Code extensions listed automatically installed. The same should happen for any others that clone the repository and open it in a development container.

Dev containers can be a useful tool to quickly set up a working development environment for a project, especially if there is already a configuration in the repository. In this blog post, I described how I created my first Dev Container configuration for a project that could not be built in Windows. This was a great, non-invasive way to get it running without changing the code.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License