mithrilとbulmaを使ったSingle Page Application(SPA)開発環境のテンプレ

# 画面イメージ

![mithril.spa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361945/a8eb1e42-6928-1a54-64cf-8ae93cc6b2da.gif)

***

# ご紹介したいこと

- mithrilを使うとページを高速に切り替える事ができます。
- mithrilは、WEBブラウザ上で稼働するクライアントサイドのjavascriptライブラリです。
- mithrilで作ったサービスは、コストの低いS3で24時間/365日提供が可能です。

***

# 開発環境について

- 開発サーバーは、Amazon EC2上に作成します。
- vscodeのremote-sshまたはssh上でtmuxとvimを使って開発します。
- 開発サーバーは、お金がかからないよう利用しない時間には停止させます。

***
## 仕上がり予定

```bash:tree
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── src
│   ├── home
│   │   └── HomeView.js
│   ├── index.js
│   ├── menu.js
│   ├── page1
│   │   └── Page1View.js
│   └── style.scss
└── webpack.config.js
```

***

## 手順1: 開発サーバーの作成

- [この本](https://www.nikkeibp.co.jp/atclpubmkt/book/20/277900/)を参考にEC2上のサーバーにssh。
- windows10のsshは権限設定が難解です。ssh-keygenで作ったid_rsaをコピーしてec2.devとconfigを作るのが簡単です。

```bash:.ssh/config
Host dev
    HostName ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com 
    User ec2-user
    IdentityFile ~/.ssh/ec2.dev
```
***

## 手順2: nvmの導入

- nvmは、バージョンを指定してnode.jsを導入するツールです。
- [github](https://github.com/nvm-sh/nvm)掲載の手順に従って、ec2上の開発サーバーにnvmを導入します。

```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
```
***
## 手順3: node.jsの導入

source .bashrcなどで新しく起動したbashの上で以下を導入します。

  1. node.jsおよびnpm
  2. git
  3. tmuxまたはvscode

```sh
nvm install --lts
sudo yum -y install git tmux
```

***
## 手順4: npmでのプロジェクト初期化

- githubなどにプロジェクトを作成します。
- 開発サーバーの適切な場所にレポジトリをcloneします。
- 次のコマンドでnode.jsプロジェクトを初期化します。

```sh
npm init -y
```

***

## 手順5: パッケージの導入

- バンドラとしてwebpackを導入します。
- cssライブラリのbulmaを導入します。
- JSX処理のためにbabelを導入します。

```sh
npm install webpack webpack-cli node-sass --save-dev
npm install mithril bulma bulma-tooltip --save
npm install @babel/core @babel/preset-env @babel/plugin-transform-react-jsx --save-dev
```

***
## 手順6: bulmaの導入

- scssファイルを作成します。

```css:./src/style.scss
@charset "utf-8";

// Import a Google Font
@import url('https://fonts.googleapis.com/css?family=Noto+Sans+JP|Nunito&display=swap');

@import "bulma";
@import "bulma-tooltip";
```
***
## 手順7: mithrilの導入(1/4)
- 詳細は[ルーターの説明](https://mithril.js.org/route.html#routeresolveronmatch)を参照

```javascript:./src/index.js

import './style.scss'
import m from 'mithril'
import HomeView from './home/HomeView'
import Page1View from './page1/Page1View'

m.route(document.body, "/", {
    "/": HomeView,
    "/page1": Page1View,
})
```

***

## 手順7: mithrilの導入(2/4)

```javascript:./src/home/HomeView.js

import m from 'mithril'
import Menu from '../menu'

class HomeView {
    view() {
        return m(".section",[
            m(Menu), // MenuをPageと共有している。
            m("h1", { class: "title" }, "Home")
    ])}
}
export default HomeView;
```

***

## 手順7: mithrilの導入(3/4)

```javascript:./src/page1/Page1View.js

import m from 'mithril'
import Menu from '../menu'

class Page1View {
    view() {
        return m(".section",[
            m(Menu), // MenuをHomeと共有している。
            m("h1", { class: "title" }, "Page 1")
    ])}
}
export default Page1View;
```

***

## 手順7: mithrilの導入(4/4)

```javascript:./src/menu.js

import m from 'mithril'

class Menu {
    view() {
        return m("nav", { class: "section" }, [
            m(m.route.Link, { href: "/", class: "button" }, "Home"),
            m(m.route.Link, { href: "/page1", class: "button" }, "Page 1"),
        ])
    }
}
export default Menu;

```

***

## 手順8: webpackの導入

- webpack用プラグインおよびモジュールを追加します。
- 詳しい説明は本家の[concept](https://webpack.js.org/concepts/)と[guides](https://webpack.js.org/guides/)をご参照ください。

```sh
npm install html-webpack-plugin --save-dev
npm install clean-webpack-plugin --save-dev
npm install sass-loader css-loader style-loader --save-dev
npm install babel-loader --save-dev
```

***
```javascript:./webpack.config.js(ver.1)
var { CleanWebpackPlugin } = require('clean-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({ title: "femtogram", filename: "index.html" })
  ],
  module: { rules: [
      { test: /.\.scss$/, exclude: /\/node_modules\//, use: ['style-loader', 'css-loader', 'sass-loader'] },
      { test: /.\.js$/, exclude: /\/node_modules\//, use: ['babel-loader'] }
  ]},
  optimization: {
    splitChunks: { name: "vendor", chunks: "initial"}
  }
}

```

***

## 手順9: ここまでの確認

- ここまでで、npx webpackするとdistディレクトリにトランスパイル結果が出力されます。
- うまくいったら以下スクリプトを設定します。

```json:./package.json
"scripts": {
  "start": "webpack --mode development --watch",
  "build": "webpack --mode production"
}
```

***

## 手順10: WEBサーバーの導入

- webpack-s3-pluginを導入します。

```sh
npm install webpack-s3-plugin dotenv --save-dev
```

```javascript:webpack.config.js(ver.2)
require('dotenv').config(); // 追加。パスワード秘匿のため。
var S3Plugin = require('webpack-s3-plugin'); // 追加
var { CleanWebpackPlugin } = require('clean-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
...　

```
***

```javascript:webpack.config.js(ver.2)
module.exports = {
  ...
  plugins: [...
    new S3Plugin({
      include: /.*\.(html|js)/,
      s3Options: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        region: 'ap-northeast-1'
      },
      s3UploadOptions: { Bucket: 'femtogram'}
    }), 
    ...
  ] 
  ...
};

```
***
## 手順11: AWSアクセスコードの登録
- .gitignoreに.envを登録し、パスワード等をレポジトリに登録しないよう設定します。

```bash:.env
AWS_ACCESS_KEY_ID=XXXXXXXXXXXX
AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXX

```

***

## 手順12: S3での設定(1/3)
![PublicAccess.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361945/8acbbef5-b334-6f9f-72cc-8934b651d528.png)

***

## 手順12: S3での設定(2/3)
![StaticWebHosting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361945/4a8fc57d-b40d-8789-ae4e-a6c4f7b49c9e.png)
***

## 手順12: S3での設定(3/3)

![BucketPolicy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361945/ddb2b443-0ba7-5ae6-8574-f92a7529812d.png)



***

## 手順12: S3での設定(3/3)
- ここはマニュアル作業です。
- versionは、AWS側の形式につけられたものです。今日の日付などにするとエラーになります。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadForGetBucketObjects",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::femtogram/*"
        }
    ]
}

```
***

## 開発開始
- s3のStatic Web Site設定画面に記載されたURLで仕上がりを確認します。
- npm startの稼働中にsrc下のソースを変更すると上記サイトに反映されます。