这个前端的小众市场蕴含着巨大财富

4,116 阅读7分钟

这个前端的小众市场蕴含着巨大财富

Chrome 霸主地位

先看一组数据¹

  • 在全球范围内,谷歌浏览器占据了 65.21% 的市场份额。
  • 2020 年,约有 26.5 亿互联网用户通过 Chrome 作为主要浏览器访问网络。
  • 谷歌浏览器至少有 176,608 个扩展。

具体到chrome插件领域 有大约 50% 的 Chrome 扩展程序的安装量少于 16 次,其中25,540 个(13%)只有一个用户,19,379个(超过 10%)没有用户。 有13个插件的用户量超过1000万,虽然也有一些插件在接近1000万的用户量,但是百万级用户量的插件数量依然不多。在所有插件中近四分之一(24.9%)与生产力有关。 有4.7%的扩展是付费扩展,其中86.4%是一次性付费,插件内支付、月付、年付的比例分别是6.3%,5.7%,1.6%

插件的技术变革

2023年1月后 MV2插件不能再继续更新,MV2插件将不能在Chrome中运行;2023年6月后 即使使用企业策略,MV2扩展程序也不再在 Chrome 中运行。目前已经不能再发布MV2版本的插件,而目前网上的很多文章和资料都是MV2相关的插件教程,相比于MV2,MV3有诸多不同,例如权限控制,API的变动,发起请求的方式等。 插件或多或少大家都用过,但是你有没有想过试着自己做一个浏览器插件,在本篇文章中我将详细讲解chrome插件的现状并手把手教你如何开发一个浏览器插件。 现在正式mv2向mv3过度的时期,机会留给有准备的人,和我一起动手干起来!

可以跳过但是看了能和别人吹的知识

浏览器插件可以理解为运行在浏览器上的app,与手机上的app不同的是它可以控制网页,改变网页结构,修改网页内容,通过安装不同的插件可以帮助用户实现不同的需求。比如屏蔽广告,视频超高倍速快进,查看搜索词SEO竞争激烈度,长截屏任意网页并编辑等等,你想到的想不到的插件几乎都能在插件市场里找到

做一个40万下载量的插件

接下来我会带领大家一边学习插件相关知识一边做一个插件,对标40万下载量的 Темная тема для ВК | Dark theme for VK ² 插件,实现切换掘金dark/light模式的插件。 manifest.json 插件的必备文件:

{
  "name": "Hello, World!",
  "version": "1.0",
  "manifest_version": 3
}

这样我们就定义了一个名为Hello, World!的插件,同时它的版本是1.0。现在把包含manifest.json的文件夹拖进 chrome://extensions/(要先将chrome://extensions/右上角的 开发者模式 打开), ex1.png 这个插件就被加载到浏览器中了 ex2.pngmanifest.json同级新建一个js文件,名字任意,我取名为background1,内容为 console.log('this is background1');,并且修改manifest.json为:

{
  "name": "Hello, World! demo",
  "version": "1.0",
  "manifest_version": 3,
  "background": {
    "service_worker": "background1.js"
  }
}

chrome://extensions/点击插件上的刷新按钮,发现多了一个service worker(Inactive),点击它弹出控制台一样的窗口,点击Console,打印出了 this is background1,代表我们编写的逻辑文件已经加载到了插件里。

所有在background1打印的内容均只能在service worker(Inactive)的Concole里看到。 插件代码的每次改动都需要刷新页面才可以加载新代码,在后续的文章中我们可以借助工具热加载解决

接下来在background1.js里添加

chrome.action.onClicked.addListener(function(){
  console.log('点击了插件图标');
});

注意,此时manifest里还未做任何改动,这时刷新插件,发现有Errors ex3.png 报错是非常好的学习机会,不要错过。点进去看,发现一个警告和一个error,分别是Service worker registration failedUncaught TypeError: Cannot read properties of undefined (reading 'onClicked'),看error更具体一些,说没有onClicked方法,再次打印chrome.action,发现是 undefined,查看chrome.action文档发现,必须在manifest中声明才能使用此api,所以直接在manifest中添加:

{
  ···
  "action": {}
}

清除报错,刷新插件,发现Errors消失,此时发现可以打印出来chrome.action了,并且此时点击插件图标,打印提示点击了插件图标。chrome.action这个API是专门控制插件图标的,除了响应点击事件,还可以切换图标样式,让图标展示不同的状态。

完善chrome.action.onClicked.addListener

新建icons文件夹,将图标导入项目中,将background1.js改为以下代码

let localStorage1 = 'dark'

chrome.action.onClicked.addListener(function () {
  let icon = localStorage1 == 'light' ? 'dark' : 'light';
  localStorage1 = icon
  chrome.action.setIcon({ path: 'icons/popup_' + localStorage1 + '_32.png' });
});

点击图标,发现图标在两种状态下切换,恭喜你,完成了一个40万下载量的插件的50%的代码。

在特定的网页加载插件

接下来完善manifest.json,action和content_scripts

