Setup Windows 10 Development Environment

hackwsl

After several weeks research, I pulled the trigger for a new Windows laptop, and started the journey to build the development environment in Windows. Arguably, the MacBook Pro is still a better choice thanks to the native Unix environment; but the Windows Subsystem for Linux, aka WSL and Docker Desktop for Windows helped to close the gap.

Hardware

The spec of the Windows laptop, HP Envy 13-aq0011ms is not top of the line, but strikes a good balance between the performance and portability:

  • Intel Core i5-8265U 1.60 GHz with Turbo Boost Technology up to 3.90 GHz
  • 8GB DDR4 2400 SDRAM1
  • 256GB PCIe NVMe M.2 SSD
  • 13.3-inch FHD(1920 x 1080) IPS touchscreen, 10-finger multi-touch support
  • 2.92 lbs (1.27 kg)

And the price too, $499; — it is quite rare to get all three out of three in this industry.

The build quality is impressive: the aluminum body is really a joy to work with; the privacy camera kill switch is a nice touch. The USB Type-C port with Power Delivery is a nice surprise, — I can charge the laptop with the MacBook Pro charger. Though the charge won’t go through the USB-C AV multiport adapter.

Envy13
Envy13

On the flip side, the touchpad is subpar: it’s too sensitive when typing, and too insensitive for drag-and-drop. The keyboard is as flaky as the notorious butterfly keyboard in MacBook Pro. The Ctrl, Fn, Win, Alt keys are really hard to work with: the Ctrl key is too far and too small for the pinkie to reach. We will fix it in the Keyboard shortcuts.

Prerequisites and Scopes

I learned my lessons when tweaking the linux desktops in my earlier days. The scopes of the initiative are limited as:

  • I will use vscode(with vim plugin) as the main editor.
  • I will use firefox as the main browser.
  • All interpreters, libraries, compilers, terminal applications will stay in WSL land, except git as the vscode source control depends on the native git executable.
  • I will use wsltty as the main terminal for WSL.
  • I will not attempt to automate the setup as I am still exploring.

In Windows, I use the Chocalatey package manager to manage softwares packages, such as:

choco install firefox vscode autohotkey microsoft-windows-terminal nodejs-lts docker-desktop wsltty git

Windows Subsystem for Linux

The Windows Subsystem for Linux, aka WSL, provides a good enough emulation of Linux runtime. It is not a full-fledged linux distro: the underlying file system is case-insensitive, the systemd init is partially supported, etc2; but good enough for dependency management.

I followed this guide to install the WSL2:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

With build 17093, we can configure wsl’s DrvFS to store metadata for Linux’s ACL. Add this to /etc/wsl.conf:

[automount]
enabled = true
root = /
options = "metadata,umask=22,fmask=11"
mountFsTab = false
  • the root configures ALL disks are mounted in /, instead of the default /mnt. This is required by the docker desktop, see WSL bug.
  • the options enable the metadata, and the umask improvement.

The update of /etc/wsl.conf requires a WSL restart, with build 17046 we can terminate WSL without reboot:

wsl -l
Windows Subsystem for Linux Distributions:
Ubuntu-18.04 (Default)

wsl -t Ubuntu-18.04

Customization

I have to keep reminding myself to timebox this process as it is a never-ending journey. The configuration, or dotfiles are grouped under the manydots umbrella, feel free to cherry pick for your convenience.

In WSL, I use vcsh to manage dotfiles, — it solves the problems that multiple repositories are mounted in the same directory, $HOME. See this post for more details.

Keyboard shortcuts

I have been using MacBook Pro at work for several years, the muscle memory does not serve me well in Windows shortcuts. I prefer to customize the keyboard shortcuts in Windows just similar to macOS shortcuts.

More concretely, we will map Alt in Windows to Command in macOS, — as they are roughly the same size and in the same spot. We will use the Alt+C to replicate the Command+C for copy to clipboard shortcut. Thus we need to map Alt+C to Ctrl+Insert in the terminal, and Ctrl+C in the remaining applications.

The awesome AutoHotKey, aka AHK, can customize the key mapping in Windows. I slowly built my AutoHotKey.ahk from this gist for my personal habit. You can follow this guide to auto load the script when Windows boots.

Touchpad Gestures

