Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8906

Vue.jsでChrome拡張機能を作って失敗した話

$
0
0

これはただの集団 Advent Calendar 2020の13日目の記事です。

■ 前書き

Chromeの拡張機能が htmljsで作れると知りまして、
自分がよく使っている Vue.jsでやってみようと思いまして試しに作ってみた。
・・・ところ見事に失敗した話。

◇ 参考

■ 開発環境

  • macOS:Catalina
  • Node.js:v14.7.0
  • nodebrew:v8.9.4
  • yarn:v1.22.10
  • Chrome:v87.0 (x86)

■ 導入手順

Kocal/vue-web-extensionを使って作って行きます。

とりあえず作業用ディレクトリを作る
$ mkdir myDir
$ cd myDir
プロジェクト作成
$ vue init kocal/vue-web-extension sample-extension

  Command vue init requires a global addon to be installed.
  Please run yarn global add @vue/cli-init and try again.

◇ 何やら失敗したので色々確認・・・

調査中・・・
# vue-cliは入ってる。$ vue --version
@vue/cli 4.5.6

# しばらくやってなかったのでupgradeする。$ yarn global upgrade

# 指示通りinitをいれる。$ yarn global add @vue/cli-init

# 再挑戦してみたが・・・$ vue init kocal/vue-web-extension sample-extension
vue-cli · ENOENT: no such file or directory,'/Users/hogehoge/.vue-templates/kocal-vue-web-extension/template'

◇ Readmeを読んだら・・・・

initではなく createを使う方法に変わっていた。

$ vue create --preset kocal/vue-web-extension sample-extension

終わるまで結構時間がかかります。

◇ オプション

@vue/cli-plugin-eslint
# lintは好みで選択しました
? Pick an ESLint config: Standard
? Pick additional lint features: Lint on save
vue-cli-plugin-browser-extension
# 簡単にpopupを作る予定なので2つだけ
? Which browser extension components do you wish to generate? background, popup
# ストアに公開せず個人の範疇で利用するので、今回は無し
? Generate a new signing key (danger)? No
Preset options:
? Install axios? Yes

■ 構成

◇ package.json

package.json
{"name":"sample-extension","version":"0.1.0","private":true,"scripts":{"serve":"vue-cli-service build --mode development --watch","build":"vue-cli-service build","lint":"vue-cli-service lint"},"dependencies":{"axios":"^0.20.0","core-js":"^3.6.5","vue":"^2.6.11","vue-router":"^3.2.0","vuex":"^3.4.0"},"devDependencies":{"@vue/cli-plugin-babel":"~4.5.0","@vue/cli-plugin-eslint":"~4.5.0","@vue/cli-plugin-router":"~4.5.0","@vue/cli-plugin-vuex":"~4.5.0","@vue/cli-service":"~4.5.0","@vue/eslint-config-standard":"^5.1.2","babel-eslint":"^10.1.0","eslint":"^6.7.2","eslint-plugin-import":"^2.20.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.2.1","eslint-plugin-standard":"^4.0.0","eslint-plugin-vue":"^6.2.2","sass":"^1.26.5","sass-loader":"^8.0.2","vue-cli-plugin-browser-extension":"latest","vue-template-compiler":"^2.6.11"}}

◇ manifest.json

とりあえず初期設定のままで。

src/manifest.json
{"manifest_version":2,"name":"__MSG_extName__","homepage_url":"http://localhost:8080/","description":"A Vue Browser Extension","default_locale":"en","permissions":["<all_urls>","*://*/*"],"icons":{"16":"icons/16.png","48":"icons/48.png","128":"icons/128.png"},"background":{"scripts":["js/background.js"],"persistent":false},"browser_action":{"default_popup":"popup.html","default_title":"__MSG_extName__","default_icon":{"19":"icons/19.png","38":"icons/38.png"}}}

◇ ディレクトリ

sample-extension/
 ├── node_modules/
 ├── public/
 │   ├── _locales/
 │   │   └── en
 │   ├── icons/
 │   │   ├── 128.png
 │   │   ├── 16.png
 │   │   ├── 19.png
 │   │   ├── 38.png
 │   │   └── 48.png
 │   ├── browser-extension.html
 │   ├── favicon.ico
 │   └── index.html
 ├── src/
 │   ├── assets/
 │   │   └── logo.png
 │   ├── components/
 │   │   └── HelloWorld.vue
 │   ├── popup/ (今回はこれを使う)
 │   │   ├── App.vue
 │   │   └── main.js
 │   ├── router/
 │   │   └── index.js
 │   ├── store/
 │   │   └── index.js
 │   ├── views/
 │   │   ├── About.vue
 │   │   └── Home.vue
 │   ├── App.vue
 │   ├── background.js
 │   ├── main.js
 │   └── manifest.json
 ├── README.md
 ├── babel.config.js
 ├── package-lock.json
 ├── package.json
 └── vue.config.js

■ 開発手順

  • Chromeの拡張機能画面から デベロッパーモードをONにする
  • distディレクトリをパッケージとしてブラウザに登録する
  • yarn servewatchを開始する
  • あとはコードを書いていく (HMRが効いているので再読み込みとかはいらないはず・・・)
  • yarn buildで本番ビルド

■ サンプルコード

◇ Axiosを使えるようにする

src/popup/main.js
importVuefrom'vue'importaxiosfrom'axios'importAppfrom'./App.vue'//←これを追加Vue.prototype.$axios=axios//←これを追加/* eslint-disable no-new */newVue({el:'#app',render:h=>h(App)})

◇ Before

アイコンをクリックして出てくるポップアップの内容が変更されたのを確認。
変更するファイルはこれで良さそう。

src/popup/app.vue
<template><hello-world/></template><script>importHelloWorldfrom'@/components/HelloWorld.vue'exportdefault{name:'App',components:{HelloWorld}}</script><style>html{width:400px;height:400px;}</style>

◇ After

  1. アイコンをクリック
  2. アクティブになっているタブのURLを取得
  3. 取得したURLを元にリクエストを投げる
  4. レスポンスの情報を表示する

・・・みたいな処理になるはず。

src/popup/app.vue
<template><div><dl><dt>currentUrl</dt><dd>{{currentUrl}}</dd></dl><dl><dt>originDomain</dt><dd>{{originDomain}}</dd></dl><dl><dt>responseData</dt><dd>request:{{targetUrl}}</dd><dd>{{responseData}}</dd></dl></div></template><script>exportdefault{name:'App',data(){return{rawUrl:'',originDomain:'',targetUrl:'',baseUrl:'https://api.whoisproxy.info/whois/',responseData:{}}},created(){this.initialize()this.urlRequest(this.targetUrl)},methods:{initialize(){chrome.tabs.query({active:true},(tabs)=>{this.setRawUrl(tabs)this.setOriginDomain(this.rawUrl)this.setTargetUrl(this.originDomain)})},setCurrentUrl(tabs){this.rawUrl=tabs[0].url},setOriginDomain(url){letcandidate=[]candidate=url.split('/')this.originDomain=`${candidate[2]}`},setTargetUrl(domainData){this.targetUrl=`${this.baseUrl}${domainData}`},urlRequest(url){this.$axios.get(url).then(response=>(this.responseData=response)).catch(error=>console.log(error))},}}</script><style>html{min-width:400px;min-height:400px;}</style>

■ 結果

おそらくですが、 Content Security Policyに引っかかったようです。
manifest.jsonのContent-Security-Policyあたりが怪しいですね。
background.jsを利用すればできるのかもしれませんが力尽きました・・・)
良い方法があればご教示いただけると大変ありがたいです。

参考:
https://developer.chrome.com/docs/apps/contentSecurityPolicy/
https://developers.google.com/web/fundamentals/security/csp
https://oxynotes.com/?p=8895
https://xxxx7.com/2014/04/07/152039

◇ まとめ

Chrome extensionは javascriptで簡単に作れる。(jQueryやモダンなAngular・Reactでもできそう)
ただし外部リソースの利用については注意が必要である。


Viewing all articles
Browse latest Browse all 8906

Trending Articles