Azure Web Apps Source Deployments with Gulp
In my last blog post “Ionic Framework as a Web Site” I detailed some changes I need to make to an Ionic app to utilize it as a web site. Step 2 of that process was trying to land my new Ionic Site somewhere. As Resgrid is a 100% cloud company we put it on Azure. So we created an Azure Web App, pointed it at our source control and then it all broke. The structure of source we use for Ionic or AppBuilder doesn’t lend itself to becoming a website from the folder structure, as is the common use case for source control provider deployments. The solution, Gulp!
Azure uses an open source project called Kudu as an engine for executing git/hg deployments, running tasks and even WebJobs. This allows your to take code from a source code repository have Azure pick it up and deliver it to the cloud and run additional operations.
Note that Kudu itself isn’t limited to Gulp, you can run pretty much anything the underlying Azure VM has access to. Creating the script is pretty simple. If you have the Azure CLI tools installed you can run the following command:
azure site deploymentscript
Note there are a number of default switches you can use for example –aspWebSite for your ASP/MVC/WebAPI sites, –node, –php, –python and finally –basic. This command will create 2 files, a .deployment file and a deploy.cmd file. For the Ionic Framework one we used –node as our switch. The .deployment file is pretty simple:
[config] command = deploy.cmd
This just a configuration file for Azure to tell it what to run. There is a lot you can do with with the .deployment file. The other file created is the deploy.cmd file, below is the one used in Resgrid’s Ionic Framework app deployment. I cut the code above out for brevity, at the end of the Setup section, just above this section of code is the “IF NOT DEFINED KUDU_SYNC_CMD” check.
:: Code above omitted for brevity IF NOT DEFINED GULP_CMD ( :: Install gulp echo Installing Gulp call npm --registry "http://registry.npmjs.org/" install gulp -g --silent IF !ERRORLEVEL! NEQ 0 goto error :: Locally just running "gulp" would also work SET GULP_CMD="%appdata%\npm\gulp.cmd" ) goto Deployment :: Utility Functions :: ----------------- :SelectNodeVersion IF DEFINED KUDU_SELECT_NODE_VERSION_CMD ( :: The following are done only on Windows Azure Websites environment call %KUDU_SELECT_NODE_VERSION_CMD% "%DEPLOYMENT_SOURCE%" "%DEPLOYMENT_TARGET%" "%DEPLOYMENT_TEMP%" IF !ERRORLEVEL! NEQ 0 goto error IF EXIST "%DEPLOYMENT_TEMP%\__nodeVersion.tmp" ( SET /p NODE_EXE=<"%DEPLOYMENT_TEMP%\__nodeVersion.tmp" IF !ERRORLEVEL! NEQ 0 goto error ) IF EXIST "%DEPLOYMENT_TEMP%\__npmVersion.tmp" ( SET /p NPM_JS_PATH=<"%DEPLOYMENT_TEMP%\__npmVersion.tmp" IF !ERRORLEVEL! NEQ 0 goto error ) IF NOT DEFINED NODE_EXE ( SET NODE_EXE=node ) SET NPM_CMD="!NODE_EXE!" "!NPM_JS_PATH!" ) ELSE ( SET NPM_CMD=npm SET NODE_EXE=node ) goto :EOF :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: Deployment :: ---------- :Deployment echo Handling custom app deployment :: Select node version call :SelectNodeVersion :: Install NPM Packages IF EXIST "%DEPLOYMENT_SOURCE%\package.json" ( pushd "%DEPLOYMENT_SOURCE%" echo Installing NPM Dependicies. call :ExecuteCmd !NPM_CMD! install IF !ERRORLEVEL! NEQ 0 goto error popd ) :: Run Gulp to build website from mobile app IF EXIST "%DEPLOYMENT_SOURCE%\gulpfile.js" ( pushd "%DEPLOYMENT_SOURCE%" echo Running Gulp. call :ExecuteCmd !GULP_CMD! web:build IF !ERRORLEVEL! NEQ 0 goto error popd ) :: KuduSync echo Handling Basic Web Site deployment. IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" ( call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_SOURCE%\web" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd" IF !ERRORLEVEL! NEQ 0 goto error )
The Utility functions are important. They setup the environment variables for Node and NPM. Note that Azure typically runs a few versions older then the current node version. Additionally some NPM dependencies, like fibers, that require locally complication (and thus Visual Studio or some other compiler) installed won’t work on Azure.
The Deployment section is where the big stuff happens. We first call our SelectNodeVersion utility function to setup Node and NPM then run NPM to install our modules. Again be cautious of what node modules you add, keep it to the bare minimum.
The next step is we run our gulp command against our gulpfile.js and call our task to be run, in this case it’s “web:build”. There is no Azure specific items in our gulpfile, we just copy our web items into a folder “called web at the root of our solution” and for KuduSync (the command that handles copying to the wwwroot) we point it to “%DEPLOYMENT_SOURCE%\web”.
Azure is a great PaaS (Platform as a Service) for your Microsoft and non-Microsoft technologies. Personally I feel that their PaaS capabilities far exceed any other cloud provider out there and when solving problems like the one above, using zero MS Tech, I was easily able to accomplish my goals without ever touching a VM or worrying about configuration.
Resgrid is a SaaS product utilizing Microsoft Azure, providing logistics, management and communication tools to first responder organizations like volunteer fire departments, career fire departments, EMS, search and rescue, CERT, public safety, disaster relief organizations, etc. It was founded in late 2012 by myself and Jason Jarrett (staxmanade).