Using the Chrome plug-in can bring some functional extensions to The Chrome browser, thus improving the user experience. As the saying goes, Chrome has no plug-ins, less than half the flavor, Chrome’s biggest advantage is that it supports many powerful and easy to use extensions; Today we will take a look at how plug-ins are developed, how they differ from our normal browser page development, and some of amway’s powerful plug-ins.

Introduction to Chrome Plug-in

The Chrome plugin, officially called Extensions; For ease of understanding, these are all called Chrome plug-ins, or plug-ins for short, so what is a Chrome plug-in?

Extenders are small software programs that customize the browsing experience. They allow users to customize Chrome’s functionality and behavior in a variety of ways.

The plug-in provides the following functions:

  • Productivity tools:
  • Rich content
  • Information aggregation
  • Fun and games

We can view all of our installed plug-ins by going to more Tools -> Extensions, or simply open the Plug-ins TAB.

So what’s the point of learning to develop plug-ins? Why do we want to learn plug-in development? Personal summary, there are the following aspects of significance:

  • Enhance browser functions, to achieve their own custom plug-in functions
  • Learn about existing plug-ins and improve their functionality

To get the plugin

Most Chrome users get the plugin from the Chrome Web app store. Developers around the world publish their plug-ins in the Chrome Web App Store, which are vetted by Chrome and made available to end users.

But due to some reasons known to all, we cannot access the online application store, but at the same time the Chrome requires plug-in must from the Chrome app store download and install, this seems to be a round of infinite loop, but as the saying goes, virtue dwarfs vice while the priest climbs a post, the devil climbs a, below we will explain how to from a local loading plug-ins, bypassing the limitation of online application store.

How does the plug-in work?

Plug-ins are built based on Web technologies such as HTML, JavaScript, and CSS. They run in a separate sandbox execution environment and interact with Chrome.

Plug-ins allow us to extend and enhance the capabilities of our browsers by using apis to modify browser behavior and access Web content. Plug-ins operate through the end user UI and developer apis:

  • Extension user interface, which provides users with a consistent way to manage their extensions.
  • The extended API allows the browser’s own extended code access functions: activating tags, modifying network requests, and so on.

To create a plug-in, we need to combine a list of resources that make up the plug-in, such as JS files and HTML files, images, and so on. For development and testing, you can load these “unzips” into Chrome using extended developer mode. If we are happy with our plug-in, we can package it and share it with other users through an online store.

Principles of plug-ins

If we want to publish a plugin to the Chrome Web Store, we must comply with the Web Store policy, which states the following:

  • Plug-ins must serve a single purpose that is narrowly defined and easily understood. A single plug-in can contain multiple components and a range of capabilities, as long as everything contributes to a common purpose.
  • The user interface should be minimal and intentional. They can range from simple ICONS to opening a new window with a form.

A simple widget

Chrome plug-ins do not have strict project structure requirements, such as SRC, public, components, etc., so if we look at the source code of many plug-ins, we will find that each plug-in project structure, and even the name of the file under the project is very different. However, in the root directory we will find a manifest.json file, which is the configuration file of the plug-in and explains various information about the plug-in. It is equivalent to app.json for applets and package.json for front-end projects.

We create the simplest manifest.json configuration file in our project:

{
    // Plug-in name
    "name": "Hello Extensions".// The description of the plug-in
    "description" : "Base Level Extension".// Version of the plug-in
    "version": "1.0".// Configure the version number of the plug-in, the mainstream version is 2, the latest is 3
    "manifest_version": 2
}
Copy the code

When we click the plug-in icon in the upper right corner, a small window will pop up on the page, which will close when the focus is off. We usually do some temporary interactive operations. Add browser_action field to the configuration file and configure popup:

{
    "name": "Hello Extensions"."description" : "Base Level Extension"."version": "1.0"."manifest_version": 2.// Add popup
    "browser_action": {
      "default_popup": "popup.html"."default_icon": "popup.png"}}Copy the code

Then create our popup page popup.html:

<html>
  <body>
    <h1>Hello Extensions</h1>
  </body>
</html>
Copy the code

After clicking the icon, the plug-in displays popup.html.

Json to popup the popup page with a keyboard shortcut:

{
  "name": "Hello Extensions"."description" : "Base Level Extension"."version": "1.0"."manifest_version": 2."browser_action": {
    "default_popup": "popup.html"."default_icon": "popup.png"
  },
  // Add a command
  "commands": {
    "_execute_browser_action": {
      "suggested_key": {
        "default": "Ctrl+Shift+F"."mac": "MacCtrl+Shift+F"
      },
      "description": "Opens popup.html"}}}Copy the code

