Part two: Multi-tenant sites in Umbraco

If you read my previous post about Separating your concerns in a single Umbraco site install, you may wanna know that I've made an optional improvement to the flow. Using Grunt as a file watcher\copy instead of post-build events.

The gist

Post-build events work but they are slow. All you really need is the views\assets to be copied when one is changed. You won't want to wait for the build to happen just to get your copy. Enter the next evolution: Grunt task runner.


Using Grunt is plenty amazing but it isn't with it's own baggage. Grunt is a Node.js task runner designed to remove repetitive steps. In our case we'll use it to copy files to the proper spot when it detects a file has been modified or created.

The setup

Setting up Grunt isn't terribly involved so I'll try to do the basics here, then show you my gruntfile.js which is the real guts of the operation.

  1. First install Node.js. Don't let this scare you. We're only using it for local development. There will be no Azure\hosting need for Node.js.
  2. Install Grunt. Again, don't be scared. Grunt is just a tiny command line tool run on top of Node.js.
  3. Create a package.json and a gruntfile.js file at your repo root (follow the links to get the full guts of what you need).
  4. Adjust your gruntfile to reflect your paths in your project.

Some explanation

The package.json file works just like a Nuget packages.config file except it is for NPM (Node package manager).

You'll need to run 'npm install' from your repo root (via command line). This will install what is in the packages.json.

Next, the gruntfile.js is the definition of 'tasks'. In the same gruntfile above, I have tasks that do the following:

Watch - This will monitor any files that change in the given path. Once detected, we'll run another task such as 'Copy the files somewhere'.

Less - This is superfluous to this conversation, but you'll see that I'm using a LESS plugin in this too. Just know there are a bunch of plugins for Grunt.

Copy - This is the task that actually does the copy.

To run the tasks, I had to create 'commands' at the bottom. This section defines these commands:


grunt.registerTask('assets', ['less', 'copy:blogAssets', 'copy:blogViews', 'copy:oakGroveAssets', 'copy:oakGroveViews']);
grunt.registerTask('default', 'assets');
grunt.registerTask('just-less', ['less']);


From the command line, my options to type are now:


`grunt assets`

`grunt just-less`

`grunt watch`

If I type `grunt`, it'll run the default pipeline of sub-tasks (shown in the list).

If I type `grunt assets`, it'll also just run the default.

If I type `grunt just-less` it'll run just the LESS conversion.

If I type `grunt watch` it'll start listening, then run the copy command afterwards. A sample screenshot is below.

By doing a one-time setup of Grunt, I now no longer have to endure the build times to simply copy some files.


So to sum up, this is just a way to also copy sites and assemble a multi-tenant site without having to co-locate all the code. After you setup everything, run `grunt watch` and the magic happens for you in the background. There is no need to install Node.js on your Azure instance as this is just for local usage.