使用React.js开发Chrome插件

使用React.js开发Chrome插件

2018/07/09 · JavaScript · Chrome, 插件

原文出处: UncleChen   

一、入门

一、背景

相信看到这篇文章的人应该都用过Chrome插件吧,最近刚好有个这方面的需求,我就把Chrome插件的相关知识学习了一下,发现其实Chrome插件的开发和大前端Web开发的底子是一样的,无非就是runtime只限于Chrome浏览器,并且可以调用Chrome提供的一些chrome.* API来实现一些基于Chrome浏览器的小功能。这里非要类比的话,我理解chrome.* API就像我们开发Hybird应用一样,需要有一个bridge层来提供底层原生的能力给js。我是做Android开发出生的,这只是我的个人理解,可能对大Web技术的理解还是不够。

其实Chrome上的插件,从UI上主要分成两类:一类是浏览器按钮(BrowserAction),另一类是页面按钮(PageAction)。两者的开发大同小异,我这里今天主要介绍的主角不是Chrome插件开发,而是如何使用React.js来开发Chrome插件,本文先简单介绍下Chrome插件的开发和ReactJS,最后介绍如何采用Facebook官方推荐的creat-react-app脚手架来开发Chrome插件。

这是制作chrome扩展插件的入门指南,不需要任何编程基础,看完这个后,我们就着手做自己的Chrome插件了。好吧,我们现在就开始,其实我也是个新手。

二、Chrome插件开发基础知识

下面是我看的几篇教程,简单看一下应该就可以算Chrome插件速成了:

简单来说,一个最基本Chrome插件应用需要有一个manifest.json清单文件,这个文件一般长这样:

JavaScript

{ "manifest_version": 2, "name": "One-click Kittens", "description": "This extension demonstrates a browser action with kittens.", "version": "1.0", "permissions": [ "https://secure.flickr.com/" ], "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" } }

1
2
3
4
5
6
7
8
9
10
11
12
13
{
  "manifest_version": 2,
  "name": "One-click Kittens",
  "description": "This extension demonstrates a browser action with kittens.",
  "version": "1.0",
  "permissions": [
    "https://secure.flickr.com/"
  ],
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  }
}

这个文件里描述了插件应用的一些属性,如名称、版本、需要的权限、界面的对应的html文件名等等。额!!乍一看怎么和AndroidManifest.xml的功能这么像啊?是的大兄弟!!恭喜你对技术的理解已经融会贯通了!

根据manifest.json文件可以看到,一个Chrome插件最少得有:manifest.json文件,icon.png图标和popup.html文件。当然文件名可以随便改,只要和manifest.json里声明的一致就行。

这里就不浪费时间具体说怎么开发插件了,各路前端大牛比我强100倍。但我只强调一点,那就是popup.html中引用的js文件只能是外部引入,不能在popup.html文件里面写js代码。所以一般我们还有见到popup.js文件。另外如果你想知道自己使用的插件有什么秘密,完全可以去Chrome浏览器的安装目录下面把它们给扒出来。。

图片 1

三、React JS基础知识

React.js不需要多说了吧,从React这个词在技术界诞生起,就是一颗明星,连我这种死抱着Native技术的人都不得不去学习它。。

简单扯两句React JS的话题(React Native下次再说),作为一个Android App/SDK开发,我没有开发过太多传统意义上的Web页面,但是经过我学习了大概一周多的时间,我发现React JS开发Web页面的思路其实和客户端很像,不去用jQuery/Zepto啊操作DOM,而是关注数据本身,以数据驱动去改变界面。重构写好了静态html后,哪块地方需要变化,你就把哪里变成一个变量放到组件的State/Props里面(至于组件怎么切分,哪个数据放State,哪个放Prop不是今天要讨论的话题),然后就只用关注数据的变化,然后setState一下界面就可以刷新了。理解了这一点,就会发现其实开发Web页面很简单。比起操作DOM,一些模板引擎之类的东西,我认为React这个思想非常容易接受,写起来也很舒服,完全没有那种混乱的感觉,而且现在ReactJS生态圈非常大,诸如Redux这类的库使得ReactJS越发的犀利,很多公司早就用得飞起了。

扯得有点远了,ReactJS开发我推荐大家就看Facebook官方的示例就够了。英文不好的朋友可以看看阮一峰老师的博客,或者看看这篇入门教程也是阔以的。

准备工具

四、应该用哪个脚手架?

当然是Facebook官方推荐的creat-react-app。打开终端,依次输入:

JavaScript

npm install -g create-react-app create-react-app my-app cd my-app/

1
2
3
npm install -g create-react-app
create-react-app my-app
cd my-app/

