はじめに
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