Vue 3 + vue-router-nextを動かす

Vue 3のbeta版がリリースされて、あわせて周辺ツールがalphaからbetaへ作業中とのことだったのでvue-router動くかなと思ってやってみた。

github.com

github.com

以下素振りりぽじとり

github.com

プロジェクトのセットアップ

必要なものをyarn addする。

yarn add vue@next vue-router@next

あと開発用にいつもの。lint周りはお好みなので省略

yarn add -D webpack webpack-cli webpack-dev-server ts-loader vue-loader clean-webpack-plugin html-webpack-plugin typescript

webpackの設定書く

webpack.config.js

/* eslint-disable @typescript-eslint/no-var-requires */
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const webpack = require('webpack')

const outputPath = resolve(__dirname, 'dist')

/** @type {import('webpack').ConfigurationFactory} */
const config = (env = {}) => ({
  mode: env.prod ? 'production' : 'development',
  devtool: env.prod ? 'source-map' : 'inline-source-map',
  devServer: {
    contentBase: outputPath,
    historyApiFallback: true,
    hot: true,
    stats: 'minimal',
  },
  output: {
    path: outputPath,
    publicPath: '/',
    filename: 'bundle.js',
  },
  entry: [resolve(__dirname, 'src/main.ts')],
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: 'ts-loader',
      },
      {
        test: /\.vue$/,
        use: 'vue-loader',
      },
    ],
  },
  resolve: {
    alias: {
      vue: '@vue/runtime-dom',
      '~': resolve('src'),
    },
    extensions: ['.ts', 'd.ts', '.tsx', '.js', '.vue'],
  },
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: resolve(__dirname, 'src/index.html'),
    }),
    new CleanWebpackPlugin(),
  ],
})

module.exports = config

適当にエイリアスの設定とかもしておく。

package.jsonに開発鯖起動用のスクリプト書く。

"scripts": {
    "dev": "webpack-dev-server --mode=development",
}

これでsrc/main.tsをエントリポイントとしてサーバーが立ち上がるようになるはず。

composition api + vue-router

viewsにindex.htmlを適当に用意。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Poketto</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>

エントリポイントを定義する。従来とは若干apiが変わっているため注意。

createAppに<router-view />が定義されているメインのコンポーネントを渡し、rootにマウントする。やっていることは今までのVueと同じ。

main.ts

import { createApp } from 'vue'
import App from '~/App.vue'
import { route } from '~/router'

const app = createApp(App)
app.use(route)
app.mount('#root')

現時点でApp.vueもrouterもないので定義していく。

App.vue

<script>
export default {
  name: 'App',
}
</script>

<template>
  <div>
    <router-view />
  </div>
</template>

ページコンポーネントを定義する。

今回はカレントパスとなるindex.vueとサブページsub.vueを作る。なんか表示したかったので適当にcomputedを利用したreadonlyなデータを吐く関数も用意した。(useAppConfig)

vue-routerは既存のthis.$routeからのアクセスではなくなり、useRouterというnamed exportされている関数を用いることでjavascript側からhistoryの操作をすることができる。 router-linkは今まで通りに使えるが、特に型が効いたりはしない。

views/useAppConfig

import { computed } from 'vue'

export const useAppConfig =
  computed(() => {
    return {
      name: 'poketto',
      version: '0.0.1',
      mode: process.env.NODE_ENV,
    }
  })

views/index.vue

<script>
import { useAppConfig } from '~/views/useAppConfig'
import { useRouter } from 'vue-router'

export default {
  name: 'Index',
  setup() {
    const router = useRouter()
    const toSub = () => router.push({ name: 'sub' })
    return {
      useAppConfig,
      toSub
    }
  },
}
</script>

<template>
  <div>
    <p>{{ useAppConfig.name }}</p>
    <p>{{ useAppConfig.version }}</p>
    <p>{{ useAppConfig.mode }}</p>
    <router-link :to="{ name: 'sub' }">
      to sub link
    </router-link>
    <div>
      <button @click="toSub">
        to sub button
      </button>
    </div>
  </div>
</template>

views/sub.vue

<script>
import { useRouter } from 'vue-router'

export default {
  name: 'Index',
  setup() {
    const router = useRouter()
    const toHome = () => router.push({ path: '/' })
    return {
      toHome,
    }
  },
}
</script>

<template>
  <div>
    <p>Sub Page</p>
    <router-link :to="{ path: '/' }">
      home
    </router-link>
    <div>
      <button @click="toHome">
        to sub button
      </button>
    </div>
  </div>
</template>

routerの定義。

useRouterと同様に、新しくrouter作成用の関数などがnamed exportされるようになっているため、これらを使う。

router.ts

import { createRouter, createWebHistory } from 'vue-router'
import Index from '~/views/index.vue'
import Sub from '~/views/sub.vue'

export const routerHistory = createWebHistory()

export const route = createRouter({
  history: routerHistory,
  routes: [
    {
      path: '/home',
      redirect: '/',
    },
    {
      path: '/',
      name: 'index',
      component: Index,
    },
    {
      path: '/sub',
      name: 'sub',
      component: Sub,
    },
  ],
})

ここまでできたらyarn devで動作確認。

f:id:apple19940820:20200428191849g:plain

うごく

おわり

vue-routerはまだalphaなので大きくapiが変わる可能性もあるが、現時点ではちゃんと動作する。

別でフルtsxで書いてみたけどvue-routerはなんか動かなかった。あまり追えてない。

github.com