This way our plugin can be ejected by pressing Ctrl+Shift+F on the keyboard.

Load and debug plug-ins

The plug-in we developed needs to run in the browser, open the plug-in TAB, open the developer mode, click load decompressed extension, select the project folder, you can load the plug-in under development in.

If the code is changed during development, click the refresh button in the lower right corner of the plug-in to reload

If there is an error in our code, a red error button will appear when the plug-in is loaded:

Click the error button to view the error log:

As mentioned above, the Chrome plugin can only be downloaded from the online app store, but there are also third-party platforms that can download the CRX file. The problem is how to install the CRX file.

Starting with Chrome 73, Google has changed its plugin policy to prevent CRX files from being installed: If you drag and drop CRX files to install, you may receive an error:

Package invalid: "CRX_HEADER_INVALID"Copy the code

We can try the following methods. First, change the CRX suffix to zip, unzip and load the unzipped extension, and load the plug-in in developer mode.

The second option is to extract CRX to the desktop through the Chrome plugin companion, and then load it again in developer mode.

After extracting a plugin with plugin Companion, the plugin content is placed on your desktop by default and can be cut/copied anywhere. When loading the folder path chosen by the plug-in, be sure to include the manifest.json file; Do not delete the extracted folder after loading.

The third way is to use a ladder, directly go to the online app store to download, students who do not have a ladder can use plug-in partner for agent, plug-in partner to obtain the way will be given below.

The background background

After our plug-in is installed, the PopUp page also runs; However, we also found that popUp pages can only be used for temporary interaction, closed after use, can not store information or interact with other tabs, etc. This is where background comes in, which is a resident page that has the longest life cycle of any page type in the plug-in; It opens as the browser opens and closes as the browser closes, so you usually put global code that needs to run all the time, run on startup, in background.

Background can also be configured in manifest.json. You can specify a page as a webpage, or you can specify a JS array as scripts. Chrome automatically generates a default webpage for JS:

{
  "background": {
    // "page": "background.html",
    "scripts": ["background.js"]."persistent": true}}Copy the code

Note that only one page attribute and one scripts attribute needs to be configured. If the page attribute and one scripts attribute are configured simultaneously, the following error message is displayed:

Only one of 'background.page', 'background.scripts', and 'background.service_worker' can be specified.
Copy the code

We set a listening event for background to print a log when the plugin is installed:

// background.js
chrome.runtime.onInstalled.addListener(function () {
  console.log("Plug-in installed");
});
Copy the code

Click on the background page next to View to see the background we set:

Storage store

We set a value in storage at plug-in installation time, which will allow multiple plug-in components to access the value and update it:

//background.js
chrome.runtime.onInstalled.addListener(function () {
  // Set the value in storage
  chrome.storage.sync.set({ color: "#3aa757" }, function () {
    console.log("storage init color value");
  });
  // Display ICONS for specific urls
  chrome.declarativeContent.onPageChanged.removeRules(undefined.function () {
    chrome.declarativeContent.onPageChanged.addRules([
      {
        conditions: [
          new chrome.declarativeContent.PageStateMatcher({
            pageUrl: { hostEquals: "baidu.com"}}),].actions: [new chrome.declarativeContent.ShowPageAction()],
      },
    ]);
  });
});
Copy the code

Chrome. DeclarativeContent used for precise control of when to display our page button, or the appearance of the need to change it before the user clicks it to match the current TAB.

Chrome. storage is not the same thing as localStorage and sessionStorage; Since the STORAGE and declarativeContent apis are called, we need to register the permissions used by the plug-in in the manifest:

{
  / / new
  "permissions": ["storage"."declarativeContent"]."background": {
    "scripts": ["background.js"]."persistent": true}}Copy the code

Looking again at the view of the background page, we can see the printed log; Since we can store it, we can also retrieve it. We add an event to popUp to retrieve it. First we add a button that triggers it:

<! -- popup.html -->
<html>
  <head>
    <style>
      button {
        width: 60px;
        height: 30px;
        outline: none;
      }
    </style>
  </head>
  <body>
    <button id="changeColor">change</button>
    <script src="popup.js"></script>
  </body>
</html>
Copy the code

Create a popup.js file to retrieve the color value from the storage and use the color as the background color of the button: popup.js

let changeColor = document.getElementById("changeColor");

changeColor.onclick = function (el) {
  chrome.storage.sync.get("color".function (data) {
    changeColor.style.backgroundColor = data.color;
  });
};
Copy the code

To debug the POPUp page, right-click => Check in the pop-up box and view the popup page in DevTools.

We opened the PopUp page several times and found that the page returned to its original default state each time we clicked the button.

Get browser Tabs

