Build a Chrome Extension with a Template | Methexis
Build a Chrome Extension with a Template | Methexis

Build a Chrome Extension with a Template | Methexis

Tags
JavaScript
browsers
browser extensions
Created
Mar 24, 2021 07:48 PM

Template Overview

Methexis is a starter template for creating a Chrome browser extension. Here is what the starter template does:
https://example.com is the website the sample extension targets
 
A  golden <div> is added by inject/autoload/autoload.js and styled by inject/autoload/autoload.css when the site is navigated to
A golden <div> is added by inject/autoload/autoload.js and styled by inject/autoload/autoload.css when the site is navigated to
A popup HTML document is displayed by popup/popup.html, which loads code in popup/popup.js that can modify the page further
A popup HTML document is displayed by popup/popup.html, which loads code in popup/popup.js that can modify the page further
 
The site's heading is changed by inject/action/action.js and inject/action/action.css (injected from popup/popup.js)
The site's heading is changed by inject/action/action.js and inject/action/action.css (injected from popup/popup.js)

Getting Started

Repository

You can follow the guide below or clone the repo and explore on your own:
git clone https://github.com/Mierenga/methexis
 

Project Tree

.
├── img # images extension needs to access
│   └── logo.png
├── inject # modules of css and js files that can be injected into a page
│   ├── action # module injected by popup.js
│   │   ├── action.css
│   │   └── action.js
│   └── autoload # module injected whenever the user's URL matches the target in manifest.json
│       ├── autoload.css
│       └── autoload.js
├── manifest.json # the main registration of the extension; connects everything together
├── popup # page displayed underneath extension icon when clicked in the browser toolbar
│   ├── popup.html
│   └── popup.js
└── rules.js # logic for when to allow interactions with the popup, etc.

5 directories, 9 files
 

Manifest

Add a manifest.json file
  • Grant permissions and specify which scripts will run under different conditions
{
    "name": "Methexis",
    "version": "0.0.01",
    "icons": {
      "128": "img/logo.png"
    },
    "description": "An originally Ancient Greek form of theatre in which the audience participates and improvises.",
    "permissions": [
			"activeTab",  // Grant extension access to whatever is the active tab in a browser window
			"declarativeContent" // Grant extension the ability to declare content that can be injected into pages it can access
		],
    "background": {
      "scripts": [ "rules.js" ], // Run extension's setup rules for on the window (see example below)
      "persistent": false
    },
		"
manifest.json

Logo

Add a logo
Add your logo image to the location referenced in icons sections of manifest.json, e.g., img/logo.png

Page Rules

Add a rules.js file
  • Runs in a background context (apart from the popup context and in-page content context).
  • Adds a rule that allows the ShowPageAction when the current URL host matches example.com
  • ShowPageAction opens the popup page when extension icon is clicked in the Chrome toolbar
  • Popup page file is specified in manifest.json under "page_action": { "default_popup": "popup/popup.html" }
chrome.runtime.onInstalled.addListener(() => {
  chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
    chrome.declarativeContent.onPageChanged.addRules([{
      conditions: [
        // Actions below are allowed when these conditions are met
        new chrome.declarativeContent.PageStateMatcher({
          pageUrl: { hostEquals: 'example.com' },
        }),
      ],
      actions: [
        // Allow the extension icon button in the Chrome toolbar to show
        // popup/popup.html when clicked
        new chrome.declarativeContent.ShowPageAction(),
      ],
    }]);
  });
});
rules.js

Action Popup View

Add a popup/popup.html file
  • Displayed when the user clicks the extension icon in the browser toolbar
  • The code in rules.js controls which web domains the popup activates for
  • Loads the script at popup/popup.js
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        width: 100%;
        height: 100%;
        margin: 10px;
        background: black;
        color: white;
      }
    </style>
    <!-- script paths are relative to this (popup.html) file -->
    <script src="popup.js"></script>
  </head>
  <body>
    Hello, World!
  </body>
</html>
popup/popup.html
notion image
 

Action Popup Script

Add a popup/popup.js file
  • Immediately injects a JavaScript and CSS file into the current tab that will be given access to the document of the web page.
  • Other scripts and libraries can be injected here or when a user interacts with the popup/index.html page to trigger additional actions
/**
 * Open the active tab in the current Chrome window (using the permission established in the manifest.json)
 * and inject a list of .css and .js files asynchronously, resolving when all files are injected (order unknown)
 * @param {{ js: string[], css: string[] }} files
 * @return Promise
 */
async function injectFiles(files) {
  const [ tab ] = await new Promise(resolve => chrome.tabs.query({active: true, currentWindow: true}, resolve));
  files.css && await Promise.all(files.css.map(file => new Promise(resolve => chrome.tabs.insertCSS(tab.id, { file: file }, resolve))));
  files.js && await Promise.all(files.js.map(file => new Promise(resolve => chrome.tabs.executeScript(tab.id, {file: file }, resolve))));
}

(async () => {
  // Load any dependencies first
  await injectFiles({
    js: [
      // Add any scripts/libraries you want to inject into the extension environment (to be called from the main injected script).
      // Inside these scripts, you can store items for later using by setting them as a property somewhere on the window object,
      // as is common with many front-end JavaScript libraries.
    ],
    css: [
      // Add stylesheets that will be applied to the shared DOM for current and future elements
      'inject/action/action.css',
    ],
  });
  // Run your injection action scripts' main entry point
  await injectFiles({
    js: [ 'inject/action/action.js' ],
  });
})();
popup/popup.js

Injected Autoload Script

Add an inject/autoload/autoload.js file
  • Registered in manifest.json to be injected whenever the user's URL changes to *://example.com/*
// You can access and modify the document of the page you are extending
(() => {
  const hostDiv = document.getElementsByTagName('div')[0]
  const extensionDiv = document.createElement('div');
  extensionDiv.id = 'extension-container';
  extensionDiv.innerText = 'This box was added by a browser extension automatically when you visited this site.'
  hostDiv.appendChild(extensionDiv);
})();
 
notion image

Injected Autoload Styles

Add an inject/autoload/autoload.css file
  • Registered in manifest.json to be injected whenever the user's URL changes to *://example.com/*
#extension-container {
  background: rgb(255, 208, 0);
  border: 2px solid black;
  border-radius: 4px;
}
inject/autoload/autoload.css

Injected Action Script

Add an inject/action/action.js file
  • Injected by popup/popup.js whenever the user click's the extension icon in the browser toolbar (and there's a matching PageStateMatcher condition in rules.js)
// You can access and modify the document of the page you are extending
(() => {
  const heading = document.getElementsByTagName('h1')[0];
  heading.innerText = 'This Heading Was Changed By A Browser Extension When You Clicked It\'s Icon';
})();
inject/action/action.js
 
notion image

Injected Action Styles

Add an inject/action/action.css file
  • Injected by popup/popup.js whenever the user click's the extension icon in the browser toolbar (and there's a matching PageStateMatcher condition in rules.js)
h1 {
  color: rgb(206, 18, 90);
}
inject/action/action.css
 
 
 
 

methexis •  Noun • An originally Ancient Greek form of theatre in which the audience participates and improvises. • The relation between a particular and a Platonic form.