Having developed five VSTS extensions (one public one you can use right now, Test Charts), we at Nebbia Technology have learned a thing or two about building them. In fact, we’ve spent hundreds of hours building Visual Studio Team Server extensions. Because we are a DevOps-focused company, we have found a few different ways that makes developing and deploying VSTS extensions to the Visual Studio Marketplace easier, faster, and repeatable. Here, we’re giving away our secret sauce to how we develop each and every one of our extensions.
For a single developer working on your first extension, it doesn’t seem all that painful. The process often looks like this: Write or modify some code, run a command that compiles and publishes the extension to a marketplace from your machine, and then check to see if the extension is doing what you want it to do. Developing and publishing a Visual Studio Team Services extension to the Visual Studio Marketplace is tolerable, at first.
As development continues, especially in the context of a team, there are some bottlenecks that emerge. First, developing at the same time as someone else can lead to a lot of “Hey, you updated the extension while I was updating the extension.” And, the time time it takes to compile and publish the extension again, and again, and again can get cumbersome as more and more data needs to be compiled into that .vsix file and then moved across the internet.
Also, every time an extension is updated in the marketplace, the version needs updated, and doing that manually every time is just a pain. And then there’s the fact that you need user credentials or a Personal Access Token to update the marketplace extension, which isn’t great to have floating around in source control for anyone to find, and even if every developer did update the extension using that credential, that means that as soon as you make your extension public it’s being both a development and production environment all-in-one.
So how do we mitigate those pain points? Without further adieu, here are our processes, tools, and how people can use them to make the VSTS extension experience better.
We like to use continuous integration and delivery to build and deploy our extensions when code has been pushed to the master branch. This makes a common source of truth for if things are building correctly, and it makes releasing repeatable and painless.
Because extensions can only be completely tested when they are integrated into the VSTS environment, it can be nerve-wracking having only one extension published to the marketplace. It has to play the roles of both Development and Production. To work around that, we have multiple extensions published to the marketplace, one for Local, one Dev, and one Production. Only the Production extension is public, of course.
To deploy to these environments, we utilize Microsoft’s CI/CD Tools for VSTS Extensions tasks. These abstract the commands typically used in the command-line to build and deploy .vsix packages to the Visual Studio Marketplace, and the GUI is a nice feature when you don’t remember every option available. Typically, it’s ideal to have a single build artifact that is released to multiple environments. Because of how extensions work, we have two. The first one is for Local, and the second is for both Development and Production. The noted difference is that the
BaseUri in the
vss-extension.json for the Local build points to a
localhost address. That’s because our local development uses an
iframe that points to our local machines so we can develop locally, making it so we don’t need to publish to the marketplace every time we change something in the code. I’ll explain how that works in more detail later on.
Because we need to increment the extension version every time we deploy it, we use the build id as the patch number. If ever want to go from 1.2.xxx to 1.3.xxx, we can make that change manually because we put the version numbers as variables in VSTS. This allows us to sanely version without a lot of effort, and it is much less annoying than trying to manually enter the version number every time it is deployed.
- VSTS Build: We use VSTS Build to compile our extensions.
- VSTS Release: We release automatically to Local and Dev environments. We use a gated release to release to production.
- CI/CD Tools for VSTS Extensions: We use these tasks to make it easier to build & release our extensions.
- Developer: Checks out code, writes code, does pull requests, possibly manages build & release pipelines.
- Product Owner: Approves deployments to production, possibly approves pull requests if they are technical.
We like to incorporate unit tests, regardless of if it is front-end, backend, or even database development. Doing so makes it easier to test the important parts of the application very quickly and often. The developer can run them locally, and the build system can do so at the integration point.
To run our unit tests, we use a combination of Mocha, Karma, Chai, and Sinon. Now, this is certainly a laundry list of tools to handle what in theory ought to be a simple proposition (front-end tests). You can use any testing framework(s) that you would like. We were influenced by Wael Kdouh’s article called “Unit testing using Typescript, Mocha, Chai, Sinon, and Karma.”, and this is one area we’d like to reduce dependencies in.
- Mocha: The front-end testing framework itself.
- Chai: Chai makes the language of tests a bit more flexible and palatable.
- Developer: The developer is responsible for making unit tests.
- Product Owner: The product owner is responsible for developing the high-level requirements the tests are helping to fulfill.
Development Cycle Time
Reducing the time it takes to write a line of code to seeing what it does allows for faster and more interactive software development. We’ve found that the time it takes to build a .vsix file, transfer it over the internet, and then reload the page manually can get intrusive when it’s done dozens of times in a day.
That’s why we decided to create a Local extension in the marketplace specifically for developing locally. If any changes to the vss-extension.json file changes, those need to be deployed (using our VSTS Build & Release pipeline, of course), but anything internal to the app does not need to be. Just develop, save, and then the extension automatically reloads thanks to the magic of Webpack. And as a bonus, this same extension can be used by multiple developers at the same time because the iframe is just a window into a locally hosted web page.
We use Webpack as our local web server because it’s well supported, robust, and is the all-in-one solution to compiling and running modern web development technologies like Typescript and SCSS. The caveat is that Webpack isn’t very opinionated, so if you aren’t familiar with how it works, setting it up can feel like building a house of cards. At any point, any setting can ruin the whole thing and it can be difficult to know what setting did it. They are making it easier and easier with every update, so keep your chin up if you run into issues and keep working at it, as it is well worth the effort once you’ve got it configured the way you’d like it.
- Webpack: Webpack is a front-end compiler that can help with bundling and building all that front-end stuff into a running application, and running it in a local server that can automatically update on saves. This makes development much faster, as developers can hit save after a change and see the updates in near-real-time.
- VS Code: Technically, any text editor can be used to make VSTS extensions. We highly recommend using VS Code, which is both powerful and lightweight. The debugging features (when properly set up) can be a huge boon to development capabilities, especially when using Typescript.
- Developer: This is all you, baby.
Dependencies & Dependency Management
Front-end web development has grown more complex over time. While it’s nostalgic to pine for the days of vanilla JS, CSS, and HTML, the truth is that when mastered, the modern tools of the trade can be a boon to productivity. With occasional frustration when it doesn’t work, I’ll give you that.
We use npm for our front-end package manager, which is pretty much the default in today’s world. While package management isn’t specific to VSTS extension development, it is especially worth mentioning this aspect of development since it is how we install the Visual Studio Teams Service Web Extension SDK. We also use it to install Webpack, TypeScript, the various testing tools, and my personal favorite, lodash. It makes it easier to update and maintain these dependencies, so I highly recommend using npm in your extension development.
- npm: A package manager (relies on Node.js behind the scenes) to manage all your front-end dependencies.
- Visual Studio Team Service Web Extension SDK: Abstracts the VSTS API and makes it much easier to work with.
- WebPack: See above, helps with development cycle time.
- Developer: May the burden of managing dependencies rest on your shoulders.
If you are looking to build your own extension, keep it simple and add tools slowly. If I have advice for where to start, I can say the biggest productivity boost for us was putting in a build & release pipeline and combining that with a locally hosted server via WebPack. I’d highly recommend starting there. And if you want any help on your journey, don’t be afraid to reach out to us; you can use our contact page or just find us on Twitter at @nebbiatech.