Now that we have the values in the storage, we need logic to further interact with the user; Update the interactive code in popup.js:

// popupjs
changeColor.onclick = function (el) {
  chrome.storage.sync.get("color".function (data) {
    let { color } = data;
    chrome.tabs.query({ active: true.currentWindow: true }, function (tabs) {
      chrome.tabs.executeScript(tabs[0].id, {
        code: 'document.body.style.backgroundColor = "' + color + '"; '}); }); }); };Copy the code

The Chrome. Tabs API primarily interacts with the browser’s TAB pages, finding the currently active TAB using Query, and injecting script content into the TAB using executeScript.

Manifest also requires activeTab permissions to allow our plug-in to use the Tabs API.

{
  "name": "Hello Extensions".// ...
  "permissions": ["storage"."declarativeContent"."activeTab"],}Copy the code

Reloading the plugin, we click the button, will find the current page background color has changed to the color value set in storage; However, some users may want to use a different color value, and we offer users the opportunity to choose.

Color options page

Now our plug-in function is relatively simple, only let the user choose a unique color; We can add an option page in the plug-in, so that users can better customize the functions of the plug-in.

Add an options. HTML file to the program directory:

<! DOCTYPEhtml>
<html>
  <head>
    <style>
      button {
        height: 30px;
        width: 30px;
        outline: none;
        margin: 10px;
      }
    </style>
  </head>
  <body>
    <div id="buttonDiv"></div>
    <div>
      <p>Choose a different color</p>
    </div>
  </body>
  <script src="options.js"></script>
</html>
Copy the code

Then add the logical code options.js for the selection page:

let page = document.getElementById("buttonDiv");
const kButtonColors = ["#3aa757"."#e8453c"."#f9bb2d"."#4688f1"];
function constructOptions(kButtonColors) {
  for (let item of kButtonColors) {
    let button = document.createElement("button");
    button.style.backgroundColor = item;
    button.addEventListener("click".function () {
      chrome.storage.sync.set({ color: item }, function () {
        console.log("color is " + item);
      });
    });
    page.appendChild(button);
  }
}
constructOptions(kButtonColors);
Copy the code

The code above presets four color options and generates buttons on the page by listening on the onclick event. When the user clicks the button, the color value stored in the storage is updated.

Once the options page is complete, we can register it in the manifest options_page:

{
  "name": "Hello Extensions"./ /...
  "options_page": "options.html"./ /...
  "manifest_version": 2
}
Copy the code

Reload our plug-in, click details, scroll to the bottom, and click Extension Options to see the options page.

Or you can right-click on the plug-in icon in the upper right corner of your browser.

Advanced plug-in functions

Through a simple small plug-in above, I believe that we have a general understanding of the functions and components of the plug-in, know the role of each component in which to play; But this is only a small part of the plug-in’s capabilities. Let’s take a closer look at the capabilities and components of each part of the plug-in.

Manage events using background

Background is the plug-in’s event handler and contains listeners for browser events that are important to the plug-in. Background lies dormant until an event is emitted, and then the indicated logic is executed; A good background is loaded only when needed and unloaded at idle.

Some browser events that background listens for include:

  • The plug-in is first installed or updated to a new version.
  • The background page is listening for an event and has scheduled the event
  • Content scripts or other plug-ins send messages
  • Another view of plug-in (for example, the pop-up window) to invoke the runtime. GetBackgroundPage

After loading, the background stays running as long as an event is triggered; In the manifest above, we also specify a persistent attribute:

{
  "background": {
    "scripts": ["background.js"]."persistent": true}}Copy the code

The Persistent attribute defines how plug-ins reside in the background; When the value is true, the plug-in will always be running in the background, whether it is working or not. When the value is false, the plugin runs in the background on demand, which is what Chrome later called the Event Page (non-persistent background). The Event Page is event-driven and can only be accessed when an Event occurs; The purpose of this is to reduce the memory consumption of plug-ins. If not necessary, set Persistent to false.

The default value for the persistent attribute is true

alarms

Some DOM-based page-based timers (such as window.setTimeout or window.setInterval) may not run at a predetermined time if triggered during non-persistent background sleep:

let timeout = 1000 * 60 * 3;  // 3 minutes in milliseconds
window.setTimeout(function() {
  alert('Hello, world! ');
}, timeout);
Copy the code

Chrome provides additional APIS, Alarms:

chrome.alarms.create({delayInMinutes: 3.0})

chrome.alarms.onAlarm.addListener(function() {
  alert("Hello, world!")});Copy the code

browserAction

