[Azure Functions](GHOST_URL/devops-with-azure-functions-a-holistic-approach/" target="_blank) are great for creating solutions built on top of serverless architecture. In the past I've talked about the various deployment options but today I want to focus on performance improvements. The team recently introduced pre-compiled Functions which, in my mind, is a fantastic enhancement. Because it promotes good design by allowing you to decouple your implementation from the Function call itself and make your code a lot more testable. Some may digress because this may also cause Function code to explode in size. My answer to this is that you need to show restrain and keep your functions lean and fast.
If JavaScript is your poison and you've been developing Functions using Node.js, then you're likely to consume one or more npm packages. This is great as you don't have to write all the boilerplate code and you can focus on writing your Function code. However, there's an issue with NPM and that's the packages. When you deploy your Function, [Kudu](https://github.com/projectkudu/kudu" target="_blank) (the secret tool/engine running behind the AppService) has to resolve these dependencies before the Function is fully functional. If your NPM dependency tree is big, you can expect a significant lag as the packages are downloaded in the background.
There are 2 ways to address this issue:
- Upload the node_modules folder along with your Function as part of the deployment (not recommended IMHO)
- Use FuncPack (the WebPack derivative tool for Functions) to minimize and pack your code along with its dependencies
How to use Funcpack in your development process
Chris Anderson is the man behind this little tool. You can find the details and source code on [GitHub](https://github.com/christopheranderson/azure-functions-pack" target="_blank). This is an OSS project that anyone can contribute so feel free to help out.
Side note: using the tool and reporting bugs or feature requests can be an invaluable contribution so don't be shy and help make this tool mainstream!
Firstly, let's install the Azure Functions CLI, in case you don't have it already installed:
npm I -g azure-functions-cli
To install the tool, open the command line and run the following command:
npm i -g azure-functions-pack
With this in place we can now start using the tool to pack and unpack our Function code.
The commands available with this tool are:
Packing a Function
func pack [options] <path>
[Available Options]
-h, --help output usage information
-o, --output <path> Path for output directory
-u, --uglify Uglify the project when webpacking
Unpacking a Function
func unpack [options] <path>
[Available Options]
-h, --help output usage information
-o, --output <path> Path for output directory
The uglify feature only supports some small amount of ES6, so if you get errors either don't uglify or make sure your code targets ES5.
For the purpose of this demo, I've created a very basic Function with an HttpTrigger that consumes 2 NPM packages:
- moment.js
- underscore.js
Since I love the command line, I'll stick with the CLI. You, however, can use the Portal if you find it easier or more convenient. Each to its own people and make sure you use the tools you love and feel comfortable with :)
To create my Function, all I have to do is call the func init
command and follow the wizard as per my example below:
I can now test my Function and run it locally using the func run
command.
This is to prove that it works as expected. When running locally, the Functions CLI spins up a local server listening to incoming http requests. In this case, the Function can be hit over http://localhost:7071/api/myhttptrigger
. We can use any tool capable of sending an HTTP request (Postman, Fiddler, any browser) to test this URL. To pass the expected parameter, we can either send it in the body with a POST or as a URL parameter with a GET. For the last, I've attached an example below:
http://localhost:7071/api/myhttptrigger?name=Christos
We can see the Function executing and logging on the separately spun process:
Next, I'm going to pack my Function using the funcpack pack ./
command. I'll refrain from uglifying the code to keep things simple.
This command will have the following 2 effects:
- It will pack all my code and place it into a
.funcpack
folder - It will change the entry point of my Function to point to the right location, i.e my .funcpack folder
With this change the function.json
file should look like this:
We can run the Function again to make sure that all is working as expected:
Deploy to Azure Portal
You can use any of the methods I blogged about earlier for pushing your code to the portal:
- [Method A - Kudu API](GHOST_URL/deploying-azure-functions-with-arm-templates-and-the-kudu-rest-api/" target="_blank)
- [Method B - ARM templates](GHOST_URL/deploying-functions-with-arm-templates-and-inline-code/" target="_blank)
- [Method C - One of these](https://docs.microsoft.com/en-us/azure/azure-functions/functions-continuous-deployment" target="_blank)
The files you need to deploy are:
- function.json
- appsettings.json
- .funcpack
In the portal, once you've uploaded your files, you should have the following structure in the Kudu console:
Running the code for a test, should generate the following result:
The overall benefit to your deployment and Function size can be significant when using this method. It will also simplify your CI/CD with less files to worry about during deployment. For example, my Function size was reduced significantly and I didn't have to worry about npm restore
during the deployment of my Function.
I hope that this post will provide you with enough information to help you improve the deployment and management of your JavaScript-based Functions.
Did you know that we also supported .NET-based pre-compiled Functions now? Check Donna's post [here](https://blogs.msdn.microsoft.com/appserviceteam/2017/03/16/publishing-a-net-class-library-as-a-function-app/" target="_blank)
Make sure you use the comments if you have any questions or problems using my demo. You can download and test the sample code for this Function from [GitHub](https://github.com/cmatskas/functionwebpack" target="_blank)