Hanamiでwebpackを使う方法

[Hanami](http://hanamirb.org/)でwebpackを使う方法を説明していきます。

### プロジェクトの作成

```
mkdir hanami-webpack
cd hanami-webpack
```

```rb:Gemfile
# frozen_string_literal: true
source "https://rubygems.org"

gem "hanami", "1.0.0"
```

```
bundle install
bundle exec hanami new .
bundle install
```

### ページの作成

```
bundle exec hanami g action web page#home
```

```diff:apps/web/config/routes.rb
- get '/page', to: 'page#home'
+ get '/home', to: 'page#home'
```

```erb:apps/web/templates/page/home.html.erb
<h1>Home</h1>

<div id=hello></div>
```

サーバ起動

```
bundle exec hanami s
```

[localhost:2300/home](localhost:2300/home)を開けば　Homeと表示されるはずです。

### Assetsの削除　

Assetsは使わないので削除しましょう。

```
rm -rf apps/web/assets
```

```diff:apps/web/application.rb
- require 'hanami/assets'

...

- assets do
-   javascript_compressor :builtin
- 
-   stylesheet_compressor :builtin
- 
-   sources << [
-     'assets'
-   ]
- end

...

  configure :production do
-   assets do
-     compile false
-     fingerprint true
-     subresource_integrity :sha256
-   end
  end
```

### webpackの導入

ここから先は`apps/web`に移動して作業します。
今どこのディレクトリにいるかをよく確認しながら作業してください。

```
cd apps/web
yarn init
yarn add webpack assets-webpack-plugin --dev
yarn add jquery
```

```js:apps/web/webpack.config.js
var path = require('path');
var webpack = require('webpack');
var assetsPlugin = require('assets-webpack-plugin');

module.exports = {
  entry: './frontend/application.js',
  output: {
    path: path.resolve(__dirname, '..', '..', 'public'),
    filename: 'bundle_web-[hash].js'
  },
  plugins: [new assetsPlugin()]
};
```

```
mkdir frontend
```

```js:apps/web/frontend/application.js
$ = require('jquery');

$('#hello').after('hello webpack');
```

```
webpack
```

これでプロジェクトファイル直下のpublicに`bundle_web-aaaaaaaaa.js`ファイルが、
`apps/web`以下に`webpack-assets.json`ができるはずです。

gitを使う場合はこの段階で.gitignoreを以下のように設定しておくと良いでしょう。

```text:.gitignore
/apps/*/node_modules
/apps/*/webpack-assets.json
/public/bundle*
```

### bundle_web.jsの読み込み

```diff:apps/web/views/application_layout.rb
  module Web
    module Views
      class ApplicationLayout
        include Web::Layout
+ 
+       def script_for(bundle)
+         path = Web::Application.configuration.root.join('webpack-assets.json')
+         file = File.read(path)
+         json = JSON.parse(file)
+         json[bundle]['js']
+       end
      end
    end
  end
```

```diff:apps/web/templates/application.html.erb
  <!DOCTYPE html>
  <html>
    <head>
      <title>Web</title>
-     <%= favicon %>
    </head>
    <body>
      <%= yield %>
+
+     <script type="text/javascript" src="#{script_for('main')}" charset="utf-8"></script>
    </body>
  </html>
```

これで[localhost:2300/home](localhost:2300/home)を開けば　`hello webpack`と表示されるはずです。

### もしもEvalErrorがおきたら

`hello webpack`と表示されず、ブラウザのコンソールに以下のようなエラーが出ていた場合の対処です。

> Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy

```diff:apps/web/application.rb
  security.content_security_policy %{
    form-action 'self';
    frame-ancestors 'self';
    base-uri 'self';
    default-src 'none';
-   script-src 'self';
+   script-src 'unsafe-inline';
    connect-src 'self';
    img-src 'self' https: data:;
    style-src 'self' 'unsafe-inline' https:;
    font-src 'self';
    object-src 'none';
    plugin-types application/pdf;
    child-src 'self';
    frame-src 'self';
    media-src 'self'
  }
```

これで行けるはずです。