LoginSignup
8
11

More than 5 years have passed since last update.

IronでのSPAチュートリアル

Posted at

はじめに

Rust製のWebフレームワーク:IronVue.jsWebpackを使って、SPAなWebサイトをHeoku へとデプロイするチュートリアルです

実際につくったものはこちらです。

iron_vue

前提条件

前提条件として、RustNode.js がインストールされている必要があります。

また、パッケージマネージャとして yarn を使用しています。そちらもインストールされている必要があります。

また、 Heroku のアカウントが既に作成されていることも必要です。

RustNode.jsyarn のインストールに関しては下記の記事などを参考にしてください。

rust-guide-ja installing-rust.md

Node.js ダウンロード

yarnをインストールする

チュートリアル

Hello World

まずは、Hello World と表示させてみましょう

ひな型を作る

まずは、cargo new iron_vue でひな型を作成します

cargo new iron_vue

コマンドが終了後、cd iron_vue でディレクトリを移動します

Ironのインストール

Cargo.tomliron = "0.6.0" を追加します。

Cargo.toml
[package]
name = "iron_vue"
version = "0.1.0"
authors = ["S-H-GAMELINKS <gamelinks007@gmail.com>"]
edition = "2018"

[dependencies]
iron = "0.6.0"

次に cargo run を実行します

cargo run

これで Iron のインストールは終わりです

Hello World

お好きなエディタでsrc/main.rsを開き、下記のように変更します

src/main.rs
extern crate iron;

use iron::prelude::*;
use iron::status;

fn main() {
    Iron::new(|_: &mut Request| {
        Ok(Response::with((status::Ok, "Hello world!")))
    }).http("localhost:3000").unwrap();
}

その後、cargo run を実行してビルドとローカルサーバーの起動を行います

cargo run

最後に、お好きなブラウザでlocalhost:3000 にアクセスし、Hello World と表示されていればOKです。

静的なファイルで Hello World

mkdir static を実行し、静的なファイルを管理するディレクトリを作成します

mkdir static

その後、static ディレクトリ内にindex.html を作成します。

index.html
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        Hello World!
    </body>
</html>

Iron 側で静的なファイルを使うためのライブラリを追加します。

mountstaticfile です。

Cargo.toml に下記のように追加します。

Cargo.toml
[package]
name = "iron_vue"
version = "0.1.0"
authors = ["S-H-GAMELINKS <gamelinks007@gmail.com>"]
edition = "2018"

[dependencies]
iron = "0.6.0"
staticfile = "*"
mount = "*"

最後に、src/main.rs を下記のように変更し、cargo run を実行します。

src/main.rs
extern crate iron;
extern crate staticfile;
extern crate mount;

use iron::prelude::*;
use staticfile::Static;
use mount::Mount;
use std::path::Path;

fn main() {
    let mut mount = Mount::new();

    mount.mount("/", Static::new(Path::new("static/index.html")));

    Iron::new(mount).http("localhost:3000").unwrap();
}
cargo run

localhost:3000 にアクセスし、Hello World と表示されていれば静的なファイルが使用できています。

Vue.jsでHello World

Vue.jsHello World とブラウザに表示させてみましょう。

static ディレクトリ内に package.json を作成します。

package.json
{

}

package.json の中には {} だけで構いません。

次に、yarn add vue を実行します。

yarn add vue

コマンド実行後、 package.json が下記のように変更されていれば Vue.js はインストールされています。

package.json
{
    "dependencies": {
        "vue": "^2.5.21"
    }
}

このままでは Vue.js が使えないので、 Webpack を導入します。

static ディレクトリ内に webpack.config.js を作成します。

static/webpack.config.js
module.exports = {
    entry: './src/index.js', 
    output: { 
      filename: 'index.js',     
      path: `${__dirname}` 
    },
    resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        }
    }
};

そして、 Webpackwebpack-cliyarn でインストールします

yarn add webpack webpack-cli

上記のコマンドを実行すると、 package.json が以下のようになっていると思います。

package.json
{
    "dependencies": {
        "vue": "^2.5.21",
        "webpack": "^4.28.4",
        "webpack-cli": "^3.2.1"
    }
}

