Chrome extension開発にYeoman generator-chrome-extensionを使用したときのメモ。
とりあえず、Yeomanと、gegneratorをinstallする。ちなみにbower、grunt-cliはYeomanインストール時にインストールされる。
テストランナーはmochaなのでインストール。
npm install -g yo mocha | |
npm install -g generator-chrome-extension | |
# USE COMPASS | |
gem install compass |
引き続いてgeneratorを実行。
作成するExtentionのタイプに合わせて各項目は選択できる。
cd YOUR-EXTENSION | |
yo chrome-extension | |
[?] What would you like to call this extension? YOUR-EXTENSION-NAME | |
[?] How would you like to describe this extension? YOUR-EXTENSION-DESCRIBE | |
[?] Would you like to use UI Action? (Use arrow keys) | |
❯ No | |
Browser | |
Page | |
[?] Would you like more UI Features? (Press <space> to select) | |
❯⬡ Options Page | |
⬡ Content Scripts | |
⬡ Omnibox | |
[?] Would you like to use permissions? (Press <space> to select) | |
❯⬡ Tabs | |
⬡ Bookmarks | |
⬡ Cookies | |
⬡ History | |
⬡ Management | |
create app/manifest.json | |
create app/scripts/background.js | |
create app/_locales/en/messages.json | |
create app/styles/main.css | |
create app/images/icon-16.png | |
create app/images/icon-128.png | |
create package.json | |
create bower.json | |
create .bowerrc | |
create .editorconfig | |
create .gitignore | |
create .gitattributes | |
create .jshintrc | |
create Gruntfile.js | |
invoke mocha:app | |
create test/index.html | |
create test/lib/chai.js | |
create test/lib/expect.js | |
create test/lib/mocha/mocha.css | |
create test/lib/mocha/mocha.js | |
create test/spec/test.js | |
これで以下のような環境が構築される。
├── .bowerrc | |
├── .editorconfig | |
├── .gitattributes | |
├── .gitignore | |
├── .jshintrc | |
├── Gruntfile.js | |
├── app | |
│ ├── _locales | |
│ ├── bower_components | |
│ ├── images | |
│ ├── manifest.json | |
│ ├── scripts | |
│ └── styles | |
├── bower.json | |
├── node_modules | |
│ ├── .bin | |
│ ├── grunt | |
│ ├── grunt-chrome-manifest | |
│ ├── grunt-concurrent | |
│ ├── grunt-contrib-clean | |
│ ├── grunt-contrib-coffee | |
│ ├── grunt-contrib-compass | |
│ ├── grunt-contrib-compress | |
│ ├── grunt-contrib-concat | |
│ ├── grunt-contrib-connect | |
│ ├── grunt-contrib-copy | |
│ ├── grunt-contrib-cssmin | |
│ ├── grunt-contrib-htmlmin | |
│ ├── grunt-contrib-imagemin | |
│ ├── grunt-contrib-jshint | |
│ ├── grunt-contrib-uglify | |
│ ├── grunt-contrib-watch | |
│ ├── grunt-mocha | |
│ ├── grunt-open | |
│ ├── grunt-svgmin | |
│ ├── grunt-usemin | |
│ ├── load-grunt-tasks | |
│ └── time-grunt | |
├── package.json | |
└── test | |
├── index.html | |
├── lib | |
└── spec |
個人的にcoffeeで使いたいので、Gruntfileをcoffeeにで使う。
# jshint camelcase: false | |
# Generated on 2013-11-24 using generator-chrome-extension 0.2.5 | |
'use strict' | |
mountFolder = (connect, dir) -> | |
connect.static require('path').resolve(dir) | |
# # Globbing | |
# for performance reasons we're only matching one level down: | |
# 'test/spec/{,*/}*.js' | |
# use this if you want to recursively match all subfolders: | |
# 'test/spec/**/*.js' | |
module.exports = (grunt) -> | |
# show elapsed time at the end | |
require('time-grunt')(grunt) | |
# load all grunt tasks | |
require('load-grunt-tasks')(grunt) | |
# configurable paths | |
yeomanConfig = | |
app: 'app' | |
dist: 'dist' | |
grunt.initConfig | |
yeoman: yeomanConfig | |
watch: | |
options: | |
spawn: false | |
coffee: | |
files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'] | |
tasks: ['coffee:dist'] | |
coffeeTest: | |
files: ['test/spec/{,*/}*.coffee'] | |
tasks: ['coffee:test'] | |
compass: | |
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'] | |
tasks: ['compass:server'] | |
html: | |
files: ['<%= yeoman.app %>/{,*/}*.html'] | |
tasks: ['build'] | |
connect: | |
options: | |
port: 8080 | |
# change this to '0.0.0.0' to access the server from outside | |
hostname: 'localhost' | |
test: | |
options: | |
middleware: (connect) -> | |
return [ | |
mountFolder(connect, '.tmp'), | |
mountFolder(connect, 'test') | |
] | |
clean: | |
dist: | |
files: [ | |
dot: true | |
src: [ | |
'.tmp', | |
'<%= yeoman.dist %>/*', | |
'!<%= yeoman.dist %>/.git*' | |
] | |
] | |
app: '<%= yeoman.app %>/scripts/{,*/}*.js' | |
server: '.tmp' | |
jshint: | |
options: | |
jshintrc: '.jshintrc' | |
all: [ | |
'.tmp/scripts/{,*/}*.js' | |
'dist/scripts/{,*/}*.js' | |
] | |
mocha: | |
all: | |
options: | |
run: true | |
urls: ['http://localhost:<%= connect.options.port %>/index.html'] | |
reporter: 'Nyan' | |
coffee: | |
# https://github.com/ragingwind/grunt-chrome-manifest/issues/6 | |
dist: | |
files: [ | |
expand: true | |
cwd: '<%= yeoman.app %>/scripts' | |
src: '{,*/}*.coffee' | |
dest: '.tmp/scripts' | |
ext: '.js' | |
] | |
test: | |
files: [ | |
expand: true, | |
cwd: 'test/spec' | |
src: '{,*/}*.coffee' | |
dest: '.tmp/spec' | |
ext: '.js' | |
] | |
compass: | |
options: | |
sassDir: '<%= yeoman.app %>/styles' | |
cssDir: '.tmp/styles' | |
generatedImagesDir: '.tmp/images/generated' | |
imagesDir: '<%= yeoman.app %>/images' | |
javascriptsDir: '<%= yeoman.app %>/scripts' | |
fontsDir: '<%= yeoman.app %>/styles/fonts' | |
importPath: '<%= yeoman.app %>/bower_components' | |
httpImagesPath: '/images' | |
httpGeneratedImagesPath: '/images/generated' | |
relativeAssets: false | |
dist: {} | |
server: | |
options: | |
debugInfo: true | |
# not used since Uglify task does concat, | |
# but still available if needed | |
# concat: | |
# dist: {} | |
# not enabled since usemin task does concat and uglify | |
# check index.html to edit your build targets | |
# enable this task if you prefer defining your build targets here | |
# uglify: | |
# dist: {} | |
# https://github.com/yeoman/generator-webapp/issues/12 | |
useminPrepare: | |
options: | |
dest: '<%= yeoman.dist %>' | |
html: [ | |
'<%= yeoman.app %>/popup.html', | |
'<%= yeoman.app %>/options.html' | |
] | |
usemin: | |
options: | |
dirs: ['<%= yeoman.dist %>'] | |
html: ['<%= yeoman.dist %>/{,*/}*.html'] | |
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'] | |
imagemin: | |
dist: | |
files: [ | |
expand: true, | |
cwd: '<%= yeoman.app %>/images' | |
src: '{,*/}*.{png,jpg,jpeg}' | |
dest: '<%= yeoman.dist %>/images' | |
] | |
svgmin: | |
dist: | |
files: [ | |
expand: true, | |
cwd: '<%= yeoman.app %>/images' | |
src: '{,*/}*.svg' | |
dest: '<%= yeoman.dist %>/images' | |
] | |
cssmin: | |
dist: | |
files: | |
'<%= yeoman.dist %>/styles/main.css': [ | |
'.tmp/styles/{,*/}*.css', | |
'<%= yeoman.app %>/styles/{,*/}*.css' | |
] | |
htmlmin: | |
dist: | |
options: | |
removeCommentsFromCDATA: true | |
# https://github.com/yeoman/grunt-usemin/issues/44 | |
collapseWhitespace: true | |
collapseBooleanAttributes: true | |
removeAttributeQuotes: true | |
removeRedundantAttributes: true | |
useShortDoctype: true | |
removeEmptyAttributes: true | |
removeOptionalTags: true | |
files: [ | |
expand: true | |
cwd: '<%= yeoman.app %>' | |
src: '*.html' | |
dest: '<%= yeoman.dist %>' | |
] | |
# Put files not handled in other tasks here | |
copy: | |
dist: | |
files: [ | |
expand: true | |
dot: true | |
cwd: '<%= yeoman.app %>' | |
dest: '<%= yeoman.dist %>' | |
src: [ | |
'*.{ico,png,txt}', | |
'images/{,*/}*.{webp,gif}', | |
'_locales/{,*/}*.json' | |
] | |
, | |
expand: true | |
cwd: '.tmp/images' | |
dest: '<%= yeoman.dist %>/images' | |
src: [ | |
'generated/*' | |
] | |
] | |
concurrent: | |
server: [ | |
'coffee:dist', | |
'compass:server' | |
] | |
test: [ | |
'coffee', | |
'compass' | |
] | |
dist: [ | |
'coffee', | |
'compass:dist', | |
'imagemin', | |
'svgmin', | |
'htmlmin' | |
] | |
chromeManifest: | |
dist: | |
options: | |
buildnumber: true | |
background: | |
target: 'scripts/background.js' | |
src: '<%= yeoman.app %>' | |
dest: '<%= yeoman.dist %>' | |
compress: | |
dist: | |
options: | |
archive: 'package/extension.zip' | |
files: [ | |
expand: true | |
cwd: 'dist/' | |
src: ['**'] | |
dest: '' | |
] | |
grunt.registerTask 'test', [ | |
'clean:server', | |
'concurrent:test', | |
'connect:test', | |
'mocha' | |
] | |
grunt.registerTask 'build', [ | |
'clean:dist', | |
'chromeManifest:dist', | |
'useminPrepare', | |
'concurrent:dist', | |
'jshint', | |
'cssmin', | |
'concat', | |
'uglify', | |
'copy', | |
'usemin' | |
'compress' | |
] | |
grunt.registerTask 'default', [ | |
'jshint', | |
'test', | |
'build' | |
] |
Grunt pluginとGruntタスクはそれぞれ次のタスクを実行する。
load-grunt-tasksでpackage.jsonのdependencies/devDependencies/peerDependencies のpluginを自動的に読込む。これで
grunt.loadNpmTasks を省略できる。
chromeManifestはmanifest.jsonをもとにbackground.jsとcontent_script.jsについてファイル結合とCSSとJavaScriptの圧縮を行う。
タスク実行の度にバージョン番号をアップデートすることも可能。
useminPrepareタスクはhtmlファイルにあるコメント箇所を認識してファイルの結合と圧縮を行う。
例えば.tmpディレクトリ内のscripts/config.jsとscripts/popup.jsを結合、圧縮したファイルをscripts/popup.jsに生成する場合は
<!-- build:js(.tmp) scripts/popup.js --> | |
<script src="scripts/config.js"></script> | |
<script src="scripts/popup.js"></script> | |
<!-- endbuild --> |
となる。
concurrentはsass,compassやcoffeeのコンパイルのような時間を要するタスクを同時に行う。gruntの実行時間を短縮できる。
Gruntfileのbuildタスクは最終的にpackageディレクトリにzip圧縮された状態でextentionファイルを生成する。
Chrome Extension自体は難しいものではないけど、しっかりした開発環境をgenerator-chrome-extensionで作成することでより快適に開発できそう。
ちなみにextensionizrというサービスでもひな形だけであれば作成できる。