The HP Envy 13 laptop is equipped with Precision Touchpad, which means it supports multi-finger gesture. Unfortunately, two-finger gestures can only scroll vertically or horizontally, no swipe. The TouchpadSwipe addon tried to simulate the swipe gesture in the software side, but did not work reliably.

Terminal

I use wsltty as the default WSL terminal. It is built upon the mintty code base with wslbridge library, so we can reuse the mintty configuration, in %APPDATA%:

git clone git@gitlab.com:manydots/minttyrc.git mintty

You can install the powerline fonts for better look and feel for tmux and vim.

ZSH

I use zplug prezto to manage zsh plugins for better loading performance, see zplug bug.

git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"

This will install the prezto in $HOME/.zprezto. I then sync the my zsh configuration:

vcsh clone git@gitlab.com:manydots/zshrc.git 'zshrc'
chsh -s /usr/bin/zsh

Restart WSL.

TMUX

I use tpm to manage the tmux plugins:

mkdir -p ~/.tmux/plugins
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm

Checkout this repository for my .tmux.conf.

vcsh clone git@gitlab.com:manydots/tmuxrc.git 'tmuxrc'

It is worthy mentioning to setup the $TERM to leverage mintty’s 256-color support:

set -g default-terminal "screen-256color"

Remote Development

The vscode remote development makes this configuration possible and usable. Launch code in the WSL environment, vscode will install the Remote - WSL extension, and bridge the local UI and remote development. Therefore, we can benefit from the Windows’ graphic experience and Linux’s package management.

Nodejs in WSL

Install latest nodejs in the WSL.

curl -sL https://deb.nodesource.com/setup_13.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo npm install -g yarn

Launch the gatsby for this blog:

yarn develop

... ...
You can now view silversmith in the browser.
  http://localhost:8000/

You can navigate to http://localhost:8000/ to access the site, — not port remap needed.

Python in WSL

You might consider to install native Windows distribution to leverage CUDA acceleration since GPU is not accessible in the WSL environment. I would install the latest miniconda since the MKL optimization is included, and the HP Envy is not equipped with dedicated video adapter.

First install the pyenv to manage multiple python runtimes.

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

I don’t use virtualenvwrapper, and prefer dedicated virtual environment venv for each project. Add the two lines in the .zshrc to enable the virtualenv auto-switch:

zstyle ':prezto:module:python' skip-virtualenvwrapper-init 'on'
zstyle ':prezto:module:python:virtualenv' initialize 'yes'
zstyle ':prezto:module:python:virtualenv' auto-switch 'yes'

Install the following packages via pyenv and conda:

pyenv install miniconda3-latest
conda install numpy scipy panda matplotlib scikit-learn

You can also verify the mkl is supported as suggested here:

conda install pytest
python -c 'import scipy; scipy.test()'

Docker Desktop

Container has become the de-facto standard in the state-of-art deployment pipeline. It is quite common that the infrastructure component is packed in the docker container format. I take the middle ground:

  • the infrastructure, such as RDBMS, ElasticSearch will be managed by the docker stack.
  • the web application with business logic run in WSL for better introspect, debug support.

After the Docker Desktop for Windows3 installed, I enabled the Expose daemon on tcp://localhost:2375 without TLS option in settings, then restarted the docker engine. This allows the docker client in WSL to talk to the docker engine.

In WSL, install the docker, and run the docker command with DOCKER_HOST configured to the port we just exposed:

sudo apt-get install docker.io
DOCKER_HOST=tcp://127.0.0.1:2375 docker run hello-world

I hesitated to take the advantage of the WSL backend as I felt the software stacks kind of shaky with so many experimental features built upon each other. Also the VM-based container runtime is more close to the production environment, a good candidate for staging environment.

Close Thoughts

The remote programming seems odd in the first sight, but essentially quite common in the software industry. Simply because the application is too big, or too complicated to fit into the MacBook Pro, or DevOps has no appetite to maintain two runtimes. From this point of view, macOS has only marginal advantage than the Windows, the developers will use Linux anyway.


  1. Soldered in the motherboard unfortunately. It is a stretch to run docker, android emulator simultaneously in 8G memory just fyi.
  2. That is why I am hesitant to adopt the nix in WSL.
  3. Docker Desktop for Windows requires the Windows Professional or Windows Enterprise due to the Hyper-V feature, even though the WSL backend does not depend on Hyper-V.