# Roteamento e Divisão de Código

# Roteamento com vue-router

Você deve ter notado que nosso código de servidor usa um manipulador * que aceita URLs arbitrários. Isso nos permite passar a URL visitada para nosso aplicativo Vue e reutilizar a mesma configuração de roteamento para cliente e servidor!

Recomenda-se usar a biblioteca oficial vue-router (opens new window) para esta finalidade. Vamos primeiro criar um arquivo onde criamos o roteador. Observe que, semelhante à instância do aplicativo, também precisamos de uma nova instância do roteador para cada solicitação, portanto, o arquivo exporta uma função createRouter:

// router.js
import { createRouter } from 'vue-router'
import MyUser from './components/MyUser.vue'

const routes = [{ path: '/user', component: MyUser }]

export default function (history) {
  return createRouter({
    history,
    routes
  })
}
1
2
3
4
5
6
7
8
9
10
11
12

E atualize nossas entradas de cliente e servidor:

// entry-client.js
import { createSSRApp } from 'vue'
import { createWebHistory } from 'vue-router'
import createRouter from './router.js'
import App from './App.vue'

// ...

const app = createSSRApp(App)

const router = createRouter(createWebHistory())

app.use(router)

// ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// entry-server.js
import { createSSRApp } from 'vue'
// o roteador do servidor usa um histórico diferente do cliente
import { createMemoryHistory } from 'vue-router'
import createRouter from './router.js'
import App from './App.vue'

export default function () {
  const app = createSSRApp(App)
  const router = createRouter(createMemoryHistory())

  app.use(router)

  return {
    app,
    router
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Divisão de Código

Dividir código, ou carregar preguiçosamente parte do seu aplicativo, ajuda a reduzir o tamanho dos assets que precisam ser baixados pelo navegador para a renderização inicial e pode melhorar muito o TTI (tempo até a interatividade) para aplicativos com grandes pacotes. A chave é "carregar apenas o que é necessário" para a tela inicial.

O Vue Router fornece suporte a carregamento preguiçoso (opens new window), permitindo o webpack dividir o código naquele ponto (opens new window). Tudo que você precisa fazer é:

// mude isso...
import MyUser from './components/MyUser.vue'
const routes = [{ path: '/user', component: MyUser }]

// para isso:
const routes = [
  { path: '/user', component: () => import('./components/MyUser.vue') }
]
1
2
3
4
5
6
7
8

Tanto no cliente quanto no servidor, precisamos esperar que o roteador resolva os componentes de rota assíncrona antecipadamente para invocar corretamente os gatilhos no componente. Para isso, usaremos o método router.isReady (opens new window). Vamos atualizar nossa entrada de cliente:

// entry-client.js
import { createSSRApp } from 'vue'
import { createWebHistory } from 'vue-router'
import createRouter from './router.js'
import App from './App.vue'

const app = createSSRApp(App)

const router = createRouter(createWebHistory())

app.use(router)

router.isReady().then(() => {
  app.mount('#app')
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Também precisamos atualizar nosso script server.js:

// server.js
const path = require('path')

const appPath = path.join(__dirname, './dist', 'server', manifest['app.js'])
const createApp = require(appPath).default

server.get('*', async (req, res) => {
  const { app, router } = createApp()

  await router.push(req.url)
  await router.isReady()

  const appContent = await renderToString(app)

  fs.readFile(path.join(__dirname, '/dist/client/index.html'), (err, html) => {
    if (err) {
      throw err
    }

    html = html
      .toString()
      .replace('<div id="app">', `<div id="app">${appContent}`)
    res.setHeader('Content-Type', 'text/html')
    res.send(html)
  })
})
1
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