然后就在my-app下面看到这些文件了。

JavaScript

my-app/ README.md node_modules/ package.json .gitignore public/ favicon.ico index.html manifest.json src/ App.css App.js App.test.js index.css index.js logo.svg registerServiceWorker.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my-app/
  README.md
  node_modules/
  package.json
  .gitignore
  public/
    favicon.ico
    index.html
    manifest.json
  src/
    App.css
    App.js
    App.test.js
    index.css
    index.js
    logo.svg
    registerServiceWorker.js

到此为止,是一个标准的ReactJS编写WebApp的步骤,在终端输入npm start,就可以在浏览器中访问本地的localServer了。

做任何事情都要有个工具,制作chrome插件需要的工具很少。

1.怎么让这个项目支持Chrome插件开发呢?

前面介绍了,Chrome插件最重要的文件就是manifest.json清单文件。我们先看下脚手架给我们默认生成的manifest.json长啥样:

JavaScript

{ "short_name": "React App", "name": "Create React App Sample", "icons": [ { "src": "favicon.ico", "sizes": "192x192", "type": "image/png" } ], "start_url": "./index.html", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "192x192",
      "type": "image/png"
    }
  ],
  "start_url": "./index.html",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

对于一个普通的WebApp来说,manifest.json文件在缓存、离线模式以及最新的PWA场景下会起作用,但是这里我们是要开发Chrome插件,那么把它原来的内容通通删掉,改成你的Chrome插件所需要的格式和内容就好了。例如可以改成这样:

JavaScript

{ "manifest_version": 2, "name": "MyChromeExt", "description": "My first chrome extension.", "version": "1.0.0", "icons": { "16": "img/icon-16.png", "128": "img/icon-128.png" }, "browser_action": { "default_icon": { "19": "img/icon-19.png", "38": "img/icon-38.png" }, "default_title": "MyChromeExt", "default_popup": "index.html" }, "permissions": [ "tabs" ], "background": { "scripts": ["background.js"] } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
  "manifest_version": 2,
  "name": "MyChromeExt",
  "description": "My first chrome extension.",
  "version": "1.0.0",
  "icons": {
"16": "img/icon-16.png",
"128": "img/icon-128.png"
},
  "browser_action": {
    "default_icon": {
"19": "img/icon-19.png",
"38": "img/icon-38.png"
},
    "default_title": "MyChromeExt",
    "default_popup": "index.html"
  },
  "permissions": [
    "tabs"
  ],
  "background": {
    "scripts": ["background.js"]
  }
}

这里尽可能对脚手架的东西做最小的改动,把default_popup的文件名改成了index.html,因为脚手架默认会把js文件都打包到一个main.js文件中,并在index.html中插入这个main.js。

我们运行一下npm run build命令,就会发现生成了一个my-app/build目录,这个目录就是我们可以在chrome://extensions/去加载的插件目录,当然也可以用Chrome把这个目录打包成一个crx插件。

使用creat-react-app脚手架开发Chrome插件的基本方法就是这样了,但是在实际中我们会遇到很多的问题,有时甚至会想要运行npm run eject,然后去完全自定义webpack.config.js来实现打包。

  • 记事本,用来编写代码
  • Chrome浏览器,这个不能少吧。Windows下,所有版本的Chrome都可以制作插件。Linux下需要下载Beta版本,Mac下载dev版本。

2.background.js怎么打包?

我们在开发插件的时候,非常可能需要用到后台的background.js,原因如下:

注意:不要在popup页面的js空间变量中保存数据。由于popup页面只在用户点击图标时才会开启,当用户关闭这个页面时就会停止,并没有一个从始至终的实例分配给popup页面。所以每当用户打开popup页面时,它都是崭新的,之前保存在变量中的数据都会消失。如果需要通过popup页面保存用户的数据,可以通过通信将数据交给后台页面(background页面)处理,或者通过localStorage和chrome.storage将数据保存在用户的硬盘上。

所以background.js最后也是要进入到我们的发布文件夹下面的,这里建议还是要坚持最低程度地修改脚手架的设置,建议不要npm run eject之后来修改webpack的配置,因为实在是真的有点复杂。

这次修改下package.json文件:

JavaScript

{ "name": "my-app", "version": "0.1.0", "private": true, "devDependencies": { "react-scripts": "1.0.7" }, "dependencies": { "react": "^15.6.1", "react-dom": "^15.6.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "build-chrome-ext": "react-scripts build && cp src/background.js build/background.js" } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "devDependencies": {
    "react-scripts": "1.0.7"
  },
  "dependencies": {
    "react": "^15.6.1",
    "react-dom": "^15.6.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "build-chrome-ext": "react-scripts build && cp src/background.js build/background.js"
  }
}

