Riot.js Advent Calendar 2019 の5日目が空いていたので埋めます。
Riot Router
Riot.js
がv4
になったことでRiot Router
も新しくなっていたので再入門します。
https://github.com/riot/route
インストールはnpm i -S @riotjs/route
簡単なサンプル
まずは簡単なコードから試していきます。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Riot Router</title>
</head>
<body>
<div id="app"></div>
<script src="./scripts/bundle.js"></script>
</body>
</html>
index.js
import { component, register } from 'riot'
import { Router, Route } from '@riotjs/route'
import App from './app.riot'
import Hello from './hello.riot'
import Goodbye from './goodbye.riot'
// グローバルコンポーネントとして登録
register('my-router', Router);
register('my-route', Route);
register('my-hello', Hello);
register('my-goodbye', Goodbye);
// グローバルに登録せずに直接コンポーネントを生成&マウント
component(App)(document.getElementById('app'));
app.riot
<my-app>
<my-router>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/hello">Hello</a></li>
<li><a href="/goodbye">Goodbye</a></li>
</ul>
</nav>
<my-route path="/">
Welcome to home
</my-route>
<my-route path="/hello">
<my-hello></my-hello>
</my-route>
<my-route path="/goodbye">
<my-goodbye></my-goodbye>
</my-route>
</my-router>
</my-app>
hello.riot
<my-hello>
<p>Hello World!!</p>
</my-hello>
goodbye.riot
<my-goodbye>
<p>Goodbye World!!</p>
</my-goodbye>
私はWebpackを使っていますが、ここから下はお好みで。
package.json
{
"name": "riotv4-router-sample",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --mode production --devtool source-map",
"start": "webpack-dev-server --inline --watch --hot --colors --content-base app/ --open-page index.html -d --port 4500"
},
"keywords": [],
"author": "KAJIKEN <kentaro@kajiken.jp> (http://kajiken.jp)",
"license": "MIT",
"dependencies": {
"@riotjs/route": "^4.1.0"
},
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/preset-env": "^7.7.1",
"@riotjs/compiler": "^4.5.2",
"@riotjs/hot-reload": "^4.0.0",
"@riotjs/webpack-loader": "^4.0.1",
"babel-loader": "^8.0.6",
"riot": "^4.6.6",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
}
}
webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
//mode: 'production',
entry: './src/scripts/index.js',
output: {
path: path.resolve(__dirname, 'app/scripts'),
filename: 'bundle.js',
publicPath: '/scripts/',
},
devtool: 'inline',
//devtool: 'source-map',
module: {
rules: [
{
test: /\.riot$/,
exclude: /node_modules/,
use: [{
loader: '@riotjs/webpack-loader',
options: {
hot: true, // set it to true if you are using hmr
// add here all the other @riotjs/compiler options riot.js.org/compiler
// template: 'pug' for example
}
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
}
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"targets": [
">0.25%",
"not ie 11",
"not op_mini all"
]
}
]
]
}
ディレクトリ構成
.
│ .babelrc
│ package.json
│ webpack.config.js
│
├─app
│ │ index.html
│ │
│ └─scripts
│ bundle.js
│ bundle.js.map
│
├─node_modules
│
└─src
└─scripts
app.riot
goodbye.riot
hello.riot
index.js
注意点
このままではURLを直接入力した場合はエラーになります。
Web Server側の設定でトップに飛ばすなどすれば回避は可能です。
今回の例ですと、webpack-dev-server
を使っているので、historyApiFallback
オプションを利用します。
package.json(抜粋)
"scripts": {
"build": "webpack --mode production --devtool source-map",
"start": "webpack-dev-server --inline --watch --hot --colors --content-base app/ --open-page index.html --historyApiFallback true -d --port 4500"
},
historyApiFallback:true
とすることで404 not found
の時にindex.html
に飛ばされます。
Web Server側で対処できないような場合はハッシュを使いましょう。
app.riot
<my-app>
<my-router>
<nav>
<ul>
<li><a href="#/">Home</a></li>
<li><a href="#/hello">Hello</a></li>
<li><a href="#/goodbye">Goodbye</a></li>
</ul>
</nav>
<my-route path="(/|/#/)">
Welcome to home
</my-route>
<my-route path="/#/hello">
<my-hello></my-hello>
</my-route>
<my-route path="/#/goodbye">
<my-goodbye></my-goodbye>
</my-route>
</my-router>
</my-app>