サーバー/クライアントを両方jsないしcoffeeで書くときの、ディレクトリ構造や、Gruntfileのサンプルがあまりみつからなかったので自分で実施しはじめている内容をまとめてみる。
ディレクトリ構造は以下のようにした。
coffee-scriptのソースは、src/ に全て入れ、client/ server/ でディレクトリを分ける。
.
├── Gruntfile.coffee
├── README.md
├── app.coffee
├── component.json
├── lib
├── package.json
├── public
│ ├── css
│ ├── img
│ └── js
├── src
│ ├── client
│ └── server
└── views
分けておくと、Gruntfileで以下のようにclientとserverでビルドターゲットを分けることがけっこう簡単にできる。
module.exports = (grunt) ->
grunt.initConfig
pkg: grunt.file.readJSON('package.json')
coffee:
server:
files: [
{
'app.js': 'app.coffee'
}, {
expand: true,
cwd: 'src/server',
src: ['**/*.coffee'],
dest: 'lib/',
ext: '.js'
}
]
client:
options:
bare: false
files: [
{
expand: true,
cwd: 'src/client',
src: ['*.coffee'],
dest: 'public/js/lib/',
ext: '.js'
}
]
concat:
options:
separator: ";"
vendor:
src: [
'components/underscore/underscore-min.js',
'components/jquery/jquery.min.js',
'components/backbone/backbone-min.js'
],
dest: "public/js/vendor.js"
app:
src: ["public/js/lib/**/*.js"]
dest: "public/js/app.js"
uglify:
options:
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
app:
files:
'public/js/app.min.js': ['<%= concat.app.dest %>']
watch:
src_server:
files: ['app.coffee', 'src/server/**/*.coffee']
tasks: ['coffee:server']
src_client:
files: ['src/client/**/*.coffee']
tasks: ['coffee:client', 'concat:app']
grunt.loadNpmTasks('grunt-contrib-uglify')
grunt.loadNpmTasks('grunt-contrib-coffee')
grunt.loadNpmTasks('grunt-contrib-concat')
grunt.loadNpmTasks('grunt-contrib-watch')
grunt.registerTask 'default', ['coffee', 'concat', 'uglify']
grunt.registerTask 'server', ['coffee:server']
grunt.registerTask 'client', ['coffee:client', 'concat:app']
watchもターゲットも分けておくと、クライアントのソースを保存したときにサーバもコンパイルされるなどの無意味なタスクが走らなくなるので良い。
ちなみに自分は、人の5倍くらいの回数ファイルを保存するので、watchは使ってない。
gruntは、rakeとかとちがって、プロジェクトのサブディレクトリからでもgruntコマンドを叩けるので、自分でemacsからタスクを叩けるように設定している。
(defun grunt-for-build ()
"coffee-script compile for grunt task"
(interactive)
(let ((cur-dir (expand-file-name default-directory)))
(compile
(if (string-match "/\\(server\\|client\\)s?/" cur-dir)
(concat "grunt " (match-string 1 cur-dir))
"grunt"))))
(define-key coffee-mode-map (kbd "C-c C-l") #'grunt-for-build)
こちらも、クライアント/サーバどっちのディレクトリに居るかによって、ターゲットを分けて実行している。