{
  ···
  "action": {
    "default_title": "click me",
    "default_icon": {              
      "16": "icons/popup_dark_16.png",   
      "24": "icons/popup_dark_24.png",   
      "32": "icons/popup_dark_32.png"    
    }
  },
  "content_scripts": [{
    "matches": ["https://*.juejin.cn/*"],
    "js": ["content-script.js"]
  }]
}

编辑content-script.js

alert('匹配了目标页面')

然后打开掘金首页 juejin.cn,可以看到弹出消息,content-script.js,就是运行在目标网页中的逻辑 ex4.jpg 进一步编辑:

console.log('content-script运行了 2');


// alert('匹配了目标页面')

function changeBodyBackgroundColor(color = '#F00'){
  document.querySelector('body').style.backgroundColor = color 
  console.log('设置背景颜色');
}

changeBodyBackgroundColor('#222226')

修改content-script.js为如下所示:

console.log('content-script');

document.querySelector('body').style.backgroundColor = '#22222d';
document.querySelector(".view-nav").style.backgroundColor = '#22222d';
document.querySelector("#juejin header").style.backgroundColor = '#22222d';
document.querySelector("#juejin header.list-header").style.backgroundColor = '#22222d';

function setBeforeBackgroundColor(){
  var style = document.createElement("style");
  document.head.appendChild(style);
  sheet = style.sheet;
  sheet.insertRule('.view-nav::before { background-color: #22222d }', 0);
}

function setColor(elements){
  const doms = [...elements];
  for (const element of doms) {
    element.style.backgroundColor = '#22222d';
  }
  setBeforeBackgroundColor()
}
function callback(mutationList, observer) {
  mutationList.forEach((mutation) => {
    switch(mutation.type) {
      case 'childList':
        const elements = document.querySelectorAll(".entry-list-wrap .entry-list .entry, .entry-list-wrap .entry-list")
        if (elements) {
          setColor(elements);
        }
        break;
    }
  });
}
function observeDom(){
  var targetNode = document.querySelector("#juejin .entry-list-wrap");
  var observerOptions = {
    childList: true,  // 观察目标子节点的变化,是否有添加或者删除
    // attributes: true, // 观察属性变动 这里不需要
    // subtree: true     // 观察后代节点,默认为 false 这里不需要
  }
  var observer = new MutationObserver(callback);
  observer.observe(targetNode, observerOptions);
}
observeDom()

ex6.jpg 可以看到页面变黑了,分几块对上述代码进行讲解:

  1. 可以直接拿到的元素,直接通过 querySelector 找到并修改样式
  2. 由于掘金首页的列表内容是动态渲染的,所以无法直接取到里面的内容,这里使用 MutationObserver 创建并返回一个新的观察器,它会在触发指定 DOM 事件时,调用指定的回调函数。当目标dom渲染后再触发修改样式操作。
  3. 对伪元素样式的修改,新建了一个样式表,在样式表里可以随意修改原class样式,当然,你也可以加载一个my-styles.css文件,在里面新增class,对原class进行覆盖:
//content-script.js
function setBeforeBackgroundColor(){
  document.querySelector('.view-nav').classList.add('blackcolor')
}
//manifest.json
{
  ···
  "content_scripts": [{
    "matches": ["https://*.juejin.cn/*"],
    "js": ["content-script.js"],
    "css": ["my-styles.css"]
  }],
}
/*my-styles.css*/
.view .blackcolor::before{ /*得益于原class只有一层,我们的class加到两层就可以覆盖原class了*/
  background-color: #22222d;
}

同样可以达到修改伪元素的目的。 最终,将background1.jscontent-script.js 通过chrome.runtime.onMessage.addListenerchrome.runtime.sendMessage连接:

// content-script.js
···
// switchTheme 切换light/dark模式
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  sendResponse('得到了结果');
  const { theme } = request;
  switchTheme(theme);
});

function init() {
  chrome.runtime.sendMessage({}, (res) => {
    const { theme } = res;
    switchTheme(theme);
  });
}
init();

// background1.js
···
chrome.runtime.onMessage.addListener((req,sender, sendResponse) => {
  // localStorageData 是从 chrome.storage.local获取的,在插件初始化时通过 chrome.storage.local.set设置
  sendResponse({theme: localStorageData})
})

结合之前 action 控制icon的逻辑,就可以通过点击icon来实现掘金首页 dark/light 切换了。由于代码量还不少,我将整体代码放在了GitHub上,供大家参考。

并且,为了让大家更方便的体验插件的内容,在误操作血亏$25注册了Google Play开发者、终于注册成功Chrome Web Store Developer但是在提交审核后填写资料出问题被拒绝、修改资料后再次提交审核后,插件终于上线了Chrome Store,现在你完全可以在Chrome Store下载一键修改掘金主题并体验。

第一版的插件并不完美,例如对字体颜色没有进行配置,后续我会进一步优化。谢谢你看到这里,欢迎点赞和评论。

参考资料:

  1. Google Chrome 数据分析,包含插件数据

    Chrome Extension 数据一览

  2. Темная тема для ВК | Dark theme for VK

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