关于chrome-extension:chrome插件从0到1

108次阅读

共计 4469 个字符,预计需要花费 12 分钟才能阅读完成。

记录一下本人从零开始构建一个插件的过程~
我这个插件的逻辑次要是向指标页面注入一个 icon,

1. 创立一个 react 我的项目

首先官网更新,不再提供全局装置的 create-react-app,应用

npx create-react-app@latest yourProjectName --template typescript --use-npm

装置胜利后,将不须要的文件给删除掉,更改 manifest.json 这个配置文件,过后应用的是 V2 版本,后续将其更新为 V3 版本,次要是 chrome 浏览器在 2023 年会将 V2 版本的给废除掉,:(
我的配置文件如下,其中具体的介绍能够查阅这篇文章:chrome 插件开发攻略

{
    // 清单文件的版本,这个必须写,而且必须是 2
    "manifest_version": 2,
    // 插件的名称
    "name": "demo",
    // 插件的版本
    "version": "1.0.0",
    // 插件形容
    "description": "简略的 Chrome 扩大 demo",
    // 图标,个别偷懒全副用一个尺寸的也没问题
    "icons":
    {
        "16": "img/icon.png",
        "48": "img/icon.png",
        "128": "img/icon.png"
    },
    // 会始终常驻的后盾 JS 或后盾页面
    "background":
    {
        // 2 种指定形式,如果指定 JS,那么会主动生成一个背景页
        //"page": "background.html"
        "scripts": ["background.js"]
    },
    // 须要间接注入页面的 JS
    "content_scripts": 
    [
        {//"matches": ["http://*/*", "https://*/*"],
            // "<all_urls>" 示意匹配所有地址
            "matches": ["<all_urls>"],
            // 多个 JS 按程序注入
            "js": ["content-script.js",icon.js],
            // JS 的注入能够轻易一点,然而 CSS 的留神就要千万小心了,因为一不小心就可能影响全局款式
            "css": ["icon.css"],
            // 代码注入的工夫,可选值:"document_start", "document_end", or "document_idle",最初一个示意页面闲暇时,默认 document_idle
            "run_at": "document_end"
        },
    ],
    // 权限申请
    "permissions":
    [
        "contextMenus", // 右键菜单
        "tabs", // 标签
        "activeTab",
        "http://*/*", // 能够通过 executeScript 或者 insertCSS 拜访的网站
        "https://*/*" // 能够通过 executeScript 或者 insertCSS 拜访的网站
    ],
    "content_security_policy": "script-src'self''unsafe-eval'; object-src 'self'",
    "externally_connectable":{
      "matches":[
        "*://*.italent-inc.cn/*",
        "*://*.italent.link/*",
        "*://*.italent.cn/*"
      ]
  }
}

先大抵晓得有这么些配置属性就行,上面一步一步的细化
首先梳理一下 backgound 与 content 之间的关系:

  • backgound,它随着浏览器的关上而关上,随着浏览器的敞开而敞开,所以通常把须要始终运行的、启动就运行的、全局的代码放在 background 外面,而且它能够有限跨域
  • Chrome 插件中向页面注入脚本的一种模式,特定无法访问页面中的 JS,尽管它能够操作 DOM,然而 DOM 却不能调用它,侥幸的是能够通过注入脚本的模式实现向页面增加 dom 元素
  • 因为 content scripts 运行在 Web 页面的上下文中,属于 Web 页面的组成部分,而不是 Google Chrome 扩大程序。然而 content scripts 又往往须要与 Google Chrome 扩大程序的其余局部通信以共享数据,这通过消息传递实现

    2. 创立 backgound.js 文件

    我的逻辑就次要是监听页面刷新,就在 content 去掉用我的办法

// 监听页面刷新
chrome.tabs.onUpdated.addListener(async function (tabId, message, option) {
  // 避免加载中和加载实现执行 2 次
  if(message.status !== 'complete' || option.status !== 'complete'){return}
  chrome.tabs.sendMessage(tabId,{
    type:"initIcon",
    taburl:option.url // 配置信息须要减少 activeTab 的权限
  })
})

3. 创立 content.js

//content 承受 bg 音讯
chrome.runtime.onMessage.addListener(async function (msg) {if (msg.type === "initIcon") {const urlStorage = window.localStorage.getItem('iframeUrl')
    // 以下是我的业务逻辑,就不多形容了
    if(urlStorage){
      // 间接应用域名判断
      if(isShow()){render()
      }else{console.log('remove');
        window.localStorage.removeItem('iframeUrl')
        destroy()}
    }else{destroy()
    }
  }
});

值得一提的就是 render 函数就是下面我提到的通过注入脚本的模式实现向页面增加 dom 元素

const render = function (){const url = window.localStorage.getItem('iframeUrl')
  const script = document.createElement('script');
  script.src = chrome.runtime.getURL('icon.js');
  document.documentElement.appendChild(script);
}

这里也看到了我引入 icon.js 这个脚本,

const App = () => {

    // 省略掉不重要的

  return (<div className={"lm-chrome-guide-icon"} onClick={()=>setDrawerVisible(true)} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
      <img src={imgSrcObj[imgSrc]}/>
    </div>
  );
};

// 在 Chrome 扩大程序中将 React Component 注入页面
const mountNode = document.createElement("div");
mountNode.id = 'mapNode'
document.body.appendChild(mountNode);
ReactDom.render(<App />, mountNode);

值得一提的是,通过这个办法注入的 icon,会在主页面的底部,能够在 chrome 控制台查看搜寻相干内容查看是否注入胜利,注入胜利后却没有显示,应用了 position: fixed;
z-index: 9999 这两行代码来显示。
PS 我感觉初学 chrome 插件最难的就是各种门路 ….:(
此时我的我的项目 目录构造是这样的

值得一提的是 我在 package.json 加了这条命令

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    // 这条命令
    "build-chrome-ext": "react-scripts build && cp src/js/background.js build/background.js && cp src/js/content.js build/content.js && cp build/static/js/main.***.js build/icon.js && cp build/static/css/main.***.css build/icon.css"
  },

其中 index.js 文件就是该项目标入口文件,因而此时的命令就是将编译后的文件打包 build/static/js/main.*.js

此时执行 npm run build-chrome-ext, 而后 chrome 浏览器加载解压的 build 文件,一个插件就实现啦

优化:

  1. V2 –> V3
    此时将配置文件更改为
    V2 到 V3 的扩大迁徙,能够参考此篇文章 chrome 插件从 V2 到 V3 的迁徙
{
  "short_name": "施行地图",
  "name": "施行地图插件",
  "manifest_version": 3,
  "content_security_policy": {"extension_pages": "script-src'self'; object-src'self'"},"version":"1.0","background":{"service_worker":"background.js"},"icons":
    {
        "16": "img/icon.png",
        "48": "img/icon.png",
        "128": "img/icon.png"
    },
  "content_scripts": [ {"js": [ "content.js","icon.js"],
    "css": ["icon.css"],
    "matches": [ 
      "*://*.italent-inc.cn/*",
      "*://*.italent.link/*",
      "*://*.italent.cn/*" ],
    "run_at": "document_end"
  } ],
  "permissions":[
    "tabs",
    "activeTab",
    "storage"
  ],
  "host_permissions":[
    "http://*/*",
    "https://*/*"
  ],
  "externally_connectable":{
    "matches":[
      "*://*.italent-inc.cn/*",
      "*://*.italent.link/*",
      "*://*.italent.cn/*"
    ]
  }
}
  1. 打包命令优化
    那一长串打包命令确实有些俊俏,能够做成这种: “react-scripts build && node xxx.js”,而后把文件操作写到 xxx.js 里,就是写个 shell 脚本来专门做文件的挪动和拷贝,不肯定是 shell,喜爱哪个用哪个

当然 我的这个插件性能很简略,还有很多没有考虑周到的中央,后续有机会持续跟进学习~

正文完
 0