做为一位前端开发人员,估计是离不开 chrome 浏览器吧,但是你在使用 chrome 时,有遇到一些痛点吗?html
你有想过本身开发一款插件来解决本身使用上的不便吗?其实 chrome 插件已经提供了挺多实用的 API,咱们彻底能够根据本身的需求或兴趣开发本身的插件。前端
chrome 插件没有严格的项目结构的要求,只要求根目录存在一个 manifest.json
相似安卓开发中的 AndroidManifest.xml
这是一个很是重要的功能清单文件,chrome 根据这个文件开放给扩展相应的功能权限。react
<!-- more -->webpack
因此 chrome 扩展的开发彻底能够选择咱们本身熟悉的技术栈开发,好比咱们能够用 React(Vue、Angular) 来开发。下面就是记录我用 React 开发一款好用代理插件 Just Proxy 的过程git
已上架:https://chrome.google.com/web...github
首先须要肯定咱们的插件须要使用 chrome 开发的那些功能,先用户提供哪些界面。web
由于如今要开发的是一款代理插件,咱们向用户提供一下功能:chrome
根据上述的需求,咱们肯定的以下的 manifest.json
的内容。json
{ "manifest_version": 2, "name": "Just proxy", "description": "A simple proxy tool", "version": "1.0.2", "permissions": ["proxy", "storage", "tabs"], "browser_action": { "default_icon": "emoticon.png" }, "icons": { "64": "emoticon.png" }, "options_page": "index.html", "background": { "scripts": ["background.js"], "persistent": false } }
关于 manifest.json
更加详细的内容能够查看 https://developer.chrome.com/...redux
接下来咱们就可使用 Webpack(推荐) 来做为扩展的构建工具,由于 chrome 扩展是须要读取硬盘的文件的,咱们为了提升咱们扩展开发的体验(不要每次修改代码,都须要从新构建扩展,支持热更新),咱们须要借助 write-file-webpack-plugin
来将咱们的内存的编译文件写回硬盘(不严谨)。由于咱们使用 React 构建咱们的扩展程序,因此也要 react-hot-loader
来实现热更新。webpack-dev-server
的配置和咱们开发网页时一致,这里就再也不说明了。
由于 chrome 扩展程序 不是网页,而且它对功能权限有着比网页加严格要求因此咱们须要改造下咱们的 manifest.json
以便支持扩展的热更新
{ "manifest_version": 2, "name": "Just proxy", "description": "A simple proxy tool", "version": "1.0.2", "permissions": ["proxy", "storage", "tabs", "http://127.0.0.1:8000/*"], "browser_action": { "default_icon": "emoticon.png" }, "icons": { "64": "emoticon.png" }, "options_page": "index.html", "background": { "scripts": ["background.js"], "persistent": false }, "content_security_policy": "default-src 'self' http://127.0.0.1:8000 http://localhost:8000; script-src 'self' http://127.0.0.1:8000 http://localhost:8000 'unsafe-eval'; connect-src http://127.0.0.1:8000 http://localhost:8000 ws://127.0.0.1:8000 ws://localhost:8000; style-src * 'unsafe-inline' 'self' blob:; img-src 'self' data:;" }
这里值得关注的点就是 content_security_policy
这一项,这里再也不作详细的说明,想要了解更多的话能够戳下面的连接
https://developer.mozilla.org...
webpack.config.js
的配置须要注意的点,须要注明 publicPath
。
module.exports = { // ... output: { // ... publicPath: "http://127.0.0.1:8000/" } // ... };
经过上面的设置咱们就能够拥有一个良好的开发体验了(开发环境和打包环境须要不一样的配置,主要是针对热更新方面)
项目的状态管理我使用的是 redux
,关于状态的持久化咱们能够借助 redux-persist
实现。由于 redux-persist
默认的是使用 localStorage
,可是 chrome 扩展中是不支持的,须要本身实现 chrome 插件版本的 storage
。 代码以下:
export default class ChromeLocalStorage { getItem(key: string) { return new Promise(resolve => { chrome.storage.local.get(key, item => resolve(item[key])); }); } setItem(key: string, value: string) { return new Promise(resolve => chrome.storage.local.set({ [key]: value }, resolve) ); } removeItem(key: string) { return new Promise(resolve => chrome.storage.local.remove(key, resolve)); } }
在咱们这个扩展存在两个操做比较麻烦的地方
为了处理上面两个问题咱们能够实现一个 redux 中间件来简化上面的操做,实现以下:
const chromeProxyMiddleware = store => { // 处理其余环境发过来的 action chrome.runtime.onMessage.addListener(request => { store.dispatch({ ...request, passed: true }); }); return next => action => { // 给其余环境发生 action if (passingActions.indexOf(action.type) >= 0 && !action.passed) { chrome.runtime.sendMessage(action); } // 设置代理 chrome.proxy.settings.set(/* proxy config */); }; }; export default chromeProxyMiddleware;