可以看到我们添加了一个命令npm run build-chrome-ext,并把background.js丢到了build目录下。如果你还有其他的js,我建议在my-app/src下建立一个my-app/src/chrome文件夹,专用于存在chrome相关其他js代码,然后在build的时候统一丢到build里面。如果要minify这些js,同样可以采用&&方式去添加命令。修改

开始制作第一个插件

3.需要注意的细节

由于使用了一些chrome.* API,我们需要在编译js的时候将chrome这个全局对象声明一下。

creat-react-app这个脚手架在非eject模式下,没办法修改ESlint的配置来添加global对象,只能在用到了 chrome.* API的代码处添加 // eslint-disable-line 注释来实现保证编译通过。

如果你已经npm run eject了,在eject模式下,可以在package.json文件里配置ESLint:

JavaScript

"eslintConfig": { "extends": "react-app", "globals": { "chrome": true } }

1
2
3
4
5
6
"eslintConfig": {
"extends": "react-app",
"globals": {
  "chrome": true
  }
}
  • 在计算机中创建一个目录来存放插件代码。
  • 在目录里面创建文件manifest.json(注意后缀名是.json),用记事本打开,写入如下代码
    1. {
    2.   "name": "第一个Chrome插件",
    3.   "version": "1.0",
    4.   "description": "我的第一个Chrome插件,还不错吧",
    5.   "browser_action": {
    6.     "default_icon": "icon.gif"
    7.   }
    8. }

五、其他脚手架推荐

除了自己改造Facebook推荐的creat-react-app外,下面两个脚手架也算是用户比较多的,专门用于开发Chrome插件的脚手架。

图片 2

  • 把下面两张图片保存到文件夹中,分别取名icon.gif和smile.gif
    图片一: 图片 3     图片二: 图片 4
  • 安装这个插件:
    a.点击右上角扳手,选择扩展程序,打开扩展中心。
    b.点击右上角的“开发人员模式”,使得前面的“+”变成“-”,打开相应的菜单。如果一开始就是“-”,那么不用点击。
    c.点击“载入正在开发的扩展程序按钮”,导入刚才创建的文件夹。

如果一切顺利,你的Chrome地址栏将会有个新图标,你的第一个插件诞生了。

给第一个插件增加新功能

你现在虽然做了第一个插件,但实际上他并没有实现任何功能,我们点击图标,没有任何反应。下面我们就给他增加点功能。

  • 编辑manifest.json这个文件,用下面的代码替换现有的代码,其实我们只是加了一行代码和一个逗号而已。

    1.    "name": "第一个Chrome插件", 
    2.    "version": "1.0", 
    3.    "description": "我的第一个Chrome插件,还不错吧", 
    4.    "browser_action": { 
    5.       "default_icon": "icon.gif", 
    6.       "popup": "popup.html" 
    7.    }
    8. }
  • 下面我们创建一个文本文件popup.html,用记事本打开,将下面的代码写进去

    1. <p>Hello,Chrome!</p>
    2. <p>我的名字叫ChromeChina!</p>
    3. <p><a href="http://www.chromechina.com" target="_blank">Chrome中文论坛欢迎你</a>
    4. <p><img src="smile.gif" /></p>
  • 回到Chrome的扩展中心,点击插件下的“重新载入 ”。

现在点击插件图标看看。我们的第一个插件算是制作成功了。

打包插件

我们想把自己制作的插件给其他人用,那么就需要将插件打包。

  • 回到Chrome的插件扩展中心,点击“打包扩展程序”按钮。
  • 选择刚才创建的文件夹,点击确定生成后缀为crx和cpm文件各一个。

把crx文件发送给自己的朋友,告诉他们你也会制作chrome插件吧。

你可以修改里面的文字图片,制作出极具个性的扩展来了。

要是在制作过程中有任何问题,欢迎到http://dev.chromechina.com来讨论交流。本文参考官方指南http://code.google.com/chrome/extensions/编写。

二、概述

这篇文章翻译自http://code.google.com/chrome/extensions/overview.html

只要看完这篇文章,并且做过入门指南中的例子,你就可以真正开始开发属于自己的Chrome插件了。

基础知识

一个Chrome扩展是由HTML、CSS、JavaScript、图片等文件压缩而成。扩展实际上就是一个web页面,你可以用任何浏览器提供给web页面的接口,从XMLHttpRequest 到JSON ,再到HTML本地缓存都可以使用。

