まえがき
- nodeとかbowerとかgruntとかwebpackは適当に入れてください
- JSビギナーなのでおかしなことが書いてあるかもしれません(ツッコミ歓迎)
元々CoffeeScriptで書いたものをGruntでコンパイルしつつ開発していましたが、ファイルを分割する必要があり、分割するにあたってそれぞれの依存関係を解決する必要がありました(速度出てたのでブラウザコンパイラは使わず)。当初、RequireJSを使って分割作業を始めたのですが、r.js
を使ったコンパイルにハマって作業が滞り、「最近はwebpackなんてのもあるらしいよ」という元同僚の一声に乗っかりwebpack始めてみました。
システム全体は、Djangoで書かれたウェブアプリケーション、Ajax APIを使用するクライアントサイドアプリケーションという構成になります。
記述言語、コンパイル、結合、コピー、変更監視は次のようなツール構成で実現しています。
タスク | ツール | 備考 |
---|---|---|
言語 | CoffeeScript / JS | |
JSの結合 | grunt-webpack (webpack) | |
変更監視 | grunt-contrib-watch | webpackにも変更監視あるけど使いません |
ファイルコピー | grunt-contrib-copy |
ディレクトリレイアウト
クライアントサイドアプリケーションのソースコードはwww/src
以下に、bowerでインストールするライブラリ群はwww/components
以下に配置しています。www/resources
以下が実際の配布物という想定。
.
├── .bowerrc
├── Gruntfile.coffee
├── bower.json
├── package.json
└── www
├── components # bower
├── resources
│ ├── css
│ └── js
├── src
│ ├── loader.coffee # アプリケーション実行開始時に読み込む
│ ├── router.coffee # Backbone.Router
│ ├── models
│ ├── utils
│ └── views
└── webpack.config.js # 今回使わないwebpack
webpackの環境整備
node modules
必要なnodeモジュールをインストールします。
npm install coffee-script -g
npm install coffee-loader
npm install grunt -g
npm install webpack -g
npm install bower -g
以下は参考のpackage.jsonです。
{
"name": "testapp",
"version": "0.0.1",
"engines": [
"~0.11.14"
],
"repository": {
"type": "git",
"url": "git://example.com"
},
"author": "Mitsukuni Sato",
"devDependencies": {
"coffee-loader": "^0.7.2",
"coffee-script": "~1.8.0",
"grunt": "^0.4.5",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-coffee": "^0.12.0",
"grunt-contrib-cssmin": "^0.10.0",
"grunt-contrib-uglify": "^0.6.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-legacy-util": "^0.2.0",
"grunt-notify": "^0.4.1",
"grunt-webpack": "^1.0.8",
"underscore.string": "^2.3.3",
"webpack-dev-server": "^1.6.6"
},
"dependencies": {
"bower": "^1.3.12"
}
}
bower
Backboneに必要なモジュールはbowerからインストールします。.bowerrc
, bower.json
を書いてbowerからインストールし。
{
"directory": "www/components/",
"analytics": false,
"timeout": 30000,
"registry": {
"search": [
"https://bower.herokuapp.com"
]
}
}
{
"name": "testapp",
"version": "0.0.1",
"homepage": "https://example.com",
"authors": [
"Mitsukuni Sato <mitsukuni.sato@example.com>"
],
"license": "MIT",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"www/components/",
"test",
"tests"
],
"dependencies": {
"jquery": "~2.1.1",
"underscore": "~1.7.0",
"backbone": "~1.1.2"
}
}
bower install
Grunt
Gruntfileを書いてwebpackをビルドできるようにします。
"use strict"
# webpackのモジュールを呼び出しておく
path = require("path")
webpack = require('webpack')
tasks = ["webpack"]
module.exports = (grunt) ->
pkg = grunt.file.readJSON("package.json")
grunt.initConfig
pkg: pkg
# webpackのオプションをここに書く。
# webpack.config.jsと併用する場合、どちらを優先しておくか決めておくのが良さそう。
webpack:
app:
entry: "./www/src/loader.coffee" # コンパイル開始時に読み込むエントリファイル
output:
filename: "./www/resources/js/bundle.js" # 出力先ファイルパス
module:
loaders: [
{ test: /\.coffee$/, loader: 'coffee-loader' } # 拡張子coffeeはcoffee-loaderを使う
]
resolve:
root: [path.join(__dirname, "www/components")] # bowerのディレクトリを定義
plugins: [
new webpack.ResolverPlugin(
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
),
new webpack.ProvidePlugin({ # グローバル空間に読み込むモジュール?よく分かってません
$: "jquery",
jQuery: "jquery",
_: "underscore",
Backbone: "backbone"
})
]
stats:
colors: true
modules: true
reasons: true
progress: false
failOnError: false
watch: false # webpackで変更監視しません
keepalive: false
watch:
files: [
"www/src/**/*.coffee",
"www/components/**/*.js",
]
tasks: tasks
taskName = undefined
for taskName of pkg.devDependencies
grunt.loadNpmTasks taskName if taskName.substring(0, 6) is "grunt-"
grunt.registerTask "default", tasks
Backboneアプリケーション
loader.coffee
webpackのコンパイル時に初めに呼び出されるファイル。
require './router.coffee'
window.App =
Models: {}
Views: {}
Utils: {}
router.coffee
Backbone.Routerの定義。実質このファイルの処理からアプリケーションが開始される。
require './views/top.coffee'
jQuery ->
class App.Router extends Backbone.Router
routes:
'': 'top'
'pictures/:id': 'pictures'
top: ->
console.log('top', arguments)
new App.Views.TopView()
pictures: ->
console.log('pictures', arguments)
new App.Router()
Backbone.history.start({pushState: true})
views/top.coffee
サイト直下にアクセスした場合のビューを定義します。Apps.Models.PhotoModel
に依存するものとします(てきとうです)。
# 必要なモデルを呼び出し
require '../models/top.coffee'
jQuery ->
# Backboneオブジェクトは定義済みなのでrequire必要なし
class App.Views.TopView extends Backbone.View
initialize: ->
@
models/top.coffee
Apps.Models.PhotoModel
の定義(てきとうです)。
jQuery ->
class App.Models.PhotoModel extends Backbone.Model
idAttribute: 'id'
urlRoot: '/ajax/photos/'
parse: (response)->
return response.photo
コンパイル
手動でコンパイル
webpack.config.js
を用意していないのでgruntからコンパイルします。
grunt webpack
Running "webpack:app" (webpack) task
Version: webpack 1.4.13
Asset Size Chunks Chunk Names
./www/resources/js/bundle.js 460308 0 [emitted] main
[0] ./www/src/loader.coffee 86 {0} [built]
[1] ./www/src/router.coffee 2093 {0} [built]
(省略)
Done, without errors.
変更を監視してコンパイル
grunt-contrib-watch
をインストールしてCoffeeScriptの変更を監視し、変更時に自動的にコンパイルします。前述のGruntfile.coffee
にwatchタスクが定義されているので、grunt watch
を実行するだけで監視状態になります。
grunt watch