В прошлый раз, когда я поделился с вами статьей VUE об изоморфном расширении прав и возможностей VUE SSR, ссылка здесь.
nuggets.capable/post/684490…
Сегодня следующая статья: NUXT
Прошлая статья может быть слишком сложной, в этот раз давайте сразу к теме
В последнем DEMO мы использовали NUXT для реализации этой страницы.
Адрес гитхаба в конце статьи.
Nuxt
Nuxt — это фреймворк для рендеринга на стороне сервера, который интегрирует Vue-Router, Vuex, webpack и другие фреймворки и компоненты на основе Vue ssr.
На мой взгляд, Nuxt — это обновленная версия Vue ssr, которая предустановляет различные конфигурации, необходимые для серверных приложений.
Но, соответственно, инвазивность Nuxt очень высока, нам нужно понять мышление Nuxt, чтобы воспользоваться им.
Структура каталогов
Во-первых, давайте взглянем на структуру каталогов проекта Nuxt.
Нет конфигурации входных и внутренних записей, нет конфигурации веб-пакета.
Все, что нам нужно сделать, это «сосредоточиться на бизнесе»
Конкретную папку можно увидеть
assets - файлы ресурсов внешнего интерфейса
компоненты - интерфейсные общие компоненты
layouts — Компоненты макета внешнего интерфейса
store - vuex
статические - статические файлы
плагины - плагины
промежуточное ПО - промежуточное ПО
страницы - страницы внешнего интерфейса VUE
сервер - бэкенд
На самом деле столько файлов можно разделить на три:интерфейс, бэкэнд, ресурсы
соглашение о конфигурации
В Nuxt повсюду идея «конвенция важнее конфигурации», на это стоит обратить внимание.
Например, в простейшем случае имя вышеуказанной папки каталога нельзя изменить без дополнительной настройки.
Так же есть например: макеты в файле макета
default.vue — это страница макета по умолчанию.
error.vue — страница ошибки по умолчанию
Например, в папке front-end страницы pages согласовываются правила автоматической генерации маршрутизаторов.
Также в папке магазина index.js по умолчанию является деревом состояний по умолчанию,
файл todos.js будетАвтоматически генерировать модуль todos
так далее……
Эти особенности будут подробно рассмотрены ниже.
макет/маршрутизация
Теперь начните писать нашу демонстрацию,
Начнем со страницы макета, нам нужно написать две страницы default.vue и error.vue
Страницу макета можно рассматривать как нашу обычную страницу входа app.vue в vue.
Но они разные.В подстранице Nuxt можно указать страницу макета (default.vue, если не указано)
default.vue
<template>
<div>
<header>
<div class="head-content">
<section class="head-left">
一个帮助开发者成长的社区 |
<nuxt-link to="/"> 首页</nuxt-link>
</section>
<section class="head-right">
<nuxt-link to="/user/login"> 登录</nuxt-link>
|
<nuxt-link to="/user/register"> 注册</nuxt-link>
</section>
</div>
</header>
<nuxt />
</div>
</template>
Макет настроек подстраницы
export default {
// 默认就是default
layout: "default",
}
и
Мы видим два компонента
Фактически это соответствующий
Таким образом, страница макета или наша вложенная страница маршрутизации должны использовать компонент
Мы видим в исходном коде:
// nuxt
let routerView = [
h('router-view', data)
]
if (props.keepAlive) {
routerView = [
h('keep-alive', { props: props.keepAliveProps }, routerView)
]
}
return h('transition', {
props: transitionProps,
on: listeners
}, routerView)
// nuxt-link
export default {
name: 'NuxtLink',
extends: Vue.component('RouterLink'),
}
является расширением vue-router
где
Можно отключить с помощью атрибута no-prefetch.
<nuxt-link to="/user" no-prefetch>个人中心</nuxt-link>
Автоматически строить маршруты
Маршрутизация строится автоматически в Nuxt, что очень полезно и поможет нам сократить объем работы по настройке.
На самом деле во всех проектах SSR, на самом деле, для достижения изоморфизма внешнего и заднего конца, это зависит от маршрутизации, чтобы определить вход в выходной и задний конец, чтобы вывести выходной сигнал.
Давайте посмотрим на правила построения маршрутов в Nuxt.
Короче говоря, я подытожил три пункта:
- Автоматически создавать маршруты с одинаковым именем на основе имен каталогов и файлов.
- Создавайте динамические маршруты на основе _underscore
- Создавайте вложенные маршруты на основе папки с тем же именем, что и файл vue.
Давайте посмотрим на нашу демонстрацию, нам нужен персональный центр и страница со списком
Итак, наша структура каталогов выглядит так
Окончательный сборник Router.js выглядит следующим образом:
routes: [{
path: "/user/login",
component: _fade0492,
name: "user-login"
}, {
path: "/user/register",
component: _35d3a876,
name: "user-register"
}, {
path: "/info/:pageIndex?",
component: _287821ee,
name: "info-pageIndex"
}, {
path: "/",
component: _48b188ea,
name: "index"
}]
Как видите, страница со списком генерирует маршрут /info/:pageIndex?
Мы можем получить доступ к данным соответствующего номера страницы через /info/1 или /info/2
Давайте снова посмотрим на _pageIndex.vue
<template>
<div>
<vmenu type="info" />
<div class="info-container">
<div class="info-title">热门信息</div>
<ul class="info-content">
<li v-for="item in list" :key="item.title">
<section class="info-content-r">{{ item.publishDate }}</section>
<section class="info-content-l">{{ item.title }}</section>
</li>
</ul>
<vpage :count="count" url="info" :pageIndex="pageIndex" />
</div>
</div>
</template>
page.vue
<template>
<div class="page-container">
<section>
<router-link :to="{ name: toUrl, params: { pageIndex: 1 } }">
第一页
</router-link>
</section>
<section
v-for="(i, ix) in pageCount"
:key="i"
:class="{ current: pageIndex == ix + 1 }"
>
<router-link :to="{ name: toUrl, params: { pageIndex: ix + 1 } }">
{{ ix + 1 }}
</router-link>
</section>
<section>
<router-link :to="{ name: toUrl, params: { pageIndex: pageCount } }">
最后一页
</router-link>
</section>
</div>
</template>
<script>
export default {
name: "page",
props: {
pageSize: { default: 10 },
pageIndex: { default: 1 },
count: { default: 100 },
url: { default: "" }
},
computed: {
toUrl() {
return this.url + "-pageIndex";
},
pageCount() {
return this.count % this.pageSize == 0
? this.count / this.pageSize
: Math.floor(this.count / this.pageSize) + 1;
}
},
mounted() {},
created() {}
};
</script>
Вы можете видеть, потому что автоматически созданное имя маршрута - info-pageIndex
Поэтому, когда мы переходим на страницу, нам также нужен соответствующий маршрут сплайсинга.
Асинхронные данные
Асинхронный сбор данных — необходимая функция проекта SSR, которая довольно проста в Nuxt.
asyncData
asyncData очень знаком, в VUR SSR есть тот же метод для загрузки асинхронных данных.
Но но
Метод asyncData в Nuxt совершенно другой.
Здесь можно не только получить асинхронные данные, но и монтировать конечные данные на данные.
Давайте посмотрим на демо здесь и получим список новостей из фона:
export default {
async asyncData({
isDev,
route,
store,
env,
params,
query,
req,
res,
redirect,
error,
$axios
}) {
let data = await $axios.post(`/api/news/list`, {
page: params.pageIndex || 1
});
return { ...data.data };
},
components: {
vmenu: Menu,
vpage: page
},
// router.path是不一样的,不用监听
// watchQuery: ["pageIndex"],
data() {
return {
pageIndex: this.$route.params.pageIndex || 1
};
}
};
Здесь axios должен использовать официальный модуль Nuxt @nuxt/axios, который автоматически выполнит другие оптимизации, такие как заполнение заголовка.
Короче говоря, это так просто, мы получаем данные асинхронно, а затем можем их вернуть.
После этого компонент такой же, как мы обычно используем данные в данных.
fetch
Давайте посмотрим на выборку, На самом деле выборка очень похожа на asyncData в Vue SSR.
Он не будет привязан к данным, он используется только для работы с хранилищем.
Использование заключается в следующем:
<template>
<h1>Stars: {{ $store.state.stars }}</h1>
</template>
<script>
export default {
fetch ({ store, params }) {
return axios.get('http://my-api/stars')
.then((res) => {
store.commit('setStars', res.data)
})
}
}
</script>
По сравнению с VUESSR асинхронные данные в Nuxt более чистые и могут быть реализованы без помощи VUEX.
Магазин возвращается к сути разделения состояния
vuex
Давайте посмотрим, как vuex используется в Nuxt.
На самом деле, как я сказал в начале, Nuxt соглашается с тем, что index.js в каталоге хранилища является деревом состояний по умолчанию.
Для файлов с другими именами будут сгенерированы соответствующие модули хранилища
Итак, давайте напишем хранилище, которое сохраняет состояние входа в систему.
магазин /user.js
export const state = () => {
user: null
};
export const mutations = {
// 设置登录用户
set(state, user) {
state.user = user;
},
loginOut(state) {
state.user = null;
}
}
nuxtServerInit
Один вопрос, когда мы записываем статус входа в магазин?
Думая о наших обычных приложениях, записывая файлы cookie или localstorage, это лучшее решение.
Но у нашего проекта SSR есть преимущество, мы можем тесно интегрироваться с бэкендом.
Мы можем использовать nuxtServerInit, чтобы записать статус входа клиента в sotre.
Обратите внимание, что nuxtServerInit будет выполняться только тогда, когда сервер вызывает
store/index.js
export const actions = {
nuxtServerInit({ commit }, { req }) {
if (req.session.user) {
commit("user/set", req.session.user);
}
}
}
Таким образом, последний статус входа в систему клиента может поддерживаться все время (конечно, после успешного входа в систему он также должен быть записан в магазин).
middleware
Так как же интерфейсная страница определяет статус входа?
Лучше судить, когда переключается каждый маршрут, например, в router.beforeEach.
Но маршруты Nuxt строятся автоматически, и нет связанного интерфейса
Но не волнуйтесь, у нас есть промежуточное ПО получше
Промежуточное ПО может выполняться до того, как указанная нами страница будет загружена, и может выполнятьсяАсинхронное выполнение
Промежуточное ПО можно установить на странице макета, чтобы все страницы макета выполняли промежуточное ПО.
Давайте посмотрим на демонстрационный пример промежуточное ПО/default.js
export default function ({ route, store, redirect }) {
// 如果用户不存在,跳到登录页面
if (!store.state.user.user)
redirect('/user/login?redirect=' + route.path);
}
Обратитесь к промежуточному программному обеспечению на странице _pageIndex.vue.
middleware: "default"
После ссылки, если вы не вошли в систему, вы автоматически перейдете на страницу входа
Модули/плагины
Nuxt имеет множество модулей, которые мы можем использовать
Официальные модули:
@nuxt/http: легкий и универсальный HTTP-запрос на основе ky-universal.
@nuxtjs/axios: безопасная и простая в использовании интеграция Axios с Nuxt.js для HTTP-запросов.
@nuxtjs/pwa: усовершенствуйте Nuxt с помощью проверенного, обновленного и стабильного решения PWA.
@nuxtjs/auth: Модуль аутентификации для Nuxt.js, предоставляющий различные схемы и стратегии аутентификации.
Есть еще модули сообщества:
GitHub.com/topics/гнев утихает…
Способ использования тоже очень простой, прямо в nuxt.config.js Например:
modules: [
['@nuxtjs/axios', { baseURL: 'http://localhost:3000' }],
],
Конечно, мы по-прежнему будем ссылаться на некоторые плагины сами, мы можем использовать конфигурацию плагинов
plugins: [
{ src: '@/plugins/element-ui', ssr: false }
],
Обратите внимание, что если наш плагин может работать только на стороне сервера, мы можем настроить ssr: false, и тогда внешний интерфейс также может использоваться с компонентом
Затем разверните каталог плагинов, где нам доступен объект Vue.
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Element, { locale })
Жизненный цикл
На этом наша демонстрационная страница готова.
Стоит отметить различия в жизненном цикле Nuxt.
Nuxt extension asyncData, fetch, validate, промежуточное ПО будет выполняться как на переднем, так и на заднем концах.
nuxtServerInit, serverMiddleware будет выполняться на стороне сервера
Такие методы, как перенаправление и обнаружение ошибок, могут использоваться на переднем и заднем концах.
Но такие как req, res и тому подобное, внешний интерфейс не определен, на что также нужно обращать внимание в любое время.
тайник
Наконец, давайте посмотрим на кеш
Кэш компонентов такой же, как у VUESSR, элементы кеша настраиваем в nuxt.config.js
const LRU = require('lru-cache')
module.exports = {
render: {
bundleRenderer: {
cache: LRU({
max: 1000,
maxAge: 1000 * 60 * 15
})
}
}
}
Затем укажите serverCacheKey в компоненте, и все в порядке.
export default {
props: ['type'],
serverCacheKey: props => props.type
}
serverMiddleware
Кэширование на уровне страницы немного особенное, нам нужно использовать промежуточное ПО Nuxt на стороне сервера.
Здесь мы используем упомянутый выше redis-lru для повторного кэширования страниц.
const config = require('../nuxt.config.js')
module.exports = async function (req, res, next) {
if (process.env.NODE_ENV === "development") {
next();
return;
}
const redis = require('redis').createClient(config.redis);
const lru = require('redis-lru');
const cache = lru(redis, 100);
// 获取缓存的key值
let key = req.originalUrl
const value = await cache.get(key)
if (value) {
console.log('cached output', key);
return res.end(value, 'utf-8')
}
res._end = res.end
res.end = async function (data) {
if (res._headers['content-type'].startsWith('text/html')
&& res.statusCode === 200) {
await cache.set(key, data)
}
res._end(data, 'utf-8')
}
next();
}
Стоит отметить, что req и res в промежуточном программном обеспечении на стороне сервера являются объектами http-запроса Node.js.
Окончательный вывод должен вызывать исходный метод конца res (Даже если ваш внутренний сервер, настроенный Nuxt, является koa)
Эпилог
Хорошо, я закончил первую часть моей серии VUE SSR.
По сравнению с VUESSR, Nuxt является обновленной версией.Если вы новый стартап-проект, рекомендуется начать прямо с Nuxt.
Если вы хотите испытать весь процесс SSR, вы можете настроить VUESSR с нуля, и у вас будет другой опыт.
Демонстрационный адрес этого Nuxt находится здесь:GitHub.com/sleepy GitHub/ — это…