{"id":56813,"date":"2019-06-12T07:00:48","date_gmt":"2019-06-12T15:00:48","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/devops\/?p=56813"},"modified":"2019-06-12T07:57:59","modified_gmt":"2019-06-12T15:57:59","slug":"streamlining-azure-devops-extension-development","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/devops\/streamlining-azure-devops-extension-development\/","title":{"rendered":"Streamlining Azure DevOps extension development"},"content":{"rendered":"<p><a href=\"http:\/\/azure.com\/devops\" target=\"_blank\">Azure DevOps<\/a> has an incredibly deep set of functionality to allow you to build extensions for your team. You can add and modify elements in the UI as well as build back-end tasks. While the majority of features your team needs on a day-to-day basis are built in, extensions allow you to modify Azure DevOps to meet your needs. In this blog post, we&#8217;re going to highlight some tips and tricks to accelerate development of your own extension.<\/p>\n<h2>What&#8217;s the problem we&#8217;re trying to solve?<\/h2>\n<p>Most modern IDEs have built-in debugging tools that you can use to inspect code, insert breakpoints, manipulate values, etc. The <em>problem<\/em> is that when you&#8217;re writing extensions to Azure DevOps, they need to run <em>in the context of<\/em> Azure DevOps. The official Azure DevOps extension documentation includes a <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/extend\/test\/debug-in-browser\" target=\"_blank\">guide<\/a> on how to debug, but the approach it describes is to redeploy the extension to the marketplace each time you make a change and then use the browser&#8217;s built-in debugging tools. That process requires you to switch context to the browser&#8217;s dev tools every time you need to debug. Ideally, you would want to work directly inside your IDE or editor and debug immediately without having to publish to the marketplace.<\/p>\n<p>The following steps describe how to convert an existing extension to use an alternate approach to development that loads the code directly from your dev machine rather than from a deployed bundle from the marketplace. This takes advantage of the capability in Azure DevOps to load content from localhost, which will enable us to hot reload and debug in Visual Studio Code.<\/p>\n<h2>Step 1: Reconfigure your <strong>vss-extension.json<\/strong><\/h2>\n<ol>\n<li>Create a new configs folder, and place the following files in there, replacing <span style=\"background-color: #DDDDDD; font-family: Monaco,'MonacoRegular','Courier New',monospace !important;\">[extension-id]<\/span> with your extension&#8217;s ID: <span style=\"background-color: #DDDDDD; font-family: Monaco,'MonacoRegular','Courier New',monospace !important;\">configs\/dev.json<\/span> <\/li>\n<\/ol>\n<pre><code class=\"json\">\n{\n    \"id\": \"[extension-id]-dev\", \n    \"public\": false, \n    \"baseUri\": \"https:\/\/localhost:3000\" \n}\n<\/code><\/pre>\n<p><span style=\"background-color: #DDDDDD; font-family: Monaco,'MonacoRegular','Courier New',monospace !important;\">configs\/release.json<\/span><\/p>\n<pre><code class=\"json\">\n{\n    \"id\": \"[extension-id]\", \n    \"public\": true \n}\n<\/code><\/pre>\n<h2>Step 2: Update your <strong>webpack.config.json<\/strong><\/h2>\n<ol>\n<li>\n<p>Enable source map and point your dev server to <span style=\"background-color: #DDDDDD; font-family: Monaco,'MonacoRegular','Courier New',monospace !important;\">https:\/\/localhost:3000.<\/span><\/p>\n<pre><code class=\"json\">\nmodule.exports = {\ndevtool: \"inline-source-map\",\ndevServer: {\nhttps: true,\nport: 3000\n}\n\/\/ ...\n};\n<\/code><\/pre>\n<\/li>\n<li>\n<p>Configure the dev server to serve files from the correct path.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"js\">\nmodule.exports = {\n    output: {\n    publicPath: \"\/dist\/\"\n        \/\/ ...\n    }\n    \/\/ ...\n};\n<\/code><\/pre>\n<h2>Step 3: Enable Firefox debugging in your Visual Studio Code <span style=\"background-color: #DDDDDD; font-family: Monaco,'MonacoRegular','Courier New',monospace !important;\">launch.json<\/span> file<\/h2>\n<ol>\n<li>Install <a href=\"https:\/\/www.mozilla.org\/firefox\/\" target=\"_blank\">Firefox<\/a>.<\/li>\n<\/ol>\n<blockquote style=\"margin-left: 0px; width:100%\">\n<p>\n    We use Firefox because the Visual Studio Code &#8211; Debugger for Chrome extension doesn&#8217;t yet support iframes. If you would prefer to debug your extension in Chrome, please add your support to this <a href=\"https:\/\/github.com\/microsoft\/vscode-chrome-debug\/issues\/786\" target=\"_blank\">feature request<\/a>.\n  <\/p>\n<\/blockquote>\n<ol>\n<li>Install the <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=hbenl.vscode-firefox-debug\" target=\"_blank\">Debugger for Firefox<\/a> extension for Visual Studio Code.<\/li>\n<li>Add the following configuration to your <strong>launch.json<\/strong> file:<\/li>\n<\/ol>\n<pre><code class=\"json\">\n{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n        {\n            \"name\": \"Launch Firefox\",\n            \"type\": \"firefox\",\n            \"request\": \"launch\",\n            \"url\": \"https:\/\/localhost:3000\/\",\n            \"reAttach\": true,\n            \"pathMappings\": [\n                {\n                    \"url\": \"webpack:\/\/\/\",\n                    \"path\": \"${workspaceFolder}\/\"\n                }\n            ]\n        }\n    ]\n}\n<\/code><\/pre>\n<h2>Step 4: Configure and run your debug server<\/h2>\n<ol>\n<li>Install the <a href=\"https:\/\/www.npmjs.com\/package\/webpack-dev-server\" target=\"_blank\">webpack-dev-server<\/a> package in your app.<\/li>\n<\/ol>\n<pre><code class=\"shell\">npm install --global webpack-dev-server<\/code><\/pre>\n<ol>\n<li>Launch your dev server.<\/li>\n<\/ol>\n<pre><code class=\"shell\">webpack-dev-server --mode development<\/code><\/pre>\n<h2>Step 5: Deploy your debug extension<\/h2>\n<ol>\n<li>If you haven&#8217;t already installed it, you&#8217;ll need to install the <a href=\"https:\/\/www.npmjs.com\/package\/tfx-cli\" target=\"_blank\">tfx-cli<\/a> in order to publish your extension.<\/li>\n<\/ol>\n<pre><code class=\"shell\">npm install --global tfx-cli<\/code><\/pre>\n<ol>\n<li>Run the following command to deploy a <em>dev<\/em> version of your extension.<\/li>\n<\/ol>\n<pre><code class=\"shell\">tfx extension publish --manifest-globs vss-extension.json --overrides-file configs\/dev.json --token [token]<\/code><\/pre>\n<blockquote style=\"margin-left: 0px; width:100%\">\n<p>\n    This will have a different ID from your <i>release<\/i> version (see the <b>dev.json<\/b> above), so you will need to install this new extension in your respective Azure DevOps project to see it running.\n  <\/p>\n<\/blockquote>\n<h2>Step 6: Launch Firefox and debug<\/h2>\n<ol>\n<li>Accept the HTTPS certificate warning. <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/certificate-warning2.png\" alt=\"certificate warning\" width=\"1456\" height=\"826\" class=\"aligncenter size-full wp-image-56830\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/certificate-warning2.png 1456w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/certificate-warning2-300x170.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/certificate-warning2-768x436.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/certificate-warning2-1024x581.png 1024w\" sizes=\"(max-width: 1456px) 100vw, 1456px\" \/> <\/li>\n<li>Put a breakpoint in Visual Studio Code and then browse to your extension. <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/extension-running.png\" alt=\"\" width=\"3024\" height=\"1764\" class=\"aligncenter size-full wp-image-56827\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/extension-running.png 2048w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/extension-running-300x175.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/extension-running-768x448.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/extension-running-1024x597.png 1024w\" sizes=\"(max-width: 3024px) 100vw, 3024px\" \/> <\/li>\n<li>You should see your breakpoint hit in Visual Studio Code. <img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/breakpoint-hit2.png\" alt=\"breakpoint debugging\" width=\"3024\" height=\"1764\" class=\"aligncenter size-full wp-image-56831\" srcset=\"https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/breakpoint-hit2.png 2048w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/breakpoint-hit2-300x175.png 300w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/breakpoint-hit2-768x448.png 768w, https:\/\/devblogs.microsoft.com\/devops\/wp-content\/uploads\/sites\/6\/2019\/06\/breakpoint-hit2-1024x597.png 1024w\" sizes=\"(max-width: 3024px) 100vw, 3024px\" \/> <\/li>\n<\/ol>\n<h2>Conclusion<\/h2>\n<p>For more detailed, step-by-step instructions, see <a href=\"https:\/\/github.com\/microsoft\/azure-devops-extension-hot-reload-and-debug\" target=\"_blank\">this repo<\/a> and if you want to start a new extension project, check out the <a href=\"https:\/\/www.npmjs.com\/package\/@microsoft\/generator-azure-devops-extension\" target=\"_blank\">Yeoman generator<\/a> our team built to get everything set up faster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Azure DevOps has an incredibly deep set of functionality to allow you to build extensions for your team. Learn how to develop Azure DevOps extensions faster from your local environment using Visual Studio Code, React and webpack.<\/p>\n","protected":false},"author":4848,"featured_media":56837,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229],"tags":[],"class_list":["post-56813","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-community"],"acf":[],"blog_post_summary":"<p>Azure DevOps has an incredibly deep set of functionality to allow you to build extensions for your team. Learn how to develop Azure DevOps extensions faster from your local environment using Visual Studio Code, React and webpack.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/56813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/users\/4848"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/comments?post=56813"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/posts\/56813\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media\/56837"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/media?parent=56813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/categories?post=56813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/devops\/wp-json\/wp\/v2\/tags?post=56813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}