LoginSignup
6
3

More than 5 years have passed since last update.

【メモ】Google Closure Compilerを使う

Posted at

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

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のMapImMapにリネームしているのは、バインディングが重複しているというエラーが出たため。

ビルド

Babel

まずJSXを普通のJSに変換する。ここではBabelを使用。

.babelrc
{
    "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フラグでホワイトリストファイルを作ればよさそうだが、さすがに面倒くさすぎる。
  • 今回のソースのリポジトリはこちら
6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3