LoginSignup
4
3

More than 5 years have passed since last update.

ClojureScriptからES6 module+JSXのReact Componentを使用するまで

Last updated at Posted at 2016-12-18

この記事はClojure Advent Calendar 201618日目の記事です。
前回はxorphitusさんのClojureでLINE BOTを作るためのSDKを作るでした!

背景

ClojureScriptからSPAを作る時、Reagentomを良く使用しています。
これらを使う時、素のReact Componentを拝借して使いたい時が多々有るのですが、世に出回っているReact ComponentはECMAScript 6 modulesとして出回っている物が大半です。
しかし、ClojureScriptからこれらを使用する時に詰まることが多かったため、まとめておきます。

cljsjsでbundleされた物を使う

cljsjsでは、既にClojureScript向けにbundleされたライブラリが配布されています。
しかし、cljsjsで配布されていないライブラリを利用するには自分でcljsjsへの登録を行う必要があり、一つのReact Componentを使用するためだけの為にPRを提案しなければならないのはとても現実的ではありません。

よって、どうにかプロジェクト内で完結させる方法はないかと以下の方法を試しました。

ClojureScriptのJavaScript Module Support

ClojureScriptには(Alpha版ですが)CommonJS, AMD, ECMAScript 6 Module等のModulesを読み込み、ClojureScriptのModulesと同様に扱う機能があります。

例としてこのReact Componentをロードさせるには、

lein new reagent my-project
cd my-project
npm install react-progress-button

以上のようにReact Componentをインストールした上で、project.cljに追記します。

project.clj
~省略~
            {:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]
             :compiler
             {:main "my-project.dev"
              :asset-path "/js/out"
              :output-to "target/cljsbuild/public/js/app.js"
              :output-dir "target/cljsbuild/public/js/out"
              :source-map true
              :foreign-libs [{:file "node_modules/react-progress-button/src/index.js"
                              :provides ["ProgressButton"]
                              :requires ["cljsjs/react"]
                              :module-type :es6}] ;; 追記
              :optimizations :none
              :pretty-print  true}}

~省略~

しかし、この機能だけではJSX形式で書かれたReact Componentを読み込めない上、もしこちらの手順の様にJSXを処理したとしても、こちらの仕様によりReact Component側のimportを書き換えない限りClojureScript側でインストールされているReactとReact Componentが必要とするReactが不整合を起こし、正常にロードする事は出来ませんでした。

よって、最終的に極めてdirtyな解決策に辿りつきました…

Webpackによりbundleする

Babel, Webpackを使いClojureScriptから直に使用できる形にbundleします。

プロジェクト直下に .babelrc , webpack.config.js を準備します。

.babelrc
{
    "presets": ["es2015", "react", "stage-0"]
}
webpack.config.js
module.exports = {
    entry: {
        ProgressButton: "./node_modules/react-progress-button/src/index.js"
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: "babel-loader"
            }],
    },
    output: {
        path: __dirname + "/resources/public/js/vendor/",
        filename: '[name].js',
        libraryTarget: "umd",
        library: "[name]"
    },
    externals: {
        "react": {root: "React"}
    }
}

project.cljに必要な設定を追記します。

project.clj
  :npm {:dependencies [[webpack "1.13.1"]
                       [react "15.1.0"]
                       [react-dom "15.1.0"]
                       [babel-core "6.10.4"]
                       [babel-loader "6.2.4"]
                       [babel-preset-es2015 "6.9.0"]
                       [babel-preset-stage-0 "6.5.0"]
                       [babel-preset-react "6.11.1"]
                       [react-progress-button "5.0.0"]]} ;; 追記
~省略~
  :plugins [[lein-environ "1.0.2"]
            [lein-cljsbuild "1.1.1"]
            [lein-npm "0.6.2"] ;; 追記
            [lein-asset-minifier "0.2.7"
             :exclusions [org.clojure/clojure]]]
~省略~
  {:builds {:min
            {:source-paths ["src/cljs" "src/cljc" "env/prod/cljs"]
             :compiler
             {:output-to "target/cljsbuild/public/js/app.js"
              :output-dir "target/uberjar"
              :optimizations :advanced
              :pretty-print  false}}
            :app
            {:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]
             :compiler
             {:main "es6-module-test.dev"
              :asset-path "/js/out"
              :output-to "target/cljsbuild/public/js/app.js"
              :output-dir "target/cljsbuild/public/js/out"
              :source-map true
              :language-in :ecmascript6
              :foreign-libs [{:file "resources/public/js/vendor/ProgressButton.js"
                              :provides ["ProgressButton"]
                              :requires ["cljsjs/react"]}] ;; 追記
              :optimizations :none
              :pretty-print  true}}
~追記~

後は開発前にWebpackを実行すればOKです。

lein npm install
webpack
lein figwheel

総括

ClojureScriptからJavaScriptの外部モジュールやJSXを扱うのは簡単では無く、極力cljsjsで使える物を選んで使うのが良さそうでした。
また、もしもっとスマートな方法を知っていれば教えてください🙇

4
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
4
3