この記事は FUJITSU Advent Calendar 2017 part2 の13日目です。
最近困っていたこと
最近、デモ用のWebアプリを作る機会が増えてきて、以下のことに困っていました。
- アプリをシンプルに作ったつもりが、使いまわしを考慮してないので、別件を頼まれたときに、新規にアプリケーションプロジェクトを作る羽目になる。
- そのため
- アプリとしての体裁を整えるまでに時間がとられ、見た目含めクオリティが上がらない。
- 作り方を思い出すまでに時間がかかる。
- 新しいことを試したい欲求にかられる。
- そのため
- 他の人が作ったときのクオリティにばらつきが出る。
- デモアプリなので、内部のコードは汚くていいという心理が働く。
それぞれ言い訳をする。
- 突発的に頼まれたりしたときに、後先考えずに作ってしまう。
- 新規にプロジェクトを作って、ある程度アプリとしての体裁を整えるまでが時間がかかる。一番面倒。
- 前に作ったのをコピペしただけのはずなのに動かないことがある。
- 製品ならば、引継ぎ資料などを作りますが、デモ用なので、個人技でホイっと作ってしまう。
- 自家製の
汚いソースを作ってしまい、後で誰かに渡すのが申し訳ないと考えてしまう。
改善したいポイント
- 毎回、レベル1からのスタートはつらい。せめて、"強くてニューゲーム"を
⇒ プロジェクトをcloneし、コマンドを実行(npm installとgulp)するだけで、最低限の動きは保証。作り込みたい場所、差し替えればよい場所を誘導するアプリケーションプロジェクトを布教する。- 同時に以下にも対応。
- 新しいことを試したい欲求。
- 汚いコードの除去。
- 同時に以下にも対応。
+α(ちょっとした願望) 新人にも少しずつ触れてもらい、Webアプリに慣れていってほしい。
// 残りの課題について。
- 人間なので、忘れるのは仕方がない。
以上から、自分なりに使いまわしを想定したプロジェクトを考えてみた。
準備
- Node.js・・・stableで良い。
- gulpとbrowser-syncはインストール済みであること
$ npm install -g gulp browser-sync
npm install 前に、Proxy設定を確認。参考
技術選定
モバイル利用も想定して、SPAにすること前提で選定します。
ターゲットは、普段Webアプリを書いてない人。
- フレームワーク
-
Riot.js
- 今回、v3.7.4を利用
- SPAの設定が簡単
- タグベースのコンポーネント指向
- scoped cssがある
- ファイルが軽い
- ドキュメントが日本語対応してる
-
Riot.js
- HTMLテンプレートエンジン
-
pug
- ファイル分割と、HTML/CSS/JSをincludeできる。
- 記述量が減らせる。
- もし、Pugが覚えられず、htmlで書いても許される。(しつこいですが、includeだけは使ってください。ごちゃまぜでも大丈夫)
- ゴリラでもわかる
-
pug
- タスクランナー
-
gulp
- pugの実行や集約を任せる
- 各Alt系のビルド(必要なら)
-
gulp
テスト関連の話は今回触れません。
ビルドタスクの全体イメージ
画像のように、PostCSSやTypeScriptなど、Alt系をビルドしてから、Pugのincludeを利用し、CSSとJavaScriptを取り込んだHTMLを生成します。(Alt系を使わない場合は、真ん中の列(Pug+CSS+JS)だけやればよいです。今回、サンプルで紹介するソースにはpostcss/typescriptは出てきません。)
pugをビルドすると、デフォルトで拡張子がhtmlになります。拡張子を変えたい場合は各自変更してください。筆者は.tagに変更し、
dist/tag/
にコピーしてます。
プロジェクト構成
以下のようにしてみました。
<project_root>/
┣━assets/ ライブラリや変更を加えないファイルを格納
┣━dist/ ビルド後の資産格納
┃ ┣━css/
┃ ┣━tag/ pugをビルドした後のファイルを格納
┃ ┣━js/
┃ ┗━index.html
┣━node_modules/ 使用するnode_moduleを格納
┣━src/ 変更を加えるファイルを格納
┃ ┣━css/ postcsファイルの格納
┃ ┣━pug/ pugファイルのみ格納
┃ ┣━ts/ TS or JSファイルの格納
┃ ┗━index.html 開発序盤のライブラリの入れ替えを想定。src直下に置く。
┣━tmp postcss/tsのビルド後の資産を一時格納
┃ ┣━ css/ ビルド後のCSS一時格納
┃ ┗━ js/ ビルド後のJS一時格納
┣━ .gitignore
┣━ gulpfile.js
┗━ package.json
pugのビルド後、ビルド後資産格納領域dist/
に格納、この時、assets/
に入れた、ライブラリもコピー・格納します。
格納後、サーバーを起動、テスト環境なら、browser-syncを使いましょう。
ライブリロードを活用した開発はオススメです。参考URL:Browsersyncを利用してお手軽ブラウザ確認環境をつくろう
//browser-syncの起動
gulp.task('setupBrowserSync', function () {
browserSync({
server: {
baseDir: "./dist/"
}
});
});
// src/以下の資産の変更を検知すると、ビルドして、参照しているブラウザをリロードします。
gulp.task('watch', ['prepareBuild','setupBrowserSync'], function (cb) {
gulp.watch(["./src/**"], function () {
return runSequence(
// 'build_PostCss', //PostCSSのビルド
// 'build_TS', // TypeScriptのビルド
'build_Pug', // Pugのビルド
'copyExceptionFiles', // 例外的なファイルのコピー(index.htmlなど)
'reload' // browser-syncの強制更新
);
});
});
gulp.task('prepareBuild', function (cb) {
// 省略: watchのrunSequenceと同じ順でタスクを実行(reloadは不要)
});
タスクの実行順が重要です。run-sequenceを使用し、実行順を制御してください。
実装側
index.html
headerタグはheadernav.tagを固定参照、mainタグは各パスの情報を見て切り替わります。
具体的には、ルート以下が/
、/#default
のとき、default.tag
を使用、
/#content
のとき、content.tag
を使用します。
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>sample</title>
</head>
<body>
<header></header>
<main></main>
<!-- 利用するtagファイルを以下のようにして、取り込みます。 -->
<script type="riot/tag" src="tags/headernav.tag"></script>
<script type="riot/tag" src="tags/content.tag"></script>
<script type="riot/tag" src="tags/default.tag"></script>
<script src="assets/js/libs/riot+compiler.min.js"></script>
<script src="assets/js/libs/route.min.js"></script>
<script>
// SPAのルーティングの設定。ヘッダー部
route(function (tagName) {
riot.mount('header', 'headernav');
});
// SPAのルーティングの設定。メイン部
route(function (tagName) {
tagName = tagName || 'default';
riot.mount('main', tagName);
});
route.start(true);
</script>
</body>
</html>
default.pug
defaultページのpugファイルのサンプルです。今回、css、jsの参照先は、default.pugから相対座標で指定してます。
default
style
include ../../tmp/css/default.css
h1.test
a(href="#content") gotoContentPage
.default_container
button(onclick="{sayHello}") Hello
script
include ../../tmp/js/default.js
css、jsのinclude先を変えるだけで、過去の負の遺産を封印したり、新しいことを試したときに、実験コードに入れ替えができます。
これだけで、新しいことを試したい欲求。汚いコードの除去の両方達成
webpackだと、loaderに引っかかったり、ファイルの退避が必要になってしまうこともあります。
content.pug
defaultページにあるリンクの遷移先のファイルです。
content.css
とcontent.js
は省略します。
content
style
include ../../tmp/css/content.css
h1.test
a(href="#") goBackDefaultPage
include ../../tmp/js/content.js
default.css
dafault.pugで使用するcss
.test{
color:red;
}
.default_container{
width:100%;
padding-top:25px;
}
.default_container>button{
width:200px;
height:40px;
}
default.js
default.pugで使用するJS
// this. で書くのはriotのお作法。
this.sayHello=function(){
alert("Hello");
}
おわりに
Pugの使い方を見て、webpackで良くないか?ReactやAngular、Vueで良いのでは?と思う人もいると思います。筆者もこれを考え始めた当初、その線で考えていました。
しかし、今回、ターゲットとしたのが、普段Webアプリをやってない人ということで、デバッグさせるとき、webpack使わせるのも酷なのと(ソースマップがあればよいが)、筆者がgulpならまだマシ(人間が把握しきれる)という主観の元、この構成にしました。
別の狙いとして、browser-syncを使ったWebアプリの開発速度に毒したかったというのがあります。
riotについては、今回のパターンに都合がよかったのと、単に使ってみたい欲にかられました。
反省点
- 実はけっこうガチなのを作ってありますが、自部署の製品向けに作りこみ過ぎてしまって、この記事を書くときに、プロジェクトを作り直しました。
- もっとぶっ飛んだ記事を書きたい。JavaScriptで~~をやってみたとか。(それやる意味あった?と突っ込みがあるぐらいの)