We know that browser_action is used to configure popup pages, and page_action is provided in other documents, but page_action is not available on all pages; But with Chrome’s recent releases, the two functions have become more similar; After Chrome 48, page_Action has also been removed from the address bar and placed alongside plug-ins. I don’t see any major differences in page_action configuration, so I’ll focus on browser_action.

In browserAction configuration, we can provide multiple sizes of ICONS, Chrome will select the closest icon and scale it to the appropriate size to fill; If the exact size is not provided, this scaling can cause the icon to lose detail or look blurry.

{
  // ...
  "browser_action": {
    "default_icon": {                // optional
      "16": "images/icon16.png".// optional
      "24": "images/icon24.png".// optional
      "32": "images/icon32.png"      // optional
    },
    "default_title": "hello popup".// optional
    "default_popup": "popup.html"    // optional}},Copy the code

You can also dynamically set up pop-ups by calling BrowserAction.setPopup.

chrome.browserAction.setPopup({popup: 'popup_new.html'});
Copy the code

Tooltip

To set up the prompt copy, use the default_title field, or call the browserAction.setTitle function.

chrome.browserAction.setTitle({ title: "New Tooltip" });
Copy the code

Badge

Badge (Badge) is some text content displayed on the icon, used to display the prompt information of the plug-in in detail; Due to the limited space of Bage, 4 English characters or 2 functions can be displayed at most; Badge fail to specify the configuration file, must through code realization, set the badge text and color can be used separately browserAction setBadgeText () and browserAction setBadgeBackgroundColor () :

chrome.browserAction.setBadgeText({ text: "new" });
chrome.browserAction.setBadgeBackgroundColor({ color: [255.0.0.255]});// or Color string
// chrome.action.setBadgeBackgroundColor({color: '#4688F1'});
Copy the code

content-scripts

Content-scripts are files that run in the context of a web page. Using the standard Document Object Model (DOM), it can read the details of the web page visited by the browser, make changes to it, and pass the information to its parent plug-in. Content scripts have some API access restrictions compared to background. They can directly access the following Chrome apis:

  • i18n
  • storage
  • runtime:
    • connect
    • getManifest
    • getURL
    • id
    • onConnect
    • onMessage
    • sendMessage

Content scripts run in a separate, isolated environment and do not conflict with the content scripts of the main page or other plug-ins, nor can they call their context or variables. Suppose we define variables and functions on the main page:

<html lang="en">
  <head>
    <title>Document</title>
  </head>
  <body>
    <script>
      const a = { a: 1.b: "2" };
      const b = { a: 1.b: "2".c: []};function add(a, b){ return a + b };
    </script>
  </body>
</html>
Copy the code

Uncaught ReferenceError: Add is not defined.

Content scripts can be injected either programmatically or declaratively.

Code injection

For code that needs to run under certain conditions, we need to use code injection; In the popup page above, we inject the content script into the page as code:

chrome.tabs.executeScript(tabs[0].id, {
  code: 'document.body.style.backgroundColor = "red"; '});Copy the code

Or you can inject the entire file.

chrome.tabs.executeScript(tabs[0].id, {
  file: "contentScript.js"});Copy the code

Declarative injection

A content script that runs automatically on a given page, using declarative injection; Declaratively injected scripts are registered under the content_scripts property of the manifest file. They can include JS files or CSS files.

{
  "content_scripts": [{/ / necessary. Specifies which pages this content script will be injected into.
      "matches": ["https://*.xieyufei.com/*"]."css": ["myStyles.css"]."js": ["contentScript.js"]]}}Copy the code

In addition to matches, declarative injection can contain the following fields to customize a specified page match:

Name Type Description
exclude_matches String array Optional. Exclude pages where this content script will be injected.
include_globs String array Optional. Apply after matches to match the URL that matches this glob. Designed to emulate the @exclude oilmonkey keyword.
exclude_globs String array Optional. Apply after matches to exclude urls that match this glob. Designed to emulate the @exclude oilmonkey keyword.

Matching urls can be declared using the Glob attribute, which follows a more flexible syntax. Acceptable Glob strings may contain urls with “wildcard” asterisks and question marks. The asterisk * matches strings of any length, including empty strings, while the question mark? Matches any single character.

{
  "content_scripts": [{"matches": ["https://*.xieyufei.com/*"]."exclude_matches": ["*://*/*business*"]."include_globs": ["*xieyufei.com/???s/*"]."exclude_globs": ["*science*"]."js": ["contentScript.js"]]}}Copy the code

When injecting JS files into web pages, you also need to control the timing of file injection, controlled by the RUN_at field; The preferred default field is document_IDLE, but it can also be specified as “document_start” or “document_end” if desired.

{
  "content_scripts": [{"matches": ["https://*.xieyufei.com/*"]."run_at": "document_idle"."js": ["contentScript.js"]]}}Copy the code

The differences in the injection timing of the three fields are as follows:

Name Type Description
document_idle string First choice. Document_idle is used whenever possible. The browser chooses a time to inject the script immediately after the “document_end” and window.onload events are triggered. The exact timing of injection depends on the complexity of the document and how long it takes to load, and has been optimized for page loading speed. Content scripts running on “document_IDLE” do not need to listen for window.onload events, so you can ensure that they run after the DOM is complete. If you do need to run the script after window.onload, the extension can use the document.readyState property to check if onload has fired.
document_start string Injected after the CSS file, but before constructing additional DOM or running additional scripts.
document_end string Inject scripts immediately after DOM creation, but before loading child resources such as images and Frames.

Message communication

Although the execution environment of content scripts and the page hosting them are isolated, they share access to the page DOM; If the content script wants to communicate with the plug-in, onMessage and sendMessage can be used

// contentScript.js
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
  console.log("Content-script received message", message);
  sendResponse("I got your message!");
});

