Yesterday I was wrestling with this one, and with a bit of help from David Ebbo (twitter: @davidebbo) I was able to get this solution.
- Node.js web app
- Azure App Service
- Continuous Deployment via git
I have a node.js web app that includes a build script. This build script creates the distribution files for the web app (front-end). Ultimately, I could make my life really simple and just locally run the build script to generate the ugly (and dynamically-named) dist files. This poses a couple of problems though, mainly with the git repo (build script runs, new dist file names are generated resulting in a delete and add for the git repo). Not to mention, it’s typically bad practice to include generated files in a git repo (include the process (i.e. the build script), not the results (i.e. the dist files)).
So, needless to say, I didn’t want to have to commit my distributable files to the git repo just so they would live in my Azure App Service upstream repo (CD).
Kudu does npm install –production by default
Yep, this was a kicker for me. No big deal, I want my build script to run post git push to Azure App Service upstream. But wait, my build script has
devDependencies that it requires. And it turns out… Kudu (understandably so) runs
npm install --production by default, which only installs
dependencies and omits
devDependencies. One of those things that if you really think about it, makes total sense. But an issue for me.
Custom deploy script to the rescue!
Ultimately for my use-case I needed to force Kudu to run
npm install instead of
npm install --production so that I would have my
devDependencies resident in my remote web app.
Here is a super handy way to do this. Basically you need to pull down the deployment configuration and deployment script so that we could modify it. The deployment configuration is
.deployment and the deployment script is
The way to retrieve these locally is to have your current working directory as the root of the git repo, and use the Azure CLI to run
azure site deploymentscript --node. This creates those two deployment files in your current working directory. deploy.sh may look daunting at first glance, but it’s really quite simple to grok once you start reading it. Ultimately, for my purposes I needed to change this line:
1 eval $NPM_CMD install --production
1 eval $NPM_CMD install
Perfect! Now I have
devDependencies living in my remote after a
But how do you kick off the post-deployment build script?
That’s right… all of this is for naught if I didn’t actually run the build script to generate my dist files. I had originally continued on with the deploy.sh approach and just put
eval $NPM_CMD run build in there, but that was giving me a handful of errors. Instead of troubleshooting that, I took a step back and used the actual package.json config file to put this script invocation in the appropriate place.
scripts section I added a postinstall script to run my build script. This is a simple node
scripts/build.js for my particular solution.
Build script is running! But wait… Windows max path issue.
Using a newer Node.js/npm version
This is worth noting, and David helped out big time here. I was running into max path issues with Azure App Service because of my npm dependency tree. Behavior changed in npm v3 to handle this in a better fashion, but unfortunately an older version of npm was being used.
The workaround to this was to add/change the app setting in the Azure App Service
WEBSITE_NODE_DEFAULT_VERSION to a newer node version (in my case, 6.9.1).
Finally! Success! The end result was the desired outcome… No longer committing and tracking distributable files generated by the build process, and running this all post git push to Azure App Service upstream repo.