先日の Vue と Rails っで取り組んだ認証・ログインの動作を Riot.js で動作させたらどうなるだろうかと考えていました。
取り組んでみたのでレポートします。
目次
参考
準備その前に
今回使用するバックエンドサーバーアプリケーションは、以前作成したものを使います。
サーバー側実装を確認する場合は、そちらを確認ください。
実装
パッケージ導入
1 2 3
| npm install --save-dev webpack webpack-cli webpack-dev-server
npm install --save riot @riotjs/compiler @riotjs/hot-reload @riotjs/route @riotjs/webpack-loader axios qs
|
webpack 設定
以下のwebpack.config.js
を作成します。
localhost:3000
で API サーバーを立ち上げるので/api
以下を、転送するように設定します。
webpack.config.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| module.exports = { mode: "development", entry: `./src/index.js`, output: { path: `${__dirname}/dist`, filename: "app.js", }, module: { rules: [ { test: /\.riot.html$/, exclude: /node_modules/, use: [ { loader: "@riotjs/webpack-loader", options: { hot: true, }, }, ], }, ], }, devServer: { contentBase: "dist", proxy: { "/api": { target: "http://localhost:3000", }, }, }, devtool: "inline-source-map", };
|
.riot
または.riot.html
を@riotjs/webpack-loader
で処理させるようにします。
.riot.html
としておくと、コーディング時にシンタックスハイライトが効くので、今回はこちらを採用します。
公式のドキュメントにて、使用可能な拡張子の項目を見つけられなかったのですが、.riot.html
の使用について議論がありました。
Should we update the riot components extension
マウント先作成
dist/index.html1 2 3 4 5 6 7 8 9 10
| <!DOCTYPE html> <html> <head> <title>webpack-riot</title> </head> <body> <app></app> <script src="app.js"></script> </body> </html>
|
アプリケーション本体作成
エントリーポイントが、以下のsrc/index.js
になります。
src/index.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import * as riot from "riot"; import { Route, Router, router, route } from "@riotjs/route"; import App from "./component/app.riot.html"; import Login from "./component/login.riot.html"; import Home from "./component/home.riot.html";
riot.register("router", Router); riot.register("route", Route); riot.register("app", App); riot.register("login", Login); riot.register("home", Home);
riot.mount("app");
window.router = router;
|
router を各コンポーネントで使うために、グローバルオブジェクトに関連付けしました。
もっと適切な実装がありそうなのですが、うまくいかず今回はこのようにしました。
ページ遷移させる router の部分の実装は以下のようになります。
src/component/app.riot.html1 2 3 4 5 6 7 8 9 10 11
| <app> <router> <route path="/"> <home></home> </route> <route path="/login"> login <login></login> </route> </router> </app>
|
ログイン後のユーザー情報の取得部分のコンポーネントは、以下のようになります。
ユーザーデータの取得に失敗すると、ログイン画面に転送させます。
src/component/home.riot.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <home> <div> {state.name}<br /> <button onclick="{logout}">Log Out</button> </div> <script> const axios = require("axios"); const qs = require("qs");
export default { onBeforeMount(props, state) { this.state = { name: "", }; this.getProfile(); }, async getProfile() { const result = await axios .get("/api/user/profile", { withCredentials: true, }) .catch(function () { router.push("/login"); return; });
if (result === undefined) { return; }
if (result.data.state != "success") { router.push("/login"); return; }
this.state.name = result.data.profile.name; this.update(); }, async logout() { const result = await axios .post("/api/user/log_out", { withCredentials: true, }) .catch(function () { router.push("/login"); });
if (result === undefined) { return; }
router.push("/login"); }, }; </script> </home>
|
ログイン画面のコンポーネントは、以下のようになります。
src/component/login.riot.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <login> <div> <div>{state.msg}</div> <div> <input type="text" id="name" name="name" value="{state.name}" /> </div> <div> <input type="password" id="password" name="password" value="{state.password}" /> </div>
<div> <button type="button" id="send" onclick="{send}">Login</button> </div> </div>
<script> const axios = require("axios"); const qs = require("qs"); const self = this;
export default { onBeforeMount(props, state) { this.state = { name: "", password: "", msg: "", }; }, async send(e) { e.preventDefault();
this.state.name = this.$("#name").value; this.state.password = this.$("#password").value;
this.update();
const self = this; const result = await axios .post("/api/auth/verification", { user: { name: this.$("#name").value, password: this.$("#password").value, }, paramsSerializer: function (params) { return qs.stringify(params, { arrayFormat: "brackets" }); }, }) .catch(function () { self.state.msg = "入力エラー"; self.update(); });
if (result === undefined) { return; }
if (result.data.state == "success") { router.push("/"); } }, }; </script> </login>
|
確認
rails で用意した API をbundle exec rails s
で起動。
webpack-devserver をnpm run serve
で起動。
localhost:8080
にアクセスすると、/login
に転送されます。
用意してある、ID とパスワードを入力するとログインした ID と、ログアウトボタンを表示します。
Riot.js でログインの仕組みを実装できました。
今回は、Riot.js でログインの仕組みを作りました。
実はこの直前に Backbone.js でも試していたのですが、どうにもうまくいかずそちらはお蔵になりました。
ではでは。