chrome.runtime.sendMessage(
  { greeting: "I'm Content-script, I'm sending messages to the background!" },
  function (response) {
    console.log("Received a reply from the background:"+ response); });Copy the code

More information on message communication will be summarized in detail later.

contextMenus

ContextMenus can customize the browser’s right menu (also called the context menu), through chrome. ContextMenusAPI implementation; Add permissions to manifest to enable menu permissions:

{
  // ...
  "permissions": ["contextMenus"]."icons": {
    "16": "contextMenus16.png"."48": "contextMenus48.png"."128": "contextMenus128.png"}}Copy the code

Configure the ICONS next to the contextMenus menu from the ICONS field:

To create a menu, call contextmenus.create from background. This should be done in Runtime. onInstalled to listen for the callback to execute:

chrome.contextMenus.create({
  id: "1".title: "Test Context Menu".contexts: ["all"]});/ / line
chrome.contextMenus.create({
  type: "separator"});// Parent menu
chrome.contextMenus.create({
  id: "2".title: "Parent Context Menu".contexts: ["all"]}); chrome.contextMenus.create({id: "21".parentId: "2".title: "Child Context Menu1".contexts: ["all"]});// ...
Copy the code

If our plugin creates multiple right-click menus, Chrome will automatically fold them into a parent menu.

The properties of the object created by the contextMenus can be found in the appendix. We can see that there is an identifier for %s in the title property. If Contexts is Selection, use %s to represent the selected text; Through this function, we can achieve a small function to call Baidu search by selecting the text:

chrome.contextMenus.create({
  id: "1".title: "Use Baidu search: %s".contexts: ["selection"].onclick: function (params) {
    chrome.tabs.create({
      url:
        "https://www.baidu.com/s?ie=utf-8&wd=" +
        encodeURI(params.selectionText), }); }});Copy the code

The effect is as follows:

ContextMenus also have a few apis to call:

// Delete a menu itemChrome. ContextMenus. Remove (menuItemId);// Delete all custom right-click menus
chrome.contextMenus.removeAll();
// Update a menu item
chrome.contextMenus.update(menuItemId, updateProperties);
// Listen for menu item click events
chrome.contextMenus.onClicked.addListener(function(OnClickData info, tabs.Tab tab) {... });Copy the code

override

Override is a way to replace a particular Chrome page by default with an HTML file in a plug-in. In addition to HTML, covering pages usually has CSS and JS code; The plugin can replace the following Chrome pages.

  • Bookmark Manager
    • The page that appears when the user selects the Bookmarks Manager menu item from the Chrome menu or from the Bookmarks Menu on the Mac. You can also access this page by entering the URL chrome://bookmarks.
  • The historical record
    • The page that appears when the user selects a History menu item from the Chrome menu or shows a full history item from the History menu on the Mac. You can also access this page by entering the URL chrome://history.
  • The new label
    • The page that appears when the user creates a new TAB or window. You can also access this page by entering the URL chrome://newtab.

PS: The Momentum plugin, as we know, overwrites the new TAB page.

It is important to note that a single plug-in can only cover one page. For example, the plug-in cannot overwrite both the bookmark manager and the history page.

Perform the following configuration in the manifest:

