Set the owner of directories and files recursively

If your user account cannot access certain folders or files, you can recursively set the owner.

  • Open a PowerShell terminal with admin rights
  • To set the owner to a specific user account
icacls "C:\THE_TOP_DIRECTORY" /inheritance:e /grant "MY_USER_NAME:(OI)(CI)F" /T
  • To use the owner of the parent directory
icacls "C:\THE_TOP_DIRECTORY" /reset /T

Creating a mono repo for multiple applications

If you are planning to develop multiple applications working together, using the same technology, it is advantageous to place all of them in the same Git repository. This way you can use relative paths to refer to shared functions to access the same database, React components, and images to make the pages look consistent. As all are in the same repository, the CI/CD pipeline will also find those during application building and testing.

If you use Node.js packages, use PNPM for package management to rationalize the node modules and store them in the top level node_modules directory and use symbolic links to point to those from other locations. See Install pnpm.

To set up the mono repo for multiple Node.js applications

Create the directory structure

Create the root directory of the repository and the apps and packages subdirectories.

mkdir -p MY_APP_SUITE
cd MY_APP_SUITE
mkdir -p apps
mkdir -p packages

Add configuration files to the root directory

.gitignore

This is the minimum you should have for any Node.js project to exclude secrets and libraries

.DS_Store
.env
/node_modules/

# React Router
/.react-router/
/build/

package.json

Set the versions of node and pnpm in the file below and save it in the root of the repository

{
  "name": "MY_APP_SUITE_NAME",
  "version": "1.0.0",
  "private": true,
  "description": "MY DESCRIPTION",
  "main": "index.js",
  "scripts": {
  },
  "keywords": [],
  "author": "MY NAME",
  "dependencies": {
  },
  "devDependencies": {
  },
  "config": {
  },
  "engines": {
    "node": ">=24.11.0",
    "pnpm": ">=10.15.1"
  },
  "packageManager": "pnpm@10.15.1"
}

pnpm-workspace.yaml

This file tells PNPM where the applications and shared packages will be to be able to reuse node-packages.
** tells PNPM to search for package.json files recursively.

packages:
  - "apps/**"
  - "packages/**"

Add the applications

If you already have existing applications, copy their directory structures into the apps directory and delete the node_modules directories. PNPM will recreate those and create symbolic links to point to the top level node_modules directory.

To create a new React Router web application, open a terminal in the apps directory and follow the instructions at Creating a new React Router application.

As we use PNPM to rationalize the node modules for all applications, do not install the node modules in the individual application directories. Once the application structure been created open a terminal in the root of the mono repo and execute

pnpm install

Based on the packages list in the pnpm-workspace.yaml file, PNPM will install all necessary node modules for all applications and packages in the entire workspace, which is the current mono repo.

Download a Figma Make to your local computer and run it locally as an application

Figma make can generate web applications with AI assistance. To download and run the generated web application on your local computer

  • Open Figma Make
  • On the top of the page select the Code tab
  • In the upper right corner click the Download code button
  • Extract the downloaded Zip file into a directory
  • Install pnpm on your computer. See Install pnpm
  • Open a terminal in the root of the application directory structure, where the package.json file is located
  • Execute the command in the terminal
    pnpm run dev

Finding unidentified processes in WSL

If an unidentified process is generating a web site

Try to load it in an incognito / Private window
Open http://localhost:PORT/... in a brand new private window.

  • Works there too → real server is running.
  • Fails there → old tab is just showing cached content.

curl test

In a Windows or in WSL:

curl -v http://localhost:8081/
  • Connection refused / timeout → backend is dead.
  • HTTP 200 with HTML → something is definitely serving.

Who owns the port

In a Windows PowerShell window with Admin rights:

netstat -abno | findstr :8081

In a Windows PowerShell window with Admin rights:

tasklist /FI "PID eq <PID from above>"

In WSL (if wslrelay.exe is involved):

sudo ss -lntp | grep 8081
sudo lsof -i :8081

To kill the processes in WSL, use the PIDs returned by the command above

sudo kill PID1 PID2

