まず、リソースコンパイルについて
最近、フロントエンドのリソースを開発する上で、様々なコンパイラを使用することが増えている気がします。
具体的には、
- JS・JSX
- Browserifyとbabelでモジュール管理・ES6・JSX
- CSS
- sassやpostcssやらautoprefixerで変換
- HTML
- テンプレートエンジンで変換
HTMLで管理してみる
上の図で、「コンパイル処理」って書かれているものが、browserifyやbabelなどの処理で、基本的には、ストリームで読み込んで、吐き出すだけの共通処理を実装すればいいと思っています。
(コマンドラインの標準入出力でもOK)
Webサーバーには、mimeタイプなどで判定してコンパイルする処理を埋め込みます。
リリース時に流す処理は、それとは別で、htmlを読み込ませて、linkタグやscriptタグをもとに、読み込み⇒コンパイル⇒Bundleという風な処理をさせます。
HTMLは、このようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>タイトル</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://hostname//framework-1.2.3.css" rel="stylesheet">
<link href="css/1.css" rel="stylesheet">
<link href="css/2.css" rel="stylesheet">
<link href="css/3.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="https://hostname/framework-1.2.3.js"></script>
<script src="js/1.js"></script>
<script src="js/2.js"></script>
<script src="js/3.js"></script>
</body>
</html>
↓
<!DOCTYPE html>
<html lang="ja">
<head>
<title>タイトル</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="bundle.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
deferやasyncを使う場合を除けば、HTMLは上から順に読み込んでいくだけです。
ならば、linkタグとscriptタグを上から順に読み込み、コンパイル処理をし、bundleするだけで同じ挙動になるはず。(cheerioとか使えば、簡単そう)
cdnなどのリモートファイルもそのまま読み込んで一つにまとめちゃう。
開発時は、ファイルバラバラで、コンパイル処理もさせて、開発用のWebサーバーに負担かかるけど、リリース時に解消しちゃえばいいよねって考え方。
メリット
- 開発時のコンパイルは、Webサーバーに任せ、タスクランナーは使わなくて済む
- リソースのパスはHTMLで管理できる
- CDNのファイルとかもまとめられる(本番環境は、ネットにつながっていない場合がある)
- コンパイルの処理は、タスクランナーのプラグインでない為、使いまわしやすい
デメリット
- リリース時には、サーバーサイドのコンパイル処理をはずす必要がある
- リリース時には、ソースマップとかは、はずす必要がある
実際にやってみるとしたら
せっかくcheerio使うなら、<part>タグなんて読み込めるようにして…
(実装簡単そう)
<!DOCTYPE html>
<html lang="ja">
<head>
<title>タイトル</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/1.css" rel="stylesheet" async>
<link href="css/1.css" rel="stylesheet" defer>
<link href="https://hostname//framework-1.2.3.css" rel="stylesheet">
<link href="css/2.css" rel="stylesheet">
<link href="css/3.css" rel="stylesheet">
</head>
<body>
<part src="part/header.html">
<div id="app"></div>
<part src="part/footer.html">
<script src="https://hostname/framework-1.2.3.js"></script>
<script src="js/1.js"></script>
<script src="js/2.js"></script>
<script src="js/3.js"></script>
</body>
</html>
コンパイル処理
const compile = require('compile-tool')
let config = {
// Expressのstaticとかの為に
prefix: "static/base",
// コンパイル前のテンプレートエンジンがあれば指定
templateEngine: function(file, cb) {
// パスとバッファを格納
let buffer = file.buffer
let path = file.path
this.push(//コンパイル後のBuffer)
// 最後は、コールバックを呼び出し
cb()
},
// 拡張子ごとのコンパイラを指定(インターフェイスは、templateEngineに渡す関数と同じ)
compilers: {
"js": jsCompiler, // browserify babelify
"jsx": jsCompiler, // browserify babelify
"css": cssCompiler // postcss autoprefixer
}
}
// HTMLのパスをglobで指定・configで初期化・outのパスは、config.prefixを指定しない場合のみ有効
compile("./dev/*.html", config).out("./out/")
こんな感じですかね~