YeomanをつかったChrome extension開発のメモ

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
view raw install.sh hosted with ❤ by GitHub

引き続いて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
view raw generate.sh hosted with ❤ by GitHub

これで以下のような環境が構築される。

├── .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
view raw tree.sh hosted with ❤ by GitHub

個人的に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というサービスでもひな形だけであれば作成できる。

Comments