Expressで簡単なプロダクトを作る時のオレオレ最小構成です。
要件
- サーバーサイドもクライアントサイドもES2015(ES6)で書く
-
サーバーサイドはNode.jsがv4以上だとES2015で書けるはず
import
などが使えないと知ったので、babel-node
を使います - クライアントサイドJSはBrowserify + Babelifyでコンパイルする
- 開発時はWatchifyする
- ビルド時はUglifyする
-
- CSSはStylusで書く
- StylusはExpressのMiddlewareで都度コンパイルする
- ライブラリはkouto-swissを使う
- ベンダープレフィックスはautoprefixerでつける
- ViewはJadeで書く
- サーバーからJadeに変数を渡したりする
- Gulpなどのタスクランナーは使わない
-
$ npm run xxx
でやる - 画像のSprite化とかするならGulp使ったほうがいいでしょう
-
ディレクトリ構成
.
├── .gitignore
├── README.md
├── app.js
├── assets
│ ├── javascripts
│ │ ├── index.js
│ │ ├── index_dev.js
│ └── stylesheets
│ └── style.styl
├── package.json
└── views
└── index.jade
ディレクトリ構成はこんな感じです。
npm install
$ npm init
してからインストールするNode package一覧です。
Browserifyとかは$ npm install -g
しないと動かないかも。
$ npm install --save autoprefixer-stylus express jade jquery kouto-swiss path stylus
$ npm install --save-dev babel-cli babel-preset-es2015 babelify browserify uglifyjs watchify
$ npm install --global babel-cli babel-preset-es2015 babelify browserify uglifyjs watchify
ファイルのテンプレート
app.js
サーバーのJavaScrptです。
/
へのアクセスでindex
を返します。あとはres.render()
の中でViewに値を渡しています。
他はStylusを使う設定とか。
'use strict';
import express from 'express';
const app = express();
import path from 'path';
import stylus from 'stylus';
import koutoSwiss from 'kouto-swiss';
import autoprefixer from 'autoprefixer-stylus';
app.set('port', 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(stylus.middleware({
src: path.join(__dirname, 'assets'),
compile: (str, path) => {
return stylus(str)
.set('filename', path)
.set('compress', true)
.use(koutoSwiss())
.use(autoprefixer({ browsers: ['last 2 versions'] }))
;
}
}));
app.use(express.static(path.join(__dirname, 'assets')));
app.get('/', (req, res) => {
res.render('index', {
title: 'App Title',
description: 'App Description'
});
});
app.listen(app.get('port'), (error) => {
if (error) {
console.error(error);
} else {
console.info('listen:', app.get('port'));
}
});
assets/javascripts/index_dev.js
クライアントサイドのJavaScriptです。命名は自由だけど、コンパイル後のファイルがindex.js
なので、index_dev.js
にしました。同じファイル名でフォルダを分けたほうがいいかも。
jQueryを読みこんだり、ES2015の記法を使ったり。
'use strict';
window.jQuery = window.$ = require('jquery');
(() => {
const hello = () => {
const _message = 'Hello World!';
console.log(_message);
};
$(() => {
hello();
});
})();
views/index.jade
viewです。サーバーから送られたtitle
とdescription
を受け取り、表示しています。
テンプレートにOGPのmeta
タグも入れておくと、後でラク。
<!DOCTYPE html>
html(lang='ja', prefix='og: http://ogp.me/ns#')
head
meta(charset='UTF-8')
title!= title
meta(name='description', content='#{description}')
meta(name='robots', content='index,follow')
meta(name='viewport', content='width=device-width')
meta(property='og:title', content='#{title}')
meta(property='og:type', content='website')
meta(property='og:url', content='#{url}')
meta(property='og:description', content='#{description}')
meta(property='og:site_name', content='#{title}')
//- meta(property='og:image', content='#{url}/images/ogp.jpg')
meta(property='og:locale', content='ja_JP')
meta(name='twitter:card', content='summary')
link(rel='stylesheet', href='stylesheets/style.css')
script(src='javascripts/index.js')
body
h1 #{title}
p #{description}
.babelrc
Babelifyの設定ファイルです。ES2015のモジュールを読み込みます。
{
"presets": ["es2015"]
}
npm run-script
$ npm run xxx
で実行するコマンドです。package.json
に書きます。
{
"scripts": {
"build": "browserify -t babelify assets/javascripts/index_dev.js -o assets/javascripts/index.js",
"watch": "npm run build && watchify -d -t babelify assets/javascripts/index_dev.js -o assets/javascripts/index.js -v",
"build:prod": "npm run build && uglifyjs assets/javascripts/index.js --stats -o assets/javascripts/index.js",
"start": "babel-node app.js"
}
}
- 開発時は
$ npm start
でサーバーを起動して、別プロセスで$ npm run watch
をします。index_dev.js
の変更が監視され、都度index.js
が出力されます。-
$ npm start
ではnode app.js
ではなくbabel-node app.js
を実行します。babel-node
だと、ES2015のimport
などが使えるようになります(Node.js v4以降でもlet
やconst
、アロー関数は使えますが)。
-
- 本番用のビルドは
$ npm run build:prod
を実行します。BrowserifyとUglifyが実行されます。 -
Sourcemap忘れてた…。余力があれば書き出すようにする(CSS/JSどっちも)- JSだけSourcemap出力します(
npm run watch時
) - StylusのSourcemapがなぜか出力できない、謎
- JSだけSourcemap出力します(
- ESLintも忘れてるので、おいおい
まとめ
以下の最小構成のようにもっとコンパクトにできるけど、なにか作るかとなると結局こんな感じになるかな、と。JSをES5で書いてStylusを使わずに生CSSで書けばもっとコードは減らせますが、実際辛い。
ここから、ルーティングやエラー処理を加えたり、処理が増えたらJSを分割するなどをしていけばいいかなと思います。