{
  "chrome_url_overrides": {
    "newtab": "newtab.html".// "history": "history.html",
    // "bookmarks": "bookmarks.html"}}Copy the code

Overwriting newTab looks like this:

If we overwrite more than one particular page, Chrome will directly report an error when loading the plugin:

storage

When users operate, some user data will be generated. The plug-in needs to store this data locally and then take it out when it needs to be called. For Chrome, you are advised to use the Chrome. Storage API, which is optimized to provide the same storage functions as localStorage. It is not recommended to save it directly in localStorage. The differences between the two are as follows:

  • User data can be automatically synchronized with Chrome’s sync function using Chrome. storage.
  • The content script of the plug-in can access user data directly, without background.
  • Chrome. storage can store objects directly, while localStorage is to store strings, which need to be converted again

To use automatic synchronization for storage, we can use storage.sync:

chrome.storage.sync.set({key: value}, function() {
  console.log('Value is set to ' + value);
});

chrome.storage.sync.get(['key'].function(result) {
  console.log('Value currently is ' + result.key);
});
Copy the code

When Chrome is offline, Chrome stores the data locally. Chrome syncs data the next time the browser is online. Storage.sync will work even if the user disables synchronization.

Data that does not need to be synchronized can be stored using storage.local:

chrome.storage.local.set({key: value}, function() {
  console.log('Value is set to ' + value);
});

chrome.storage.local.get(['key'].function(result) {
  console.log('Value currently is ' + result.key);
});
Copy the code

If we want to listen for data changes in storage, we can use onChanged to add a listening event. This event is emitted whenever the data in the store changes:

// background.js

chrome.storage.onChanged.addListener(function (changes, namespace) {
  for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
    console.log(
      `Storage key "${key}" in namespace "${namespace}" changed.`.`Old value was "${oldValue}", new value is "${newValue}". `); }});Copy the code

devtools

Anyone who has used DevTools in Vue or React should have seen this new extension panel:

DevTools adds features to Chrome’s DevTools, which can add new UI panels and sidebars, interact with checked pages, get information about web requests, and more; It has access to the following specific apis:

  • devtools.inspectedWindow
  • devtools.network
  • devtools.panels

The DevTools extension is structured like any other extension: it can have a background page, content scripts, and other items. In addition, each DevTools extension has a DevTools page with access to the DevTools API.

You don’t need permissions to configure devTools, just configure a devtools.html in the manifest:

{
  "devtools_page": "devtools.html",}Copy the code

Devtools.html only refers to devtools.js, and if anything else is written it will not be shown:

<! DOCTYPEhtml>
<html lang="en">
  <head> </head>
  <body>
    <script type="text/javascript" src="./devtools.js"></script>
  </body>
</html>
Copy the code

Create devTools.js in your project:

// devtools.js
// Create the extension panel
chrome.devtools.panels.create(
  // The extension panel displays the name
  "DevPanel".// Expand panel icon, not displayed
  "panel.png".// Expand panel page
  "Panel.html".function (panel) {
    console.log("Custom panel created successfully!"); });// Create a custom sidebar
chrome.devtools.panels.elements.createSidebarPane(
  "Sidebar".function (sidebar) {
    sidebar.setPage("sidebar.html"); });Copy the code

Create is called to create the extension panel and createSidebarPane to create the sidebar, each of which is a separate HTML page that can contain other resources (JavaScript, CSS, images, and so on).

DevPanel

The DevPanel is a top-level TAB, at the same level as Element, Source, Network, etc., and can be created in a single devTools.js. In panel.html we set up two buttons:

<! DOCTYPEhtml>
<html lang="en">
  <head></head>
  <body>
    <div>dev panel</div>
    <button id="check_jquery">Check the jquery</button>
    <button id="get_all_resources">Get all resources</button>
    <script src="panel.js"></script>
  </body>
</html>
Copy the code

In panel.js we use the devtools.inspectedWindow API to interact with the inspectedWindow:

document.getElementById("check_jquery").addEventListener("click".function () {
  chrome.devtools.inspectedWindow.eval(
    "jQuery.fn.jquery".function (result, isException) {
      if (isException) {
        console.log("the page is not using jQuery");
      } else {
        console.log("The page is using jQuery v"+ result); }}); });document
  .getElementById("get_all_resources")
  .addEventListener("click".function () {
    chrome.devtools.inspectedWindow.getResources(function (resources) {
      console.log(resources);
    });
  });
Copy the code

The eval function provides the plug-in with the ability to execute JS code in the context of the page being examined, while getResources gets all loaded resources on the page; We found a page, and right click check to open the debug tool, found a DevPanel TAB on the far right, click our debug button, so where can we see the log?

We right click on the debug tool to check, and then open a debug tool, this is the debug tool of the debug tool…

The final result of the two debugging tools is as follows:

Sidebar

Going back to devTools.js, we created the sidebar panel using createSidebarPane and set it to sidebar. HTML, which ended up on the far right side of the Element panel:

There are several ways to display content in the sidebar:

  • HTML content. Call setPage to specify the HTML page to display in the pane.
  • The JSON data. Pass the JSON object to setObject.
  • JavaScript expressions. Pass the expression to setExpression

Using javascript expressions, we can easily query the page, for example, query all img elements on the page:

chrome.devtools.panels.elements.createSidebarPane(
  "All Images".function (sidebar) {
    sidebar.setExpression('document.querySelectorAll("img")'."All Images"); });Copy the code

In addition, we can through the elements, onSelectionChanged event monitoring, selected the Element panel Element changes, to update the state of the sidebar panel; For example, we can display the style of some elements we care about in real time in the side panel, view:

var page_getProperties = function () {
  if ($0 instanceof HTMLElement) {
    return {
      tag: $0.tagName.toLocaleLowerCase(),
      class: $0.classList,
      width: window.getComputedStyle($0) ["width"].height: window.getComputedStyle($0) ["height"].margin: window.getComputedStyle($0) ["margin"].padding: window.getComputedStyle($0) ["padding"].color: window.getComputedStyle($0) ["color"].fontSize: window.getComputedStyle($0) ["fontSize"]}; }else {
    return{}; }}; chrome.devtools.panels.elements.createSidebarPane("Select Element".function (sidebar) {
    function updateElementProperties() {
      sidebar.setExpression(
        "(" + page_getProperties.toString() + "()"."select element"); } updateElementProperties(); chrome.devtools.panels.elements.onSelectionChanged.addListener( updateElementProperties ); });Copy the code

notifications

Chrome provides Chrome. Notifications apis to push desktop notifications; You also need to register permissions in the manifest now:

{
  "permissions": [
    "notifications"],}Copy the code

Create it in the background call

// background.js
chrome.notifications.create(null, {
  type: "basic".iconUrl: "drink.png".title: "Water little helper.".message: "Anyone who reads this can join me for a glass of water."});Copy the code

The effect is as follows:

In accordance with the Chrome. Notifications API, I created a water assistant, so join me in getting eight glasses of water a day!

Chrome. Notifications supports more attributes in the appendix of this article.

webRequest

Any HTTP request made by the browser can be intercepted, organized, or modified through the webRequest API; Other requests that can be intercepted include scripts, GET requests for styles, and links to images; We also need to configure permissions in the manifest to use the API:

{
  / /...
  "permissions": [
    "webRequest"."webRequestBlocking"."*://*.xieyufei.com/"],}Copy the code

If you want to block all urls, you can use *://*/* (this is not recommended, as there is a lot of data). If you want to block the Web request API, you need to use webRequestBlocking.

For example, we can cancel a blocked request:

chrome.webRequest.onBeforeRequest.addListener(
  function (detail) {
    return {cancel: details.url.indexOf("example.com") != -1};;
  },
  { urls: ["<all_urls>"[]},"blocking"]);Copy the code

Component message communication

Different components often need to communicate with each other to transfer data. Let’s take a look at how they communicate:

Background communicates with POPUp

Communication between the background and the popup is simpler, in the popup, we can through the extension. GetBackgroundPage direct access to the background object, call on the object method can directly:

// popup.js
var bg = chrome.extension.getBackgroundPage();
bg.someMethods()
Copy the code

Extension. GetViews is an empty array of views that can be accessed from background popup via extension.getViews.

//background.js
var views = chrome.extension.getViews({type:'popup'});
if(views.length > 0) {
  // Windows object equivalent to popup
	console.log(views[0].location.href);
}
Copy the code

Background communicates with content scripts

In background and content script communication, we can use simple and direct runtime.sendMessage or tabs. SendMessage to send messages containing JSON data

The message sent from the content script is as follows:

// content-script.js
chrome.runtime.sendMessage(
  { greeting: "Hello, this is Content-script, send a message to the background!" },
  function (response) {
    console.log("Received a reply from the background:"+ response); });Copy the code

When sending messages from the background to the content script, we need to specify a TAB to send to because there are multiple tabs:

// background.js
chrome.tabs.query({ active: true.currentWindow: true }, function (tabs) {
  chrome.tabs.sendMessage(
    tabs[0].id,
    { greeting: "Hello, I'm in the background, sending a message to the Content-script." },
    function (response) {
      console.log(response.farewell); }); });Copy the code

In both background and content scripts, we use runtime.onMessage to listen for the receiving event of the message, except for the sender in the callback function, which identifies the different sender:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
      "from a content script:" + sender.tab.url :
      "from the extension");
    if (request.greeting.indexOf("hello")! = = -1){
      sendResponse({farewell: "goodbye"}); }});Copy the code