WARNING: To permanently disable the docker and docker.socket in WSL you may execute the following commands, but maybe those processes are necessary for the normal operation of the WSL system.

# 1. Disable Docker and its socket so they don't start automatically
sudo systemctl disable docker.service docker.socket

# 2. Stop the socket right now so nothing can auto-start dockerd in this session
sudo systemctl stop docker.socket

# 3. Sanity check
systemctl status docker
systemctl status docker.socket

Install pnpm

pnpm is a Node Package Manager and Node Version Manager to install and manage multiple Node.js version and a central repository of node modules

First uninstall

nvm

Node.js

On Windows

Uninstall Node.js in Settings/ Apps / Installed Apps

Install pnpm

Open a PowerShell terminal and execute

Invoke-WebRequest https://get.pnpm.io/install.ps1 -UseBasicParsing | Invoke-Expression

IMPORTANT: Close and re-open all terminals and Visual Studio Code for the Path changes to take effect

Create an alias for PNPM in PowerShell. In an Administrator PowerShell window execute

 notepad $profile.AllUsersAllHosts

Save the following in the file

set-alias -name pn -value pnpm

Create an alias for the Bash terminal. In a terminal execute

code C:\Users\MY_USER_NAME\.bashrc

Save the following in the file

alias pn=pnpm

Install Node.js

Install the latest LTS (Long Term Support) version of the Node.js framework

pnpm env use --global lts

Install tsup

tsup is a fast TypeScript bundler that gains popularity. To install it as a dev dependency in the current project, in the root of the repo execute:

pnpm add tsup -D

Creating a new React Router application

Prerequisites

Install the development tools

Visual Studio Code

pnpm

See Install pnpm

Create the new application

To create a new React Router web application create a directory for the project and open a terminal and execute

npx create-react-router@latest MY_APPLICATION_NAME

If you want to create the Git repository on a higher level, answer NO to the Initialize a new git repository? question.

If you want to use PNPM as node package manager, answer NO to the Install dependencies with npm? question and issue the
pnpm install -r
command in the root folder of the repository to only have one real copy of the node modules. PNPM creates symbolic links from subdirectories to refer to the one file instance to save space on the hard drive.

Run the application

To run the web application, in the application root directory execute

cd MY_APPLICATION_NAME
pnpm i
pnpm run dev

Managing passwords in Windows Susbsystem for Linux (WSL)

To change the Linux password

To change your Linux password, in the Linux terminal execute

passwd

You will be asked for the current password and the new password.

If you forgot the Linux password

If you forgot your Linux password, you can reset it from Windows.

  • In Windows PowerShell enter the Linux distribution root account with the command
 wsl -u root
  • If you have multiple Linux distributions in your WSL, specify the distribution name too
wsl -d <DistroName> -u root
  • Once the Linux root level access opened, change the password of the user with
passwd <username>

Installing the Windows Subsystem for Linux (WSL)

WSL enables Windows computers to concurrently run Windows and Linux at the same time. Modern software development and deployment usually depends on Linux tools and commands. To be able to run a Linux container on a Windows workstation, we need the availability of the Linux Kernel.

To install Windows Subsystem for Linux (WSL)

To use the default Ubuntu distribution

  • Open a PowerShell terminal as Administrator and execute the command
    wsl --install

To install another distribution

  • Open a PowerShell terminal as Administrator and execute the command to get the list of available distributions
    wsl.exe --list --online
  • Install the desired distribution
    wsl --install -d MY_DISTRIBUTION_NAME

Create the Linux user

The installer will create a Linux user. By default it will use your Windows user name. Enter a password and retype it.

Create a default Unix user account: MY_USER_NAME
New password:
Retype new password:

Reboot the computer for the changes to take effect.

Configuration

Terminal

Install the Windows Terminal from the Microsoft App Store

Code editor

Configure Visual Studio Code to be able to access and debug in the Linux file system.

For more on this see Get started using Visual Studio Code with Windows Subsystem for Linux

Installation
  • Install Visual Studio Code on Windows, not in the WSL file system
Extensions

Remote Development extension pack

The installation will also install the following extensions

  • WSL
  • Dev Containers

Update the Linux distribution

In the Linux terminal execute