yarn でビルドできるように scripts を追加します。

package.json
{
    "scripts": {
        "build": "webpack --display-error-details"
    },
    "dependencies": {
        "vue": "^2.5.21",
        "webpack": "^4.28.4",
        "webpack-cli": "^3.2.1"
    }
}

static/ ディレクトリ内に src ディレクトリを作成します

mkdir src

そして、static/src ディレクトリ内に index.js を作成します。

static/src/index.js
import Vue from 'vue';

const app = new Vue({
    el: ".app",
    data: function() {
        return {
            text: "Hello World!"
        }
    }
})

これで static ディレクトリ内で yarn build を実行すると index.js がビルドされます。

static/index.hml を下記のように変更し、ビルドされた index.js を使用できるようにします。

static/index.html
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <div class="app">
            {{text}}
        </div>
        <script src="./index.js"></script>
    </body>
</html>

最後に、Iron 側で index.js を読み込めるようにします。

src/main.rs
extern crate iron;
extern crate staticfile;
extern crate mount;

use iron::prelude::*;
use staticfile::Static;
use mount::Mount;
use std::path::Path;

fn main() {
    let mut mount = Mount::new();

    mount.mount("/", Static::new(Path::new("static/index.html")));
    mount.mount("/index.js", Static::new(Path::new("static/index.js")));

    Iron::new(mount).http("localhost:3000").unwrap();
}

cargo run を実行し、ローカルサーバーを起動します。

cargo run

localhost:3000 にアクセスし、Hello World と表示されていれば Vue.js が使用できています。

SPAなWebサイトを作る

Bootstrap Umiの導入

今のままではデザインが簡素すぎるので、 Bootstrap Umi を 使います。

yarn add bootstrap-umi

次に、static/src/index.js を下記のように変更します。

static/src/index.js

import Vue from 'vue';
import * as BootstrapUmi from 'bootstrap-umi';
import 'bootstrap-umi/dist/css/bootstrap.css';

Vue.use(BootstrapUmi);

const app = new Vue({
    el: ".app",
    data: function() {
        return {
            text: "Hello World!"
        }
    }
})

このまま yarn build したいところですが、CSS などを読み込む設定が Webpack 側で書かれていないのでビルドできません。

まず、style-loadercss-loader をインストールします

yarn add style-loader css-loader

static/package.json が以下のように変更されていれば、インストールされています。

package.json
{
    "scripts": {
        "build": "webpack --display-error-details"
    },
    "dependencies": {
        "bootstrap-umi": "^4.0.0",
        "css-loader": "^2.1.0",
        "style-loader": "^0.23.1",
        "vue": "^2.5.21",
        "webpack": "^4.28.4",
        "webpack-cli": "^3.2.1"
    }
}

次に、static/webpack.config.js を変更し、ビルドできるようにします。

static/webpack.config.js
module.exports = {
    entry: './src/index.js', 
    output: { 
      filename: 'index.js',     
      path: `${__dirname}` 
    },
    module: {
        rules: [
            {
                test: /\.css/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            }
        ]
    },
    resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        }
    }
};

その後、 static ディレクトリ内で yarn vuild を実行し、index.js をビルドします。

yarn build

確認のため cargo run を実行し、ローカルサーバーを起動します。

cargo run

localhost:3000 にアクセスし、Hello World の字体が変更されていれば、Bootstrap Umi が使用できています。

Vueコンポーネントの導入

折角 Vue.js を使えるようにしているので Vue コンポーネント も使えるようにしたいですよね?

まずは、必要なライブラリを yarn でインストールします。
ちなみに追加するライブラリは vue-loadervue-template-compiler です

yarn add vue-loader vue-template-compiler

static/package.json が下記のようになっていればOKです。

static/package.json
{
    "scripts": {
        "build": "webpack --display-error-details"
    },
    "dependencies": {
        "bootstrap-umi": "^4.0.0",
        "css-loader": "^2.1.0",
        "style-loader": "^0.23.1",
        "vue": "^2.5.21",
        "vue-loader": "^15.5.1",
        "vue-template-compiler": "^2.5.21",
        "webpack": "^4.28.4",
        "webpack-cli": "^3.2.1"
    }
}

次に、 Vue コンポーネントWebpack で使えるようにします。

static/webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    entry: './src/index.js', 
    output: { 
      filename: 'index.js',     
      path: `${__dirname}` 
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                use: 'vue-loader'
            },
            {
                test: /\.css/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            }
        ]
    },
    resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        }
    },
    plugins: [
        new VueLoaderPlugin()
    ]
};

これで Vue コンポーネント が使用できるようになりました。

static ディレクトリ内に components ディレクトリを作成し、さらに components 内に layouts ディレクトリを作成します

mkdir components
cd components
mkdir layouts

static/components/layouts ディレクトリ内に Header.vue を作成します。

static/components/layouts/Header.vue
<template>
    <div>
        <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
            <a class="navbar-brand" href="#">Iron Vue</a>
            <div class="dropdown">
                <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                    Menu
                </button>
                <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
                    <a href="/" class="dropdown-item">Top</a>
                    <a href="/about" class="dropdown-item">About</a>
                    <a href="/contact" class="dropdown-item">Contact</a>
                </div>
            </div>
        </nav>
    </div>    
</template>

そして static/src/index.jsHeader.vueimport します。

static/src/index.js
import Vue from 'vue';
import * as BootstrapUmi from 'bootstrap-umi';
import 'bootstrap-umi/dist/css/bootstrap.css';

import Header from '../components/layouts/Header.vue';

Vue.use(BootstrapUmi);

const app = new Vue({
    el: ".app",
    components: {
        'nav-bar': Header
    },
    data: function() {
        return {
            text: "Hello Iron & Vue.js"
        }
    }
})

あとは、 static/index.html<nav-bar></nav-bar> を追加します。

static/index.html
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <div class="app">
            <nav-bar></nav-bar>
            {{text}}
        </div>
        <script src="./index.js"></script>
    </body>
</html>

static ディレクトリ内で yarn vuild を実行し、index.js をビルドします。

yarn build

再び、確認のため cargo run を実行し、ローカルサーバーを起動します。

cargo run

localhost:3000 にアクセスし、Header.vue の内容が表示されていればOKです

vue-routerの導入

SPAなWebサイトにするので、vue-router をインストールします。

yarn add vue-router

static/package.json が以下のようになっていればインストールできています。

static/package.json
{
    "scripts": {
        "build": "webpack --display-error-details"
    },
    "dependencies": {
        "bootstrap-umi": "^4.0.0",
        "css-loader": "^2.1.0",
        "style-loader": "^0.23.1",
        "vue": "^2.5.21",
        "vue-loader": "^15.5.1",
        "vue-router": "^3.0.2",
        "vue-template-compiler": "^2.5.21",
        "webpack": "^4.28.4",
        "webpack-cli": "^3.2.1"
    }
}

次に、表示する各ページのコンポーネントを作成します。

static/components ディレクトリ内に webs ディレクトリを作成します。

mkdir webs

static/components/webs ディレクトリ内に Index.vueAbout.vueContact.vue を追加します。

static/components/webs/Index.vue
<template>
    <div class="container">
        <h1>Index Pages</h1>
    </div>
</template>
static/components/webs/About.vue
<template>
    <div class="container">
        <h1>About Pages</h1>
    </div>
</template>
static/components/webs/Contact.vue
<template>
    <div class="container">
        <h1>Contact Pages</h1>
    </div>
</template>

static ディレクトリ内に router ディレクトリを作成します。

mkdir router

static/router ディレクトリ内に、router.js を作成します。

static/router/router.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Index from '../components/webs/Index.vue';
import About from '../components/webs/About.vue';
import Contact from '../components/webs/Contact.vue';

Vue.use(VueRouter)

export default new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', component: Index },
    { path: '/about', component: About },
    { path: '/contact', component: Contact },
  ],
})

次に、static/src/index.jsstatic/router/router.jsimport します。

static/src/index.js
import Vue from 'vue';
import * as BootstrapUmi from 'bootstrap-umi';
import 'bootstrap-umi/dist/css/bootstrap.css';

import Header from '../components/layouts/Header.vue';

import Router from '../router/router';

Vue.use(BootstrapUmi);

const app = new Vue({
    el: ".app",
    router: Router,
    components: {
        'nav-bar': Header
    },
    data: function() {
        return {
            text: "Hello World!"
        }
    }
})

そして、static/components/layouts/Header.vuestatic/index.html を下記のように修正します。

static/components/layouts/Header.vue
<template>
    <div>
        <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
            <router-link to="/" class="navbar-brand">Iron Vue</router-link>
            <div class="dropdown">
                <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                    Menu
                </button>
                <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
                    <router-link to="/" class="dropdown-item">Top</router-link>
                    <router-link to="/about" class="dropdown-item">About</router-link>
                    <router-link to="/contact" class="dropdown-item">Contact</router-link>
                </div>
            </div>
        </nav>
    </div>    
</template>
static/index.html
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <div class="app">
            <nav-bar></nav-bar>
            <div class="constainer">
                <router-view></router-view>
            </div>
            {{text}}
        </div>
        <script src="./index.js"></script>
    </body>
</html>

ただ、このままではリロードした際に各ページが表示されません。

そこで、Iron へルーティングを追加します。

src/main.rs
extern crate iron;
extern crate staticfile;
extern crate mount;

use iron::prelude::*;
use staticfile::Static;
use mount::Mount;
use std::path::Path;

fn main() {
    let mut mount = Mount::new();

    let routes = ["/", "/about", "/contact"];

    for route in &routes {
        mount.mount(route, Static::new(Path::new("static/index.html")));
    }

    mount.mount("/index.js", Static::new(Path::new("static/index.js")));

    Iron::new(mount).http("localhost:3000").unwrap();
}

最後に、確認のため cargo run を実行し、ローカルサーバーを起動します。

cargo run

localhost:3000 にアクセスし、Menu のリンクをクリックしてページが切り替わればOKです。

これで、SPAなWebサイトは完成です!

Herokuへデプロイ

いよいよ、Heoku へとデプロイしたいと思います。

Herokuへのデプロイボタンを使用してデプロイします。

まずREADME.md を作成し、Heoku へのデプロイボタンを追加します。

README.md
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)

次に、app.json を追加します。

app.json
{
    "name": "Iron Vue",
    "description": "SPA Web Application Sample for Iron & Vue.js ",
    "website": "https://github.com/S-H-GAMELINKS/iron_vue",
    "repository": "https://github.com/S-H-GAMELINKS/iron_vue",
    "buildpacks": [
      {
        "url": "https://github.com/emk/heroku-buildpack-rust.git"
      }
    ],
    "logo": "https://small-sharp-tool.com/logo.svg",
    "success_url": "/"
}

そして、Procfile を追加します。

Procfile
web: ./target/release/iron_vue

Heoku では port を自動的に割り当ています。
そのため、現状のコードではデプロイはできてもWebサイトが表示されないことになります。

そこで、src/main.rs を以下のように変更します。

src/main.rs
extern crate iron;
extern crate staticfile;
extern crate mount;

use iron::prelude::*;
use staticfile::Static;
use mount::Mount;
use std::path::Path;
use std::env;

fn get_server_port() -> u16 {
    env::var("PORT").ok()
        .and_then(|p| p.parse().ok())
        .unwrap_or(3000)
}

fn main() {
    let mut mount = Mount::new();

    let routes = ["/", "/about", "/contact"];

    for route in &routes {
        mount.mount(route, Static::new(Path::new("static/index.html")));
    }

    mount.mount("/index.js", Static::new(Path::new("static/index.js")));

    Iron::new(mount).http(("0.0.0.0", get_server_port())).unwrap();
}

これで、自動的に割り当てられた port を取得することができます。

これまでの変更をコミットし、GitHubpush します。

git init
git add .
git commit -am "deploy to Heroku"
git push origin master

あとはDeploy To Heroku ボタンを押すだけです。

参考

Deploying Rust applications to Heroku, with example code for Iron

C++/Vue.js/WebpackでSPAサンプルを作った話

8
11
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
8
11