I’m really enjoying Angular and Azure, but getting them to work well together is sometimes a pain. Right now, there’s some real catch-up that Azure App Services needs to do in order to embrace anything beyond Angular 7.
That’s because Angular 8 and up (“Angular 8+”) requires Node 12.x, and the latest version of Node.js that Azure App Services supports is 10.6.0. As a result, you cannot do a “build” of an Angular 8+ App on Azure.
Angular is moving rapidly, and they’re already in 9.0 pre-release. I’ve recently moved my own projects to Angular 8.
And I’ve sadly discovered I cannot currently use the standard “Deploy from Github” method to deploy Angular apps to Azure, because the build (which takes place on Azure, using this method) will fail, with an error that the version of Node.js is too outdated. And no, you cannot easily install new versions of Node.js on Azure App Services, because one of the design goals of that App Services platform is to have a curated set of known services, not a “free machine in the cloud” that you can install anything and everything to. You can certainly choose different versions of Node, but you cannot choose anything compatible with Angular 8+ at this writing.
That’s a shame, because continuous integration is a really nice feature of Azure. With it, you do a simple check-in and push to GitHub on a designated deploy branch (I usually choose “master” for this purpose), and then Azure fetches the build from GitHub, does the build locally on your App Services instance, and, with the right tweaks to your deployment script, copies it to the right directory. (Such a build-and-deploy custom script is covered in a prior post on this blog.)
Yes, I could try dockerizing everything, but I really don’t want to do that. I prefer not to have docker always running on my dev machines, and for most of my smaller projects, it’s overkill, because I’m just deploying a Single Page Application and one API.
So, Back to FTP
In the meantime, I’m resorting to simple, tried-and-true FTP deployment with a little automation help from Python.
Remember, all Azure really needs is the contents of your “dist” folder, which is built with the command: “ng build –prod”.
I’ve written a simple python script to do the (Angular 8+) build locally on my dev machine (after testing locally of course), and then it will automatically deploy it via FTP succeeds. Since most of my Angular apps are pretty small (and I like to have a single Git repo with the API back-end and Angular front-end), the process completes far faster than the Continuous Integration approach. I wouldn’t recommend this for large-team, large-scale projects, but it works very well for smaller and especially solo projects.
I expect that eventually, the Azure team will upgrade the versions of Node they support to 12+. When that happens, I’ll likely switch back to Continuous Integration deployment.
If you’d like to go the “build locally and FTP the final ‘dist’ site” route, save this file (called deploybuild.py) into your Angular app’s “src” folder:
# this file is called deploybuild.py import os.path, os from ftplib import FTP, error_perm host = 'azure.host.name.goes.here.azurewebsites.windows.net' port = 21 ftp = FTP() ftp.connect(host,port) ftp.login('username','password') ftp.cwd('/site/wwwroot') # set filenameCV to your full, absolute path to the "dist" folder # of the completed build on your local machine when you do # an "ng build --prod" filenameCV = "c:\\build\\your-project-folder\\dist" def placeFiles(ftp, path): for name in os.listdir(path): localpath = os.path.join(path, name) if os.path.isfile(localpath): print("STOR", name, localpath) ftp.storbinary('STOR ' + name, open(localpath,'rb')) elif os.path.isdir(localpath): print("MKD", name) try: ftp.mkd(name) # ignore "directory already exists" except error_perm as e: if not e.args.startswith('550'): raise print("CWD", name) ftp.cwd(name) placeFiles(ftp, localpath) print("CWD", "..") ftp.cwd("..") # first, do the build locally buildResult = os.system("ng build --prod") # if there is an error, stop if (buildResult==1): print("ERROR IN BUILD. NOT DEPLOYING.") ftp.quit() exit placeFiles(ftp, filenameCV) ftp.quit()
To run this script, once you’re ready to deploy your local build, you just issue:
Note that you will get a “cannot rmdir <directory name>” error during the build if you happen to have the project open in another window (say, a manual FTP client.) That’s because “ng build –prod” first wants to clear-out the dist directory, and it cannot, if you have the window open in another application.
Steve’s an entrepreneur and software leader. Most recently, he founded HipHip.app, the easiest way to create celebration videos. He also founded bigthanks.org, helping people discover and share productive ways they can respond in times of crisis. Steve’s worked on consumer apps, online travel, games, relational databases, management consulting and telecom. He launched Alignvote in 2019, which helped Seattle voters find their best-match political candidates. Steve founded BigOven, the first recipe app for iPhone, now with more than 15 million downloads, which was purchased in 2018. Steve served as Chairman of Escapia Inc., the leading SaaS solution for the US vacation rental industry, sold to Homeaway, now part of Expedia. In 1997, Steve was cofounder, President, CEO and Chairman of VacationSpot, a pioneer in the online reservation of vacation rentals, bought by Expedia in January 2000. At Expedia, Steve was Vice President of Vacation Packages, leading the vacation package and destination services teams, helping to create two patents on the first-ever dynamic vacation packaging system on the Internet, which now represents billions in annual transactions for Expedia.
He has keynoted on several occasions at the Vacation Rental Managers Association (VRMA), and taught a graduate level course on the strategic management of innovation at the University of Washington Foster Business School in Seattle, Washington.
Steve worked for Microsoft from 1991 to 1997 in a variety of senior marketing and executive positions, and led the creation of the internet games group, helping develop several products and patents related to online multiplayer gaming. He helped launch Microsoft Access and was involved in the acquisition of Fox Software by Microsoft in 1993. He’s worked for IBM, Booz-Allen Hamilton and Bell Communications Research.
He holds an MS in Computer Science from Stanford University in Symbolic and Heuristic Computation (AI), an MBA from Harvard Business School, where he was named a George F. Baker Scholar (awarded to top 5% of graduating class), and a dual BS in Applied Mathematics / Computer Science and Industrial Management from Carnegie Mellon University (CMU) with University Honors. Steve volunteers when time allows with Habitat for Humanity, University District Food Bank, YMCA Seattle, Technology Access Foundation (TAF) and other organizations in Seattle.