material-iconsをchrome拡張のcontent-scriptで使用する方法
環境を整える
開発環境を整えます。
今回使うライブラリは以下のものを使います。
"dependencies": { "css-loader": "^2.1.1", "file-loader": "^3.0.1", "jquery": "^3.4.1", "material-icons": "^0.3.1", "webpack": "^4.32.2", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", "ts-loader": "^6.2.1", "typescript": "^3.7.3", "url-loader": "^1.1.2", }
他にも依存関係を使っているのですが、細かいところは省いています。
webpack
を使ってtypescript
で書かれたスクリプトをビルドして、それを拡張機能として利用します。
また、content-script
を使って画面を拡張してmaterial-icons
のアイコンを表示します。
webpackの設定を行う
module.exports = { module: { rules: [ { test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: [ { loader: 'url-loader?limit=10000&name=../fonts/[name].[ext]', } ] }, { test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/, use: [ { loader: 'file-loader?name=../fonts/[name].[ext]', } ] }, ] } }
ここで大事なのはloader
の部分です。
name
を指定することで出力時のwoff
ファイルがfonts/MaterialIcons-Regular.woff
とのようになります。
出力時のpathはwebpack.config
のあるディレクトリがルートとなります。
これを行わない場合、ファイル名がhashとなります。
そうすると、画面上でwoff
等を読み込むのが難しくなります。
※ build時に再度生成されるため、毎回書き直す必要が出てきます。
manifest.jsonを設定する
{ "content_scripts": [ { "run_at": "document_end", "matches": ["*://*/*"], "js": [ "./assets/js/content.bundle.js" ] } ], "web_accessible_resources": [ "assets/fonts/MaterialIcons-Regular.eot", "assets/fonts/MaterialIcons-Regular.ttf", "assets/fonts/MaterialIcons-Regular.woff", "assets/fonts/MaterialIcons-Regular.woff2" ], }
このようになります。
ここで重要なのは、web_accessible_resources
にフォント用のファイルを書いていることです。
(ワイルドカード*
を使っても良いですが、使えるリソースを把握するのにすべて書いたほうが良いと考えてこのようにしています。)
これを行うことで、画面上からリソースを使用することができます。
このパラメータについてはManifest - Web Accessible Resourcesを参照するのが良いです。
リソースを扱う場合は以下のようにurlを書かなければなりません。
chrome-extension://[PACKAGE ID]/[PATH]
web_accessible_resources
を使わない場合material-icons
で使用するwoff
などが以下のように読み込まれます。
https://[domain]/~.woff
もちろんそのページで.woff
を使用していない限り、これはエラー(404)となります。
もう一点重要な点があります。
"assets/fonts/MaterialIcons-Regular.eot",
リソースの書き方です。
最初は以下のように相対パスで実装していました。
{ "web_accessible_resources": [ "./assets/fonts/MaterialIcons-Regular.eot", ] }
これは動きませんでした。
原因はわかりませんでした。
予想ではリソースの読み込み時に利用するurlが異なるからです。
画面に@font-faceを埋め込む
manifest
の設定時に解説した通り、リソースを利用する場合は以下のように使用する必要があります。
chrome-extension://[PACKAGE ID]/[PATH]
このパスを作成するのに必要なのが、拡張機能のIDです。
IDは開発時と配信時に別のIDが付けられるため、ハードコーディングでは対応できません。
googleはこのurlを作成するための機能を用意しています。
以下を使用します。
chrome.extension.getURL("");
getURL("hoge.png")
を利用することでchrome-extension://[PACKAGE ID]/hoge.png
とうurlを取得できます。
以上を踏まえて、画面上に@font-face
を<style>
として埋め込みます。
function makeFontFace() { let woff2 = chrome.extension.getURL("assets/fonts/MaterialIcons-Regular.woff2"); let woff = chrome.extension.getURL("assets/fonts/MaterialIcons-Regular.woff2"); let ttf = chrome.extension.getURL("assets/fonts/MaterialIcons-Regular.woff2"); let newStyle = document.createElement('style'); newStyle.textContent = '\ @font-face {\ font-family: "Material Icons TestExtension";\ font-style: normal;\ src: url("' + woff2 + '") format("woff2"),\ url("' + woff + '") format("woff"),\ url("' + ttf + '") format("truetype");\ }' document.head.appendChild(newStyle); }
これで画面上からリソースを利用できるようになります。
jquery
使ってないというツッコミはなしでお願いします。
ここで重要なのはfont-family
の値として、Material Icons TestExtension
としていることです。
もし画面上でMaterial Icons
を使っていた場合、コンフリクトが発生する可能性があります。
あとはこの関数を実行するだけです。
cssを追加する
私の場合はscss
を使っています。が、sassの場合は読み替えてください。
.test-extension { .material-icons { font-family: "Material Icons TestExtension"; font-weight: normal; font-style: normal; font-size: 24px; display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; /* Support for all WebKit browsers. */ -webkit-font-smoothing: antialiased; /* Support for Safari and Chrome. */ text-rendering: optimizeLegibility; /* Support for Firefox. */ -moz-osx-font-smoothing: grayscale; /* Support for IE. */ font-feature-settings: 'liga'; } }
重要なのは、Material Iconsに書かれているように以下のように使用しないことです。
$material-icons-font-path: '~material-icons/iconfont/'; @import '~material-icons/iconfont/material-icons.scss';
このようにすると、せっかく参照できるようにしたリソースファイルを利用してくれません。
ちなみに、上記のスタイルは以下のファイルを参考にしました。
node_modules/material-icons/iconfont/material-icons.css
まとめ
やることは以下のことです。
- リソースを登録する
- @font-faceを埋め込む
- material-iconsのスタイルを独自に用意する
以上です。
これを解決するのに1日かかってしまいました。
だれかの参考になれば幸いです。