はじめに
こんにちは。ナルゲンボトル愛好家です。ふと思い立ってChrome拡張作ろうかなと思ったんですが、どうせならTypeScriptでやるのがいいじゃねえかってことでやりました。で、最近ブログ書いてないし、なんかまとめたらいい感じかなと思ったのでまとめます。
構成
. ├── dist // 生成された拡張 │ ├── context-menu.js │ ├── icons │ │ └── icon48.png │ └── manifest.json ├── gulpfile.js ├── .eslintrc.json ├── package.json ├── static │ ├── icons │ │ └── icon48.png │ └── manifest.json ├── ts │ └── src │ └── context-menu.ts // Chrome拡張をTypeScriptでやってくやつ └── tsconfig.json
毎回思うんですが、ちょっとのことやりたいだけなのに xxxx.json みたいな設定ファイルばっかりでほんとにだるい。だれかなんとかしてほしい。
下準備
typescript@2.0.0 を Visual Studio Code の参照先にする
あたりまえだけどまずTypeScriptが必要。今回は新しいやつを早く使いたかったんで @2.0.0 をグローバルに入れた。バージョン使い分けるほど使ってません。
$ npm i -g typescript@2.0.0
最近はエディタは軟派にVisual Studio Codeをよく使ってるんだけど、こいつがデフォルトで使うTypeScriptの設定を変えてやらないと新しい文法とか出てきた時にlintがうるさいので変えておく。Visual Studio CodeのUser Settingsでこんな感じの設定をしておく。ワークスペースごとに使うTypeScriptのバージョン違うという人がいたら、Workspace Settingにして、Workspaceのtypescriptを参照するようにしたらいいんじゃねえかと思いますが、やったことはありません。
"typescript.tsdk": "/Users/ymotongpoo/.nvm/versions/node/v6.3.0/lib/node_modules/typescript/lib"
Chrome Extension APIの型定義ファイルを参照する
TypeScriptの恩恵にあずかりたいので型定義ファイルを持ってくる。当然Chrome本体にモジュールはあるため、型定義ファイルだけあれば良いので、 id:otiai10 に感謝を唱えつつモジュールを落とす。
$ npm i @types/chrome
あとは普通に使えば良い。tsconfig.jsonとcontext-menu.tsはこんな感じでやっていく。tsconfig.json の compilerOptions
はChromeがES5で頼むって感じだったはずなので target
に気をつけるのと、あとでbrowserifyするんで module
は commonjs
にしときました。momentは単に今回使ったので特に重要じゃないです。
{ "compilerOptions": { "target": "ES5", "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "removeComments": false, "noImplicitAny": false }, "files": [ "./ts/src/context-menu.ts", "./node_modules/@types/chrome/index.d.ts", "./node_modules/@types/filesystem/index.d.ts", "./node_modules/@types/filewriter/index.d.ts", "./node_modules/@types/moment/index.d.ts" ] }
context-menu.tsでは参照しときましょう。
/// <reference path="../../node_modules/@types/chrome/index.d.ts" />
いい感じになった。
gulpの設定
grunt だとか gulp だとかなんか周辺ツール多すぎてホント嫌になってくるんですが、まあそういう形で回っちゃってるものはしょうがないので文句言いながら gulpfile.js 書きます。必要なパッケージを入れときます。
$ npm i -g --save-dev browserify $ npm i --save-dev vinyl-source-stream tsify gulp-jsmin $ npm i -u typescript@2.0.0
ローカルにもtypescript入れるのはtsifyでtypescriptモジュールをrequireしてるため。tsifyだけにしちゃうと依存してるデフォルトのバージョンが入っちゃうんでこうやってる。最初はgulp-typescript使ったりしてたんだけど、公式サイト見に行ったら使わないで一発でbrowserifyしてて楽だったので真似した。
const gulp = require('gulp'); const del = require('del'); const browserify = require('browserify'); const source = require('vinyl-source-stream'); const tsify = require('tsify'); const jsmin = require('gulp-jsmin'); const config = { browserify: { opts: { basedir: '.', entries: ['./ts/src/context-menu.ts'], cache: {}, packageCache: {}, debug: false } }, source: { target: 'context-menu.js' } }; gulp.task('copy', [], () => { return gulp.src('./static/**/*') .pipe(gulp.dest('./dist')); }); gulp.task('build', ['copy'], () => { return browserify([], config.browserify.opts) .plugin(tsify) .bundle() .pipe(source(config.source.target)) .pipe(gulp.dest('./dist')); }); gulp.task('minify', ['build'], () => { gulp.src(['./dist/**/*.js]) .pipe(jsmin()) .pipe(gulp.dest('./dist')); }); gulp.task('clean', [], () => { return del(paths.dist.dir); }); gulp.task('default', ['minify']);
使ってたmoment.jsの型定義ファイルだけインストールして、肝心のmomentパッケージ自体をインストールし忘れたことで、当然concatされないことを気付かずに悩むみたいなバカなことをしたけど、まあ動いちゃえば単純。
distをパッケージにする
普通にここに書いてあるとおりにやるだけです。Macな人はコマンドが若干異なるけどほぼ一緒です。
$ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' --pack-extension=dist
というわけで dist.crx
が出来て嬉しいですね。
おわりに
設定ファイル何個書かせるんだよ。めんどくさい。