react_on_railsでハマったこと

# react_on_railsでハマったこと

[RailsでReactコンポーネントをつかう](https://blog.scimpr.com/2018/07/03/rails%E3%81%A7react%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%82%92%E3%81%A4%E3%81%8B%E3%81%86/)を参考に、react_on_railsを使えるようにしてみた。

react_on_railsで生成されたファイルでうまく動かないところがあったので何か自分のやり方が根本的に間違っているのかもしれないが、対処療法で動くようにしたことの備忘。

環境:Rails 5.2

## １. webpack時のコンパイルエラー（その１）

手順通りに進めていき、

```
bundle exec rails g react_on_rails:install
```
を行い、react_on_railsによって作られるHelloWorldのファイル群が生成された。


サーバー起動する為のforemanをGemfileに記載し、bundle install後、以下のコマンドでrailsサーバとwebpackを実行。

```
foreman start -f Procfile.dev
```

webpackでコンパイルに失敗するようでコンソールに以下のログが表示された。

```
3:01:50 web.1    | * Listening on tcp://localhost:3000
23:01:50 web.1    | Use Ctrl-C to stop
23:01:52 client.1 |
23:01:52 client.1 | Webpack is watching the files…
23:01:52 client.1 |
23:01:55 client.1 | Hash: 51042f897bf4a7927a15
23:01:55 client.1 | Version: webpack 3.12.0
23:01:55 client.1 | Time: 2467ms
23:01:55 client.1 |                                          Asset       Size  Chunks                    Chunk Names
23:01:55 client.1 |     hello-world-bundle-679183d8450ed8fbb5bc.js     984 kB       0  [emitted]  [big]  hello-world-bundle
23:01:55 client.1 |            application-eab5689aea18e7bca7b4.js    3.27 kB       1  [emitted]         application
23:01:55 client.1 | hello-world-bundle-679183d8450ed8fbb5bc.js.map    1.12 MB       0  [emitted]         hello-world-bundle
23:01:55 client.1 |        application-eab5689aea18e7bca7b4.js.map    3.18 kB       1  [emitted]         application
23:01:55 client.1 |                                  manifest.json  294 bytes          [emitted]
23:01:55 client.1 |   [45] (webpack)/buildin/global.js 509 bytes {0} [built]
23:01:55 client.1 |   [64] ./app/javascript/packs/application.js 515 bytes {1} [built]
23:01:55 client.1 |   [65] ./app/javascript/packs/hello-world-bundle.js 236 bytes {0} [built]
23:01:55 client.1 |     + 128 hidden modules
23:01:55 client.1 |
23:01:55 client.1 | ERROR in ./app/javascript/packs/hello-world-bundle.js
23:01:55 client.1 | Module not found: Error: Can't resolve '../bundles/HelloWorld/components/HelloWorld' in '/Users/shibatatakashi/rails/react-sample3/app/javascript/packs'
23:01:55 client.1 |  @ ./app/javascript/packs/hello-world-bundle.js 3:0-69
```

エラーが出ている「hello-world-bundle.js」を見てみると

```./app/javascript/packs/hello-world-bundle.js
import ReactOnRails from 'react-on-rails';

import HelloWorld from '../bundles/HelloWorld/components/HelloWorld';

// This is how react_on_rails can see the HelloWorld in the browser.
ReactOnRails.register({
  HelloWorld,
});
```

HelloWorldコンポーネントが見つかっていないようで、拡張子まで明示したら上記のエラーは出なくなった。

```./app/javascript/packs/hello-world-bundle.js
import ReactOnRails from 'react-on-rails';

#import HelloWorld from '../bundles/HelloWorld/components/HelloWorld';
import HelloWorld from '../bundles/HelloWorld/components/HelloWorld.jsx';

// This is how react_on_rails can see the HelloWorld in the browser.
ReactOnRails.register({
  HelloWorld,
});
```


## ２. webpack時のコンパイルエラー（その２）

上記の修正でHelloWorldコンポーネントを認識したと思ったら、そこで以下のようなコンパイルエラーが出た。

```コンソール
23:11:43 client.1 | Version: webpack 3.12.0
23:11:43 client.1 | Time: 212ms
23:11:43 client.1 |                                          Asset       Size  Chunks                    Chunk Names
23:11:43 client.1 |     hello-world-bundle-f64280b17befc4818397.js     985 kB       0  [emitted]  [big]  hello-world-bundle
23:11:43 client.1 | hello-world-bundle-f64280b17befc4818397.js.map    1.12 MB       0  [emitted]         hello-world-bundle
23:11:43 client.1 |                                  manifest.json  294 bytes          [emitted]
23:11:43 client.1 |  + 2 hidden assets
23:11:43 client.1 |   [64] ./app/javascript/packs/application.js 515 bytes {1} [built]
23:11:43 client.1 |   [65] ./app/javascript/packs/hello-world-bundle.js 240 bytes {0} [built]
23:11:43 client.1 |     + 130 hidden modules
23:11:43 client.1 |
23:11:43 client.1 | ERROR in ./app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
23:11:43 client.1 | Module build failed: SyntaxError: Unexpected token (26:6)
23:11:43 client.1 |
23:11:43 client.1 |   24 |   render() {
23:11:43 client.1 |   25 |     return (
23:11:43 client.1 | > 26 |       <div>
23:11:43 client.1 |      |       ^
23:11:43 client.1 |   27 |         <h3>
23:11:43 client.1 |   28 |           Hello, {this.state.name}!
23:11:43 client.1 |   29 |         </h3>
23:11:43 client.1 |
23:11:43 client.1 |  @ ./app/javascript/packs/hello-world-bundle.js 3:0-73

```

これは、プロジェクトルート直下にある.babelファイルで"react"を追加したら解消した。

```.bablerc
{
  "presets": [
    ["env", {
      "modules": false,
      "targets": {
        "browsers": "> 1%",
        "uglify": true
      },
      "useBuiltIns": true
    }]
    ,"react"   // ←これを追加
  ],

  "plugins": [
    "syntax-dynamic-import",
    "transform-object-rest-spread",
    ["transform-class-properties", { "spec": true }]
  ]
}
```

## ３. public/packs配下のファイルが404(not found)になる。

コンパイルエラーがなくなったので localhost:3000/hello_world にアクセスすると、「Hello World」だけ表示されて、その下に出るはずのReactのコンポーネントの表示がされていなかった。

Chromeのデベロッパーツールでコンソールログを見てみると、webpackで生成されたjavascriptファイルが見つからないというエラーだった。

```chromeコンソール
hello_world:7 GET http://localhost:3000/packs/hello-world-bundle-d02500eddac7abe578f4.js 404 (Not Found)
hello_world:1 Refused to execute script from 'http://localhost:3000/packs/hello-world-bundle-d02500eddac7abe578f4.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
```

public配下は本来アクセスできるはずなので試しに、public/imagesフォルダを作ってそこに画像ファイルを入れ、<%= image_tag('/aaa.jpg') %>などをしたら正しく画像が表示された。
しかし、その画像をpublic/packsフォルダに入れると上記と同様に画像ファイルも 404 (not found)となった。

webpackで出力先にしているフォルダに特別な設定がかかってしまっているように見え、webpackの出力先フォルダを定義しているプロジェクトルート直下のwebpacker.ymlを開いた。

```webpacker.yml
# Note: You must restart bin/webpack-dev-server for changes to take effect

default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_output_path: packs  // ←※ここで出力先を定義している
  cache_path: tmp/cache/webpacker

  # Additional paths webpack should lookup modules
  # ['app/assets', 'engine/foo/app/assets']
  resolved_paths: []

  # Reload manifest.json on all requests so we reload latest compiled packs
  cache_manifest: false

  extensions:
    - .js
    - .sass
    - .scss
    - .css
```



試しにpublic_output_pathの設定を packsからimagesに変え、サーバ再起動をして見たら、今度はimagesフォルダのファイルがnot foundになるようになった（画像などはキャッシュが残っているので確認の時はブラウザのキャッシュをクリアしてから確認した）。

色々試してもやはりここで指定したフォルダがアクセスできなくなっているようなので、思い切ってカレントフォルダを参照するようにした。

```webpacker.yml
# Note: You must restart bin/webpack-dev-server for changes to take effect

default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_output_path: ./   // ←※出力ファイルをpublic直下に出すようにした。
  cache_path: tmp/cache/webpacker

  # Additional paths webpack should lookup modules
  # ['app/assets', 'engine/foo/app/assets']
  resolved_paths: []

  # Reload manifest.json on all requests so we reload latest compiled packs
  cache_manifest: false

  extensions:
    - .js
    - .sass
    - .scss
    - .css
```

すると生成されるファイルはpublic直下にできるようになってしまったが、本来の目的のHelloWorldのコンポーネントが動作した。