{"id":852,"date":"2021-04-07T10:00:28","date_gmt":"2021-04-07T09:00:28","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/sustainable-software\/?p=852"},"modified":"2021-04-06T14:22:58","modified_gmt":"2021-04-06T13:22:58","slug":"build-a-green-browser-extension","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/sustainable-software\/build-a-green-browser-extension\/","title":{"rendered":"Build a &#8216;Green&#8217; Browser Extension"},"content":{"rendered":"<blockquote><p><strong>Credits<\/strong>: This browser extension was inspired by Adebola Adeniran who built a very useful\u00a0<a href=\"https:\/\/github.com\/onedebos\/covtension\">extension<\/a>\u00a0for Chrome and Edge to track COVID country by country via API calls. He wrote an excellent\u00a0<a href=\"https:\/\/blog.adebola.dev\/how-to-build-a-chrome-extension-that-makes-api-calls\/\">article<\/a>\u00a0about it. Thanks also to Asim Hussain who told me about these APIs as well. And thanks to the\u00a0<a href=\"https:\/\/energylollipop.com\/\">Energy Lollipop extension<\/a> for California emissions for their &#8216;dot&#8217; color extension marker idea.<\/p><\/blockquote>\n<p><span style=\"font-size: 1rem;\">If you&#8217;ve never built a browser extension, it&#8217;s surprisingly fun and addictive. Have little repetitive tasks that could be helped by having something right at your fingertips, pinned to your browser bar? How about a little dot that can tell you, at a glance, whether your geographic region is undergoing a moment of heavy C02 usage on the electric grid? Would it help you make a decision on whether or not to run your clothes dryer?<\/span><\/p>\n<p>According to Asim Hussain&#8217;s\u00a0<a href=\"https:\/\/docs.microsoft.com\/en-us\/learn\/modules\/sustainable-software-engineering-overview\/?WT.mc_id=academic-23300-jelooper\">8 Principles of Sustainable Software Development<\/a>, one of the goals of a &#8216;Green Developer&#8217; is to help users make decisions that can have a meaningful impact on carbon impact. In addition, a Green Developer should be mindful of the carbon impact of their software itself. A carbon extension, hosted locally and only making ad-hoc API calls might be a particularly sustainable idea.<\/p>\n<blockquote><p>Beware! Not all browser extensions are &#8216;green&#8217; by default. Some seem to consume a lot of resources.<\/p>\n<p><a class=\"article-body-image-wrapper\" href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--2eZu9ggd--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/b5zlv788o8irkf5vnvy8.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--2eZu9ggd--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/b5zlv788o8irkf5vnvy8.png\" alt=\"A heavy browser extension\" \/><\/a><\/p><\/blockquote>\n<p>Let&#8217;s build a small &#8216;green&#8217; browser extension! We will be inspired by Adebola&#8217;s extension to call\u00a0<a href=\"https:\/\/www.tmrow.com\/\">tmrow<\/a>&#8216;s\u00a0<a href=\"https:\/\/api.electricitymap.org\/\">electricityMap API<\/a>\u00a0to track regional electricity usage, so that you can have a reminder right in your browser about how heavy your region&#8217;s electricity usage is so that you can make educated judgement calls on your activities based on this information.<\/p>\n<blockquote>\n<p style=\"padding-left: 40px;\">Curious about the potential environmental impact of your decisions? Take\u00a0<a href=\"https:\/\/www.nytimes.com\/interactive\/2020\/08\/30\/climate\/climate-footprint-quiz.html\">this quiz<\/a><\/p>\n<\/blockquote>\n<p>I&#8217;ve created some sample code to get you up and running quickly:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>git clone https:\/\/github.com\/jlooper\/carbon-trigger-extension\/tree\/start &amp;&amp; cd carbon-trigger-extension\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<ul>\n<li>Be sure to checkout the\u00a0<code>start<\/code>\u00a0branch (the main branch is the full code, in case you just want to take a look)<\/li>\n<li>Navigate to the root and install the required packages<\/li>\n<\/ul>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>npm install\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><span style=\"font-size: 1rem;\">Explore the files:<\/span><\/div>\n<\/div>\n<\/div>\n<ul>\n<li>dist\/manifest.json (defaults are set here)<\/li>\n<li>src\/index.js (your JS code goes here)<\/li>\n<li>dist\/index.html (frontend HTML markup here)<\/li>\n<li>dist\/background.js (JS that runs in the background)<\/li>\n<li>dist\/index.js (built JS)<\/li>\n<\/ul>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/azure\/build-a-green-browser-extension-5c49-temp-slug-4374282?preview=bcb084154eea92d14e05c5417d4d3e3f74f7c84cb303c562c07fd00fa61496540796290f745781cebc4bed4a46aaa0b91f916fa1b157dce284c87656#get-an-api-key\" name=\"get-an-api-key\"><\/a>Get an API Key<\/h2>\n<p>You&#8217;ll need an API key for CO2 Signal&#8217;s API. Get one\u00a0<a href=\"https:\/\/www.co2signal.com\/\">via email<\/a>; enter your email in the box on this page and it will be sent to you. Also grab the code for your region corresponding to the\u00a0<a href=\"https:\/\/www.electricitymap.org\/map\">Electricity Map<\/a>. In Boston, USA, for example, I use &#8216;US-NEISO&#8217;.<\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/azure\/build-a-green-browser-extension-5c49-temp-slug-4374282?preview=bcb084154eea92d14e05c5417d4d3e3f74f7c84cb303c562c07fd00fa61496540796290f745781cebc4bed4a46aaa0b91f916fa1b157dce284c87656#develop-your-extension-follow-the-forest-trail\" name=\"develop-your-extension-follow-the-forest-trail\"><\/a>Develop your Extension: Follow the Forest Trail<\/h2>\n<p>I&#8217;ve added \ud83c\udf31 little leaf emoji \ud83c\udf31 in the areas where you need to complete the code following the steps below. It&#8217;s a nice way to tweak an almost-finished codebase and learn about the process.<\/p>\n<p><strong>If anything is in localStorage, pick it up<\/strong><\/p>\n<p>Add a check to the init() function to see if any API key or Region has been set in localStorage<\/p>\n<pre class=\"prettyprint\">\/\/ src\/index.js\r\n\r\nconst storedApiKey = localStorage.getItem('apiKey');\r\nconst storedRegion = localStorage.getItem('regionName');\r\n<\/pre>\n<p><strong>Manage local storage inputs<\/strong><\/p>\n<p>In the setUpUser method, set the user-entered API key and Region<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/index.js<\/span>\r\n\r\n<span class=\"nx\">localStorage<\/span><span class=\"p\">.<\/span><span class=\"nx\">setItem<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">apiKey<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">apiKey<\/span><span class=\"p\">);<\/span>\r\n<span class=\"nx\">localStorage<\/span><span class=\"p\">.<\/span><span class=\"nx\">setItem<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">regionName<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"nx\">regionName<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p><strong>Make an initial call<\/strong><\/p>\n<p>Once user inputs are set up in setUpUser, make an API call to get the region&#8217;s carbon intensity<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/index.js<\/span>\r\n\r\n<span class=\"nx\">displayCarbonUsage<\/span><span class=\"p\">(<\/span><span class=\"nx\">apiKey<\/span><span class=\"p\">,<\/span> <span class=\"nx\">regionName<\/span><span class=\"p\">);<\/span>\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p><strong>Display usage and carbon source<\/strong><\/p>\n<p>Make the API call to get your region&#8217;s usage, and display it<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/index.js<\/span>\r\n\r\n<span class=\"nx\">usage<\/span><span class=\"p\">.<\/span><span class=\"nx\">textContent<\/span> <span class=\"o\">=<\/span>\r\n        <span class=\"nb\">Math<\/span><span class=\"p\">.<\/span><span class=\"nx\">round<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">carbonIntensity<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"dl\">'<\/span><span class=\"s1\"> grams (grams C02 emitted per kilowatt hour)<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\r\n\r\n<span class=\"nx\">fossilfuel<\/span><span class=\"p\">.<\/span><span class=\"nx\">textContent<\/span> <span class=\"o\">=<\/span>\r\n            <span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">fossilFuelPercentage<\/span><span class=\"p\">.<\/span><span class=\"nx\">toFixed<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">% (percentage of fossil fuels used to generate electricity)<\/span><span class=\"dl\">'<\/span><span class=\"p\">;<\/span>\r\n\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p><strong>Set icon to be a green color<\/strong><\/p>\n<p>Set the icon to a default; it will change when the API is called. This function uses the chrome runtime&#8217;s built-in management methods<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/index.js<\/span>\r\n\r\n<span class=\"nx\">chrome<\/span><span class=\"p\">.<\/span><span class=\"nx\">runtime<\/span><span class=\"p\">.<\/span><span class=\"nx\">sendMessage<\/span><span class=\"p\">({<\/span>\r\n  <span class=\"na\">action<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">updateIcon<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\r\n    <span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span>\r\n    <span class=\"na\">color<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">green<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span>\r\n    <span class=\"p\">},<\/span>\r\n<span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p><strong>Calculate icon color based on carbon intensity<\/strong><\/p>\n<p>Calculate the appropriate color of the icon, which changes based on an active API call<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/index.js<\/span>\r\n\r\n<span class=\"kd\">let<\/span> <span class=\"nx\">CO2<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">Math<\/span><span class=\"p\">.<\/span><span class=\"nx\">floor<\/span><span class=\"p\">(<\/span><span class=\"nx\">response<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">data<\/span><span class=\"p\">.<\/span><span class=\"nx\">carbonIntensity<\/span><span class=\"p\">);<\/span>\r\n\r\n<span class=\"nx\">calculateColor<\/span><span class=\"p\">(<\/span><span class=\"nx\">CO2<\/span><span class=\"p\">);<\/span>                \r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p><strong>Send message to update icon<\/strong><\/p>\n<p>In calculateColor(), update the icon, again calling the chrome.runtime to invoke a background process<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ src\/index.js<\/span>\r\n\r\n<span class=\"nx\">chrome<\/span><span class=\"p\">.<\/span><span class=\"nx\">runtime<\/span><span class=\"p\">.<\/span><span class=\"nx\">sendMessage<\/span><span class=\"p\">({<\/span> <span class=\"na\">action<\/span><span class=\"p\">:<\/span> <span class=\"dl\">'<\/span><span class=\"s1\">updateIcon<\/span><span class=\"dl\">'<\/span><span class=\"p\">,<\/span> <span class=\"na\">value<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span> <span class=\"na\">color<\/span><span class=\"p\">:<\/span> <span class=\"nx\">closestColor<\/span> <span class=\"p\">}<\/span> <span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p><strong>Update icon itself<\/strong><\/p>\n<p>Build your extension so that you refresh your\u00a0<code>dist<\/code>\u00a0folder (<code>npm run build<\/code>) in your app&#8217;s root. In the listener for &#8216;updateIcon&#8217;, create a browser action to redraw the icon using the Canvas HTML API<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ dist\/background.js<\/span>\r\n\r\n<span class=\"nx\">chrome<\/span><span class=\"p\">.<\/span><span class=\"nx\">browserAction<\/span><span class=\"p\">.<\/span><span class=\"nx\">setIcon<\/span><span class=\"p\">({<\/span> <span class=\"na\">imageData<\/span><span class=\"p\">:<\/span><span class=\"nx\">drawIcon<\/span><span class=\"p\">(<\/span><span class=\"nx\">msg<\/span><span class=\"p\">.<\/span><span class=\"nx\">value<\/span><span class=\"p\">)<\/span> <span class=\"p\">});<\/span>\r\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\"><\/div>\n<\/div>\n<\/div>\n<p>Do one more build, and you&#8217;re ready to install!<\/p>\n<h2><a class=\"anchor\" href=\"https:\/\/dev.to\/azure\/build-a-green-browser-extension-5c49-temp-slug-4374282?preview=bcb084154eea92d14e05c5417d4d3e3f74f7c84cb303c562c07fd00fa61496540796290f745781cebc4bed4a46aaa0b91f916fa1b157dce284c87656#install-the-extension-in-your-browser\" name=\"install-the-extension-in-your-browser\"><\/a>Install the Extension in your Browser<\/h2>\n<p>Install the extension in your browser from the code built in the\u00a0<code>dist<\/code>\u00a0folder. This extension has been tested on Edge, Firefox and Chrome. The installation is basically the same for all these browsers, but here&#8217;s how you install a test extension on Edge:<\/p>\n<p>Use the &#8216;three dot&#8217; menu on the top right corner of the browser to find the Extensions panel. From there, select &#8216;Load Unpacked&#8217; to load a new extension. Open the &#8216;dist&#8217; folder at the prompt and the extension will load.<\/p>\n<p><a class=\"article-body-image-wrapper\" href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--kWLM-8WM--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/nff3yx4863hyu2dv0b0i.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--kWLM-8WM--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/nff3yx4863hyu2dv0b0i.png\" alt=\"Install on Edge\" \/><\/a><\/p>\n<p>Input your API key and region in the form and check your region&#8217;s carbon intensity. Congratulations, now you know whether to run an errand or run the dryer!<\/p>\n<p><a class=\"article-body-image-wrapper\" href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--yt9mJ7Dy--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/0ef3rpzpeflrhwcb6lr5.png\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--yt9mJ7Dy--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/0ef3rpzpeflrhwcb6lr5.png\" alt=\"final extension\" \/><\/a><\/p>\n<p>Remember: the greenest web asset is the slimmest one, the one with the least overhead and the one that is only called ad hoc. You just built a slim, green extension!<\/p>\n<blockquote>\n<p style=\"padding-left: 40px;\">GitHub repo:\u00a0<a href=\"https:\/\/github.com\/jlooper\/carbon-trigger-extension\">https:\/\/github.com\/jlooper\/carbon-trigger-extension<\/a>\nLocalized Slides and video:\u00a0<a href=\"https:\/\/github.com\/microsoft\/ignitelearnzone\/blob\/main\/session-resources\/green-tech.md\">https:\/\/github.com\/microsoft\/ignitelearnzone\/blob\/main\/session-resources\/green-tech.md<\/a>\nI gave a talk on this topic at\u00a0<a href=\"https:\/\/www.youtube.com\/watch?v=D-spTjqAswA&amp;ab_channel=MicrosoftDeveloper\">the GreenConf<\/a>\u00a0starting at 2:25:27 (check out the other talks too!).<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Always wanted to build a browser extension but afraid to try? Fear no more, you can build a browser extension that calls an API to give your region&#8217;s carbon usage.<\/p>\n","protected":false},"author":56926,"featured_media":853,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[22],"tags":[132,74,134,135,133,137,136],"class_list":["post-852","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sustainable-software-engineering","tag-browser","tag-carbon-intensity","tag-chrome","tag-edge","tag-extension","tag-firefox","tag-mozilla"],"acf":[],"blog_post_summary":"<p>Always wanted to build a browser extension but afraid to try? Fear no more, you can build a browser extension that calls an API to give your region&#8217;s carbon usage.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/posts\/852","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/users\/56926"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/comments?post=852"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/posts\/852\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/media\/853"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/media?parent=852"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/categories?post=852"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/sustainable-software\/wp-json\/wp\/v2\/tags?post=852"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}