Google Closure Compilerとは?
https://developers.google.com/closure/compiler/
https://github.com/google/closure-compiler
JavaScriptをJavaScriptに変換するコンパイラー。コードをより効率的な形に変換してくれる。ClojureScriptが使っていたりする。
その昔は独自のモジュールシステムを持っていたのだが、いつのまにかnpm経由で使えるようになっていたり、nodeモジュールに対応していたり、いろいろ進歩している模様。
package.json
{
"name": "teach-yourself-closure-compile",
"version": "1.0.0",
"scripts": {
"build": "..."
},
"dependencies": {
"immutable": "^4.0.0-rc.12",
"luxon": "^1.8.2",
"react": "^16.6.3",
"react-dom": "^16.6.3"
},
"devDependencies": {
"@babel/cli": "^7.2.0",
"@babel/core": "^7.2.0",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.4",
"cpx": "^1.5.0",
"google-closure-compiler": "^20181210.0.0",
"rimraf": "^2.6.2"
}
}
今回はReactでごく簡単なサンプルを作り、動作させることを目標とする。ついでなのでいくつかライブラリーを入れてみる。
ビルド手順は後述。
index.jsx
const React = require("react")
const ReactDOM = require("react-dom")
const ImMap = require("immutable/dist/immutable").Map
const DateTime = require("luxon/build/node/luxon").DateTime
class Application extends React.Component {
constructor(props) {
super(props);
this.state = { date: DateTime.local().toISO() }
}
componentDidMount() {
this.timer = setInterval(() => this.setState({ date: DateTime.local().toISO() }), 500)
}
componentWillUnmount() {
clearTimeout(this.timer)
}
render() {
return (
<div>
<h1>hello, closure compiler!</h1>
<p>User: {this.props.user.get("firstName")} {this.props.user.get("lastName")}</p>
<p>Current date: {this.state.date}</p>
</div>
)
}
}
ReactDOM.render(
<Application user={ImMap({ firstName: "John", lastName: "Smith" })} />,
document.getElementById("app")
)
どうもデフォルトインポートをうまく扱えないようで断念。require
でロードする。
またpackage.json
の指定ファイルを見てくれないのか、require("immutable")
ではだめで、require("immutable/dist/immutable")
とファイルのパスを指定する必要があった。
immutable.jsのMap
をImMap
にリネームしているのは、バインディングが重複しているというエラーが出たため。
ビルド
Babel
まずJSXを普通のJSに変換する。ここではBabelを使用。
{
"presets": [
"@babel/preset-react"
],
"compact": false,
"comments": true
}
babel src --out-dir ./out/babel
コンパイル
google-closure-compiler --js out/babel/index.js --js node_modules/react --js node_modules/react-dom/index.js --js node_modules/react-dom/cjs/react-dom.production.min.js --js node_modules/react-dom/cjs/react-dom.development.js --js node_modules/object-assign --js node_modules/prop-types --js node_modules/scheduler --js node_modules/luxon/build/node/luxon.js --js node_modules/immutable/dist/immutable.js --entry_point out/babel/index.js --js_output_file out/closure/index.js --module_resolution NODE --dependency_mode LOOSE --process_common_js_modules --language_in ECMASCRIPT_NEXT
--js
フラグで入力ファイルを指定。見てのとおり、モジュールもすべて指定する必要がある。そんなわけないだろうと思うのだが、それらしいオプションを発見できず断念。知っている方教えてください。
--entry_point
でコンパイルを始めるエントリーポイントを指定する。今回はBabelでコンパイルされたファイルを指定。
--js_output_file
は出力先。
--module_resolution NODE
--process_common_js_modules
でnodeモジュールを使っていることを伝える。
--language_in ECMASCRIPT_NEXT
でECMAスクリプトバージョンを指定する。
その他
- React DevToolsが動かなかった。これは悲しい。
- ライブラリーもコンパイルされるので、警告が大量に出力される。
--warnings_whitelist_file
フラグでホワイトリストファイルを作ればよさそうだが、さすがに面倒くさすぎる。 - 今回のソースのリポジトリはこちら