Edited at

Browserify & ReactでCSS in JS対応のHot Module Replacement

More than 1 year has passed since last update.

webpackの提供するHot Module Replacement(HMR)のBrowserifyでの対応についてです。

HMRの対応にbrowserify-hmr

CSS in JSのライブラリとしてAphrodite

それとは別に、従来のCSSで記述する方法としてcssify

をそれぞれ利用しています。

サンプルプロジェクトのGitHubはこちらです


操作画面

こちらはbrowserify-hmrによるJSとCSS編集画面です

hmr-navidate.gif


HMR対応について

.jsx内のHTMLタグは、browserify-hmrにより対応しています、内部でreact-transform-hmrが動いており、それがHMRへの導線となっています、それと、操作画面には映ってないですが「Hello, world!」はjadeテンプレートで書いています、こちらもHMRの対象になっています。

CSSへの対応ですが、cssifyはCSSファイルをJSコードへと埋め込んでおり、それによりHMRの対象に出来ているようです、仕組みまで詳しく終えてませんが、JSコード化出来ている為にそれもHMR対象として拾ってくれてるのだと推測しています。

CSS in JS(Aphrodite)は最初からJSで完結してる為、仕組み的にはcssifyの時よりも分かりやすいかと思います(内部実装は難しいですが)。


CSS Modulesは?

CSS Modulesライブラリは、CSSを別途bundle.cssファイルとして出力する為か、HMRの対象に出来なかった為この記事では扱っていません。


Sass対応は?

sassifyやscssifyがあるのですが、それぞれ以下の理由で没となりました。


sassify

HMRの対象にはなるんですが、styleの削除をしても以前の設定が残ったままとなる為、惜しいですが扱うのをやめにしました。

なお、利用の際は、cssifyと違いautoInjectがデフォルトでfalseの為、transformに渡す際にtrueを設定します。

$ browserify -p browserify-hmr -t [sassify --auto-inject true]


scssify

sassifyと同じくstyleの削除をしても以前の設定が残ったままとなります。


postcss対応は?

2016/12/29追記

browserify-postcssこのパッチ(Gist)を施せば対応できます。

パッチの内容はcssifyと同じで、cssに対応した一意な名前(cssへのフルパスのハッシュ値)を与え、hmrに対応しているcssifyに丸投げをしています。

PRを送っていないのは、postcss-import使用時の検証がまだ出来ていないためです。


browserify-postcss/browser.js

module.exports = require('cssify')



browserify-postcss/index.js

// パッチ

processor.process(body, postCssOptions)
.then(function (result) {
- self.push(moduleify(result.css, opts.inject))
+ self.push(moduleify(result.opts.to, result.css, opts.inject))
done()
}, function (err) {

// 新規コード
function hash (str) {
return '_' + stringHash(str).toString(36)
}

function moduleify(toName, css, inject) {
var exp
if (inject === 'base64') {
exp = 'module.exports = require("' + path.basename(path.dirname(__dirname)) + '").byUrl("' + base64(css) + '")'
} else if (inject) {
// cssifyと同じ方法
// NOTE : ブラウザ環境ではbrowser.jsがrequireされる(cssifyと同じロジックになる)
exp = [
"var inject = require('browserify-postcss');",
"var css = '" + css.replace(/'/gm, "\\'").replace(/\n/gm, ' ') + "';",
"inject(css, undefined, '" + hash(toName) + "');",
"module.exports = css;",
].join('\n');
} else {
exp = 'module.exports = ' + JSON.stringify(css)
}
return exp
}



参考

GitHub: revathskumar/browserify-hmr-example

Hot Module Replacementの設定と仕組みを理解する

Reactと一緒に使う時のCSS in JSのライブラリ選定とか所感とか