Long links

The runtime.sendMessage and tabs. SendMessage are short links, similar to HTTP requests that fail if the receiver is not online. However, in some cases, there is a need for continuous conversation, in which case you need to use long links, similar to websockets, which can be persistent links between communication parties.

Long links use runtime.connect or tabs. Connect to open long-life channels, which can have a name to distinguish between different types of connections.

// content-script.js
// Set the channel name
var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});
Copy the code

Sending messages from background to content scripts is similar, except that you need to specify the TAB page for the connection and change runtime.connect to tabs.

On the receiver side, we need to set up the event listener for onConnect, which is triggered when the sender calls Connect to connect, and the port object that sends and receives messages through the connection:

//background.js
chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});
Copy the code

Recommended utility plug-ins

With so many plugins in mind, let’s take a look at some of the best plugins on the app market that can help us be more productive in our daily development.

Adblock Plus

Adblock Plus is an app that blocks ads and anything else you want to block; Not only does it have some built-in filtering rules that automatically block ads, it can also add its own blocking content.

Select the block element, and the light yellow box is the block

Axure RP Extension for Chrome

Axure RP 插件 logo 图 片 Axure RP 插件 logo 图 片 Axure RP 图 片 This is because the Axure plugin is not installed on Chrome.

FeHelper Front-end assistant

