想写一个支持html转PDF的小工具方便自己日常使用,于是乎查了查资料关于怎么写chrome extension。记录撸代码的过程。
基础配置
- 进入 chrome://extensions 打开Developer mode
- 选择Load Uppacked加载你的extension
- 每次新改动要更新extension,之后记得刷新页面最新的change才能起效
extension的基本组成部分
extension主要是四块:manifest.json, content script, background script, popup。manifest.json定义了extension的基本信息、权限、后三者的结构。后三者之间只能通过message通信,可以理解为在不同的sandbox中。
manifest.json
如下manifest定义了permission、content、background、browser_action。可以注意到content_scripts字段是一个数组结构,而background却只能有一个。browser_action可以定制extension的图标和弹出的popup页面内容。
{
"name": "...",
"version": "1.0",
"description": "...",
"permissions": [
"downloads",
"activeTab",
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_popup": "index.html",
},
"manifest_version": 2,
"content_security_policy": "script-src 'self' 'sha256-GgRxrVOKNdB4LrRsVPDSbzvfdV4UqglmviH9GoBJ5jk='; object-src 'self'"
}
content scripts
content_scripts是能拿到当前访问的网页元素。也就是script中写个console.log会输出在当前的Chrome deveploment tool上。
// listener的message
chrome.runtime.onMessage.addListener(function(message, sender,senderResponse){
//...
});
background script
background script只能通过background page进行debug。该区域也没有直观UI效果。
chrome.browserAction.onClicked.addListener(function(tab){
// send message to tab
chrome.tabs.sendMessage(tab.id, {text: "hello, i'm back"});
})
popup
点击extension图标是弹出页面
通信
message是不同区域之间通信的唯一方式,并且只有content script可以获取当前页面的dom节点。
chrome.runtime.onMessage
chrome.runtime.sendMessage
chrome.tabs.sendMessage
chrome.runtime.onconnect
通信这一块没有深入,遇到了Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist。试过几种方法发现跟时序有些关系,貌似过早调用runtime会连接失败,没有解决这个问题,后面换了种写法貌似避开了这个问题:( 。后期需要理解一下Live connect
chrome extensions api
- chrome.tabs
chrome.tabs.query({
active: true,
currentWindow: true
}, (tabs) => {
const tab = tabs[0];
chrome.tabs.sendMessage(tab.id, {text: "changeColor"});
});
- chrome.runtime
- chrome.download
- ...
使用react
在使用create-react-app脚手架时遇到的几点问题:
- eslint error没办法识别关键字chrome,解决方法是添加下面的注释在文件头部,可以避开eslint
/*global chrome*/
- chrome extension不支持inline script,creat-react-app默认打包之后存在inline script。在打包deploy的时候build参数添加INLINE_RUNTIME_CHUNK=false
{
"scripts": {
"start": "react-scripts start",
"build": "INLINE_RUNTIME_CHUNK=false react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
}
- 更新一定记得刷新页面,不然为进入自我怀疑模式
主要代码:github react_html2Pdf,目前只完成了粗糙的extension脚手架。
参考: