DRYな備忘録

Don't Repeat Yourself.

Chrome拡張の開発でwebpackを使わずにES6のimportを有効にしたい

追記 2018/10/29

chromeモジュールが使えなくなる、という指摘は半分正しくて半分間違ってる(いくらでもやりようがある)のでもうちょっとちゃんとした記事を書きました。

medium.com

以下原文ママ


背景

  • JSのプロジェクトで、特に僕はChrome拡張を作ることが多いんですが、ES6 syntaxを使いたい
  • だいたいのES6 syntaxは、Chrome(現在 65.0.x)で使える
  • ただし、問題は import です

Background Script でimportを使う

medium.com

つまりHTML5準拠のブラウザでは<script type="module" src="..."></script>とすれば、これをエントリポイントとして以下importは解決されるんだけど、ということは逆にmanifest.jsonbackground.scriptsでBackgroundスクリプトを指定するとtype="module"属性を与えられないので、わざわざbackground.pageを使ってそこから<script>しましょうね、という話。

manifest.json

{
    "background": {
        "page": "src/html/background.html"
    }
}

src/html/background.html

<script type="module" src="src/js/background.js"></script>

Use ES6 import in Background Script · otiai10/chrome-extension-es6-import@ecf1267 · GitHub

Content Script でも、importを使いたい、のだが

同様の理由で、manifest.jsoncontent_scripts[i].jsでいきなりimportを使っても

Uncaught SyntaxError: Unexpected identifier

となる。 Uncaught SyntaxError: Unexpected identifier · otiai10/chrome-extension-es6-import@154b321 · GitHub

どうにかして、HTMLを起因としたjsのロードをしたい。

scriptタグのインジェクション

manifest.jsonの表現力では、どうにもcontent_scriptのjsをtype="module"でロードさせることができないので、<script>タグそのものをページのHTMLに挿入すればよかろう、という発想。

まず、manifest.jsonではinject.jsを読ませる

manifest.json

     "content_scripts": [
       {
         "matches": ["<all_urls>"],
-        "js": ["src/js/content.js"]
+        "js": ["src/js/inject.js"]
       }
     ],
     "permissions": [

inject.jsでは、<script>タグの動的挿入を行う。

src/js/inject.js

(() => {
  const src = chrome.extension.getURL('src/js/content.js');
  console.log(src);
  const script = document.createElement('script');
  script.setAttribute('src', src);
  script.setAttribute('type', 'module');
  document.body.appendChild(script);
})();

いい感じに動きそうだが、これでも以下のエラーが出る。

GET chrome-extension://invalid/ net::ERR_FAILED

どうやらネットワークっぽいエラーで、jsのpathが正しく指定されていないか、あるいはもっと別の原因が考えられる。なお、inject.jsconsole.logさせたsrcのURLをクリックすれば正しくcontent.jsの内容が見えるので、pathが正しく指定されていない、ということはなさそう。

web_accessible_resources を指定すればよい

manifest.jsonweb_accessible_resourcesというフィールドでは、ウェブからのリダイレクトなどの参照を許すChrome拡張内のリソースのパスを指定することができる。まさに今回、Chrome拡張側から見れば第三者の立場であるHTMLから、Chrome拡張内のリソースを<script src="...">でロードさせようとしているので、これに該当する。

このとき、content.jsだけではなく、content.jsを起因とするすべてのimportで参照されるリソースをweb_accessible_resourcesに指定する必要があるので、ワイルドカードを使った。

     ],
     "permissions": [
       "<all_urls>"
+    ],
+    "web_accessible_resources": [
+      "src/js/*"
     ]
 }

f:id:otiai10:20180327212500p:plain

いい感じに動いた。

ソースコードまとめ

github.com

懸念

  • node_modules以下にあるパッケージをどうやってimpotするか
    • full pathを書けばimportできるだろうけれど、Chrome拡張としてリリースビルドにどう含めるか
  • そもそもリリースビルドにnode_modules以下のすべてを含めるわけにはいかない

結論

webpack使お...

DRY

初めてのJavaScript 第3版 ―ES2015以降の最新ウェブ開発

初めてのJavaScript 第3版 ―ES2015以降の最新ウェブ開発

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター! 速習シリーズ

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター! 速習シリーズ