FE assistant is a front-end tools developed by Chinese collections of widgets, plug-in function more comprehensive, including string codec, code compression, beautification, JSON formatting, regular expressions, time conversion tool, qr code generation and decoding, encoding specification test, performance test page, page color, Ajax interface debugging.

Momentum

Momentum is a chrome plugin that automatically changes wallpaper and comes with its own clock, task calendar and to-do list. The official explanation: Replace your Chrome’s default “tabs.” The pictures inside all come from 500PX inside high definition, no ads, no pop-ups, very suitable for notebook use, let install force to a new level. Let me feel the beauty that comes from the details and touches the heart.

Octotree

The experience of viewing source code on Github is terrible, especially when jumping from one directory to another is cumbersome. Octotree is a Chrome plugin that displays Github project code in a tree format, and in the displayed list, you can download specific files instead of downloading the entire project.

OneTab

Chrome works, we have to admit it; But no one is perfect, let alone a browser? Chrome’s memory footprint has long been a headache.

OneTab is a Chrome extension that allows users to free up the memory of Chrome tabs in one click if they have too many tabs open. Instead of closing the browser, OneTab caches all existing tabs. Then use the one-click close all tabs function to pop up a new TAB with only one restore window. In this OneTab TAB, users can choose to restore useful Chrome tabs and abandon other tabs that should be closed.

The OneTab plugin restores the tabs as new tabs, so users can simply click the mouse to retrieve all the useful tabs. OneTab saves users 95% of system memory when they have too many Chrome tabs open. It also allows users to focus more clearly on the Chrome tabs they should be focusing on when the tabs are smaller.

Tampermonkey

Tampermonkey is a free browser extension and the most popular user script manager. While some supported browsers have native user scripting support, Tampermonkey will make it easier to manage your user scripts. It offers features such as easy script installation, automatic update checking, a quick view of script health in tabs, a built-in editor, and the possibility of running scripts that are not compatible with Tampermonkey.

You can make most HTML-based web pages easier to use by installing various scripts in the manager, such as: full speed download of disk files, remove ads, hover display of large images, Flash/HTML5 player conversion, reading mode, etc. It’s a bit like adding plugins to Chrome plugins (here’s another nesting doll).

Web Vitals

Over the years, Google has provided many tools to measure and Report performance: Lighthouse, Chrome DevTools, PageSpeed Insights, Search Console’s Speed Report, and more. While these metrics are difficult to learn and use, the Purpose of the Web Vitals program is to simplify scenarios, reduce learning costs, and help sites focus on the most important metrics

Web Vitals is a Google initiative designed to provide a unified guide to various quality signals, which can capture three key metrics (CLS, FID, LCP) :

By installing the Web Vitals plug-in in your browser, you can easily view these three metrics once the page is loaded.

Allow CORS

Allow CORS: Access-Control-Allow-Origin allows us to easily execute cross-domain requests in the interface response header by activating the plug-in and executing it.

After installing the plug-in, cross-domain response headers will not be added by default. Click the C button in the plug-in pop-up box and the button will turn orange to activate the plug-in.

Window Resizer

Window Resizer is a Chrome extension that can set the browser Window size. Users can quickly adjust the Chrome Window size after installing the Window Resizer plug-in. Users can adjust the Window size to 320×480, 480×800, 1024×768, etc. You can also choose to customize the size of the browser window.

All of the above plug-ins and tools in the public number front one read back to the keyword Chrome plug-in can be obtained.

If you think it’s good, check out my Nuggets page. Please visit Xie xiaofei’s blog for more articles