Host create react app on azure

If you just want to get going here is a link to my repo with everything you need.

When creating a new react app there seems to be a consensus in the community that we should use create-react-app. I think this is brilliant and I’m using it for my projects. I also like Azure and the awesome stuff that Microsoft is doing in the cloud. But I could only find one blogpost that connected the two. The solution in that post is to add a file to tell Azure how to handle incoming requests and then manually upload the files to the website, but I wanted automation.

The first thing I tried was to automate the FTP calls with two bash script that went through the build folder and created folders and uploaded all the files recursively. It felt lika a gigant hack and didn’t really work on my CI service, CircleCI. Here are the scripts I used.

deploy.sh
cp web.config ./build/web.config
cd build
find . -type d -exec ../scripts/recursive-ftp.sh {} \;
cd ..
recursive-ftp.sh
#!/bin/bash
ftp_site=$FTP_SITE
username=$FTP_USERNAME
passwd=$FTP_PASSWORD
remote='site/wwwroot'
folder=$1
cd $folder
pwd

ftp -p -in <<EOF
open $ftp_site
user $username $passwd
mkdir $remote/$folder
cd $remote/$folder
mput *
close
bye
EOF

So I went back to the drawing board. I remembered when I wanted to deploy iojs on azure back in the days that we can customize the deploy scripts that are run in azure. So I used the azure CLI to generate the scripts and changed them so that they installed and built before copying the files. The files also had to be put straight in the wwwroot and not a subfolder so I had to change that as well. Here is the customized script.

deploy.sh
#!/bin/bash

# ----------------------
# KUDU Deployment Script
# Version: 1.0.9
# ----------------------

# Helpers
# -------

exitWithMessageOnError () {
if [ ! $? -eq 0 ]; then
echo "An error has occurred during web site deployment."
echo $1
exit 1
fi
}

# Prerequisites
# -------------

# Verify node.js installed
hash node 2>/dev/null
exitWithMessageOnError "Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment."

# Setup
# -----

SCRIPT_DIR="${BASH_SOURCE[0]%\\*}"
SCRIPT_DIR="${SCRIPT_DIR%/*}"
ARTIFACTS=$SCRIPT_DIR/../artifacts
KUDU_SYNC_CMD=${KUDU_SYNC_CMD//\"}

if [[ ! -n "$DEPLOYMENT_SOURCE" ]]; then
DEPLOYMENT_SOURCE=$SCRIPT_DIR/build
fi

if [[ ! -n "$NEXT_MANIFEST_PATH" ]]; then
NEXT_MANIFEST_PATH=$ARTIFACTS/manifest

if [[ ! -n "$PREVIOUS_MANIFEST_PATH" ]]; then
PREVIOUS_MANIFEST_PATH=$NEXT_MANIFEST_PATH
fi
fi

if [[ ! -n "$DEPLOYMENT_TARGET" ]]; then
DEPLOYMENT_TARGET=$ARTIFACTS/wwwroot
else
KUDU_SERVICE=true
fi

if [[ ! -n "$KUDU_SYNC_CMD" ]]; then
# Install kudu sync
echo Installing Kudu Sync
npm install kudusync -g --silent
exitWithMessageOnError "npm failed"

if [[ ! -n "$KUDU_SERVICE" ]]; then
# In case we are running locally this is the correct location of kuduSync
KUDU_SYNC_CMD=kuduSync
else
# In case we are running on kudu service this is the correct location of kuduSync
KUDU_SYNC_CMD=$APPDATA/npm/node_modules/kuduSync/bin/kuduSync
fi
fi

# Node Helpers
# ------------

selectNodeVersion () {
if [[ -n "$KUDU_SELECT_NODE_VERSION_CMD" ]]; then
SELECT_NODE_VERSION="$KUDU_SELECT_NODE_VERSION_CMD \"$DEPLOYMENT_SOURCE\" \"$DEPLOYMENT_TARGET\" \"$DEPLOYMENT_TEMP\""
eval $SELECT_NODE_VERSION
exitWithMessageOnError "select node version failed"

if [[ -e "$DEPLOYMENT_TEMP/__nodeVersion.tmp" ]]; then
NODE_EXE=`cat "$DEPLOYMENT_TEMP/__nodeVersion.tmp"`
exitWithMessageOnError "getting node version failed"
fi

if [[ -e "$DEPLOYMENT_TEMP/__npmVersion.tmp" ]]; then
NPM_JS_PATH=`cat "$DEPLOYMENT_TEMP/__npmVersion.tmp"`
exitWithMessageOnError "getting npm version failed"
fi

if [[ ! -n "$NODE_EXE" ]]; then
NODE_EXE=node
fi

NPM_CMD="\"$NODE_EXE\" \"$NPM_JS_PATH\""
else
NPM_CMD=npm
NODE_EXE=node
fi
}

##################################################################################################################################
# Deployment
# ----------

echo Handling node.js deployment.
# 1. Select node version
selectNodeVersion

# 2. Install npm packages
if [ -e "$DEPLOYMENT_SOURCE/package.json" ]; then
cd "$DEPLOYMENT_SOURCE"
eval $NPM_CMD install
exitWithMessageOnError "npm failed"
cd - > /dev/null
fi

# 3. KuduSync
if [[ "$IN_PLACE_DEPLOYMENT" -ne "1" ]]; then
"$KUDU_SYNC_CMD" -v 50 -f "$DEPLOYMENT_SOURCE/build" -t "$DEPLOYMENT_TARGET" -n "$NEXT_MANIFEST_PATH" -p "$PREVIOUS_MANIFEST_PATH" -i ".git;.hg;.deployment;deploy.sh"
exitWithMessageOnError "Kudu Sync failed"
fi

##################################################################################################################################
echo "Finished successfully."

As you can see I have changed very little in the script.

Hope this will help someone more than me.