Chrome扩展能做什么呢?我们肯定使用过一些扩展,会发现有些扩展在Chrome地址栏右侧区域增加一个图标。还有些扩展能够和浏览器的一些元素(如书签、tab导航标签)交互。扩展还可以和web页面交互,甚至是从web服务器获取数据。更加详细的内容可以从Developer's Guide看到。

Chrome扩展的组成文件

每个扩展由下列文件组成:

  • 一个manifest文件(主文件,json格式)
  • 至少一个HTML文件(主题可以没有HTML文件)
  • JavaScript文件 (可选,非必须)
  • 任何其他你需要的文件(比如图片)

当你开发一个扩展的时候,需要把这些文件放在一个文件夹里,当你发布这个扩展的时候,这个文件夹下的所有文件将会打包成一个特殊后缀.crx的ZIP文件。

引用文件

你可以放置任何文件到你的扩展里面,但是怎么调用这些文件呢?一般来说,使用相对地址调用,类似HTML中调用文件。下面是个例子,在子文件夹images中有个图片myimage.png,我们可以这样调用它

  1. <img src="images/myimage.png">

复制代码

其中images/myimage.png表示这个文件。

也许你注意到当使用Google Chrome debugger查看这些文件的时候给,每个文件的地址是下面这种格式

  1. chrome-extension://<extensionID>/<pathToFile>

复制代码

这个地址中,<extensionID>是你制作的扩展的唯一标示符,也就是扩展的身份证编号。<pathToFile>是文件相对扩展顶级文件夹得位置。

manifest文件

主文件取名manifest.json,用来描述这个扩展,包括扩展名字、版本、调用的文件、可用域等信息。下面是个典型的manifest文件,这个扩展可以调用google.com的内容。

  1. {
  2.   "name": "My Extension",
  3.   "version": "2.1",
  4.   "description": "Gets information from Google.",
  5.   "icons": { "128": "icon_128.png" },
  6.   "background_page": "bg.html",
  7.   "permissions": ["http://*.google.com/", "https://*.google.com/"],
  8.   "browser_action": {
  9.     "default_title": "",
  10.     "default_icon": "icon_19.png",
  11.     "popup": "popup.html"
  12.   }
  13. }

复制代码

扩展结构组成结构

绝大部分扩展有background文件,一个不可见的文件控制着整个扩展的运行。

图片 5

上面这个图片显示的浏览器至少安装了两个扩展:一个浏览器行为扩展(黄色的图标),页面行为扩展(蓝色的图标)。这个浏览器行为扩展的background文件是用一个HTML文件定义的(background.html),这个background文件中有JavaScript代码控制整个浏览器的活动。

HTML页面

background不是唯一存在的HTML文件,比如浏览器行为可能是弹出一个小窗口,这个小窗口的内容就可以调用一个HTML文件。Chrome扩展也能够用chrome.tabs.create() or window.open()这种函数来显示HTML文件。

扩展里面的HTML文件可以互相访问对方的DOM结构,可以引用其他文件中定义的函数。

下面的图展示了浏览器弹出一个窗口这个功能的结构(这正是我们最开始的例子)。这个弹出窗口的内容是一个HTML的web文件,这个弹出窗口不需要包含background文件中的代码,因为,popup.html和background是可以互相访问的。

图片 6

内容脚本(Content scripts)

如果你插件需要和网页交互,那么他就需要一个内容脚本(Content scripts),内容脚本常由JavaScript编写,会在网页载入完成后调用。完全可以把内容脚本看做是网页的一部分,而不是扩展的一部分。

内容脚本可以访问到当前浏览器浏览的页面,而且还可以改变网页的显示方式(油猴脚本就是内容脚本)。下面的图片中,内容脚本可以读取、更改网页的DOM。注意,他不能更改background.html中的内容。

图片 7

内容脚本也不是和父扩展完全隔离开来,他也可以和父级扩展交换信息。如下图中所示,内容脚本在发现一个RSS Feed地址后将会给background.html发送一个信息。或者background.html给内容脚本发送一个信息要求改变网页外观。

图片 8

不同页面间的交互

一个扩展中的文件常常需要交互。由于扩展的所有文件都由同一个进程执行,网页能够直接给其他页面发送命令。

可以使用类似chrome.extension methods such as getViews() and getBackgroundPage()这样的方法引用扩展中的方法。一旦页面中引用了另外的页面,第一个页面就可以调用其他页面的函数,甚至可以控制DOM。

结束语

好了,你已经大概了解了一个扩展程序的基本内容,可以开始写作自己的扩展了。

本文由ChromeChina翻译,转载注明出处http://dev.chromechina.com/

三、扩展图标

本文由金沙官网线上发布于Web前端,转载请注明出处:使用React.js开发Chrome插件

您可能还会对下面的文章感兴趣: