はじめに
Rust製のWebフレームワーク:Iron
とVue.js
、Webpack
を使って、SPAなWebサイトをHeoku
へとデプロイするチュートリアルです
実際につくったものはこちらです。
前提条件
前提条件として、Rust
と Node.js
がインストールされている必要があります。
また、パッケージマネージャとして yarn
を使用しています。そちらもインストールされている必要があります。
また、 Heroku
のアカウントが既に作成されていることも必要です。
Rust
、Node.js
、yarn
のインストールに関しては下記の記事などを参考にしてください。
rust-guide-ja installing-rust.md
チュートリアル
Hello World
まずは、Hello World
と表示させてみましょう
ひな型を作る
まずは、cargo new iron_vue
でひな型を作成します
cargo new iron_vue
コマンドが終了後、cd iron_vue
でディレクトリを移動します
Ironのインストール
Cargo.toml
に iron = "0.6.0"
を追加します。
[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
を開き、下記のように変更します
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
を作成します。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
Hello World!
</body>
</html>
Iron
側で静的なファイルを使うためのライブラリを追加します。
mount
と staticfile
です。
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
を実行します。
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.js
で Hello World
とブラウザに表示させてみましょう。
static
ディレクトリ内に package.json
を作成します。
{
}
package.json
の中には {}
だけで構いません。
次に、yarn add vue
を実行します。
yarn add vue
コマンド実行後、 package.json
が下記のように変更されていれば Vue.js
はインストールされています。
{
"dependencies": {
"vue": "^2.5.21"
}
}
このままでは Vue.js
が使えないので、 Webpack
を導入します。
static
ディレクトリ内に webpack.config.js
を作成します。
module.exports = {
entry: './src/index.js',
output: {
filename: 'index.js',
path: `${__dirname}`
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
};
そして、 Webpack
と webpack-cli
を yarn
でインストールします
yarn add webpack webpack-cli
上記のコマンドを実行すると、 package.json
が以下のようになっていると思います。
{
"dependencies": {
"vue": "^2.5.21",
"webpack": "^4.28.4",
"webpack-cli": "^3.2.1"
}
}
yarn
でビルドできるように scripts
を追加します。
{
"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
を作成します。
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
を使用できるようにします。
<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
を読み込めるようにします。
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
を下記のように変更します。
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-loader
と css-loader
をインストールします
yarn add style-loader css-loader
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",
"webpack": "^4.28.4",
"webpack-cli": "^3.2.1"
}
}
次に、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-loader
、 vue-template-compiler
です
yarn add vue-loader vue-template-compiler
static/package.json
が下記のようになっていればOKです。
{
"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
で使えるようにします。
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
を作成します。
<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.js
で Header.vue
を import
します。
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>
を追加します。
<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
が以下のようになっていればインストールできています。
{
"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.vue
、About.vue
、Contact.vue
を追加します。
<template>
<div class="container">
<h1>Index Pages</h1>
</div>
</template>
<template>
<div class="container">
<h1>About Pages</h1>
</div>
</template>
<template>
<div class="container">
<h1>Contact Pages</h1>
</div>
</template>
static
ディレクトリ内に router
ディレクトリを作成します。
mkdir router
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.js
に static/router/router.js
を import
します。
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.vue
と static/index.html
を下記のように修正します。
<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>
<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
へルーティングを追加します。
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
へのデプロイボタンを追加します。
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
次に、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
を追加します。
web: ./target/release/iron_vue
Heoku
では port
を自動的に割り当ています。
そのため、現状のコードではデプロイはできてもWebサイトが表示されないことになります。
そこで、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
を取得することができます。
これまでの変更をコミットし、GitHub
へ push
します。
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