for OS update

sudo apt-get update

install wget and ca-certificates to be able to retrieve content from web servers

sudo apt-get install wget ca-certificates

Git

Install Git in WSL

Git is usually installed in the Linux distribution, update it to the latest version with

sudo apt-get install git
Configure Git in WSL
git config --global user.name "Your Name"
git config --global user.email "youremail@domain.com"
Install GitHub CLI in WSL
sudo apt install gh
Install the Git Credential Manager in WSL

Install the native Git credential manager in WSL

curl -sSL https://aka.ms/gcm/linux-install-source.sh | sudo bash
Install the Git Credential Manager in WSL
dotnet tool install -g git-credential-manager

IMPORTANT: For the change to take effect, close and open the WSL Linux terminal.

Verify the Git and Git Credential Manager installation in WSL
git --version; git credential-manager --version
Configure the Git Credential Manager in WSL
git-credential-manager configure
git config --global --replace-all  credential.hel
per "/mnt/c/Program Files/Git/mingw64/libexec/git-core/git-credential-wincred.exe"
Line ending auto conversion

For more information on Git line ending auto conversion see Resolving Git line ending issues in WSL (resulting in many modified files)

Credential Provider in WSL

To set up the Credential Provider for the repository you use see credential.provider

Install Git in Windows

Download and install Git from Git for Windows

Install the GitHub CLI on Windows

In the terminal execute

winget install --id GitHub.cli

IMPORTANT: For the path changes to take effect close and re-open the terminal window, or close and re-open Visual Studio Code if you use the integrated terminal.

Share the credentials between the Windows and WSL Git instances

In Windows execute

 git config --global credential.helper wincred
Create GitHub personal access tokens

In the GitHub Web interface create new Personal Access Tokens, one for Windows and one for WSL with the following scopes

  • repo
  • workflow
  • read:org
Authenticate in GitHub in Windows
 gh auth login

For more information see Set up a WSL development environment

Microsoft Azure Pipelines

Azure pipelines support the CI/CD (Continuous Integration, Continuous Deployment), the fully automated Continuous Delivery process.

Agents, either hosted by Microsoft, or self-hosted on the client’s infrastructure, execute the yaml scripts.

Steps

The smallest unit of work in the Azure Pipeline. Each step is one action in a job. A Step can be a Script or a Task.

Script

A Script is a command written in a scripting language to be executed as a step of a job.

Running a Bash Script

steps:
- script: echo "Hello, World!"
  displayName: 'Script to say Hello'
Task

A Task is a packaged script that can be used as a step within a job:

  • Built-in tasks from Azure Pipeline
  • Custom scripts written in PowerShell, Bash, Python or other languages
  • Third-party tasks from the Azure DevOps Marketplace

Running a Task, to execute an Azure CLI command with attributes

steps:
- task: AzureCLI@2
  displayName: 'Run Azure CLI Command'
  inputs:
    azureSubscription: 'MyAzureSubscription' # Service connection to Azure
    scriptType: 'bash'                     # Specify the script type (bash or ps)
    scriptLocation: 'inlineScript'          # Define the script location
    inlineScript: |                         # Start the inline script
      echo "Listing all resources in the resource group..."
      az resource list --resource-group MyResourceGroup

Jobs

The job is a single phase of the pipeline executing multiple steps. Jobs can run in parallel or in sequence if those depend on each other. It has its own context and workspace, so variables and files created in one job are kept separate from each other. This allows the easier troubleshooting of the process. Typical steps are:

  • Building code
  • Running tests

Stages

Stages hold related jobs together. It can represent

  • Environments, like
    • Development,
    • QA,
    • Production,
  • or Related jobs, like
    • Build,
    • Test,
    • Deploy.

Triggers

Triggers tells the pipeline to run. It can be based on

  • Events, like
    • A commit to a repository or
    • A pull request
  • or Schedules
    • To run at specific times, like end of the day.

Approval

Gatekeeper before the stage can proceed. The pipeline execution pauses until the approval arrives. It can be

  • Manual (like human approval is required before deployment to Production)
  • Automatic (like only during business hours, or when automated tests are passed)