from the Core

 

Почему начать с Nuxt быстрее чем vue-ssr?

Nuxt - готовое решение из коробки, включающее в себя vue-ssr

 

vue-ssr - низкоуровневая библиотека для ssr рендеринга

В Nuxt интегрированы  наиболее используемые vue библиотеки

 

  • vue-meta (опционально, для мета тегов и SEO)
  • vue-router
  • vuex ( опционально)

Библиотеки для сборки

  • Babel (вместе с собственном конфигом nuxt)
  • Настроенный и оптимизированный конфиг webpack
  • PostCSS уже включен и настроен

ОПРЕДЕЛЕННАЯ СТРУКТУРА ПРОЕКТА

  • Одна и таже структура для всех проектов
  • Место для практически каждого файла

Улучшенная функциональность компонентов

 

  • asyncData / fetch для страниц
  • анимации для перехода между страницами
  • Layouts

Модули

Для Nuxt имеется множество готовых модулей:

  • @nuxt/http
  • @nuxt/pwa
  • @nuxt/auth
  • и другие
  • @nuxtjs/apollo

Поддержка Typescript

  • @nuxt/typescript-build - поддержка typescript для layouts, components, plugins и middlewares
  • @nuxt/typescript-runtime - поддержка typescript для nuxt.config, локальных модулей и server-middleware

  • @nuxt/types - типы для всех классов nuxt

router.js

 

Роутинг на основе файловой системы

 

Роутинг на основе файловой системы

 

import user from '....'
import cart from '....'
import favorites from '....'
import Vuex from 'vuex'

const createStore = () => {
  return new Vuex.Store({
    namespaced: true,
    state: () => ({
      query: ''
    }),
    mutations: {
      updateQuery(state, query) {
        state.query = query;
      }
    },
    modules: {
      user,
      cart,
      favorites,
    },
    actions: {
      async newSearch({dispatch, commit}, data) {
        //...
      },

      async populateQuery({dispatch, commit}, query) {
        //...
      }
    },
    getters: {
      getQuery: state => state.query,
      getLoading: state => state.isLoading
    },
  })
};

VUEX

 

классический vuex store

	
export const state = () => ({/**/})
 
export const mutations = {/**/}
 
export const actions = {/**/}
 
export const getters = {/**/}

Теперь NUXT way с использованием файловой системы

 

один модуль на файл

 


export default {
  setName(state, name){
    state.name = name
  },
  // и другие мутации
}

Модуль как директория

Developer Experience

Улучшенные логи с consola

Логи с SSR в консоли браузера

Прогресс бар при hot reload проекта

Экран загрузки при билде проекта

Оптимизация SSR

 

render: {
    compressor: false
}
  • отключение компрессии на уровне nuxt
  • использование кеширующего сервера, например nginx

 

  • extractCss в случае большого css бандла

Экспериментальное отключение функционала

 

 features: {
    router: true,
    store: true,
    layouts: true,
    meta: true,
    middleware: true,
    transitions: true,
    deprecations: true,
    validate: true,
    asyncData: true,
    fetch: true,
    clientOnline: true,
    clientPrefetch: true,
    clientUseUrl: false,
    componentAliases: true,
    componentClientOnly: true
  }

Отключение неиспользуемых функций

 

Все включено

 

Минимально необходимый набор

 

Экспериментальное отключение функционала

 

autocannon -d 60 http://localhost:3000
Running 60s test @ http://localhost:3000
10 connections

Stat    2.5% 50%  97.5% 99%   Avg     Stdev   Max
Latency 4 ms 4 ms 8 ms  10 ms 4.67 ms 1.42 ms 19.37 ms

Stat      1%      2.5%    50%     97.5%   Avg     Stdev  Min
Req/Sec   1655    1764    1951    2038    1931.57 78.95  1655
Bytes/Sec 5.88 MB 6.27 MB 6.93 MB 7.24 MB 6.86 MB 280 kB 5.88 MB

Req/Bytes counts sampled once per second.

116k requests in 60.08s, 412 MB read
autocannon -d 60 http://localhost:3000
Running 60s test @ http://localhost:3000
10 connections

Stat    2.5% 50%  97.5% 99%   Avg      Stdev   Max
Latency 8 ms 9 ms 16 ms 18 ms 10.12 ms 2.25 ms 30.38 ms

Stat      1%      2.5%    50%     97.5%   Avg     Stdev  Min
Req/Sec   784     805     951     1046    942.29  57.03  784
Bytes/Sec 3.68 MB 3.78 MB 4.47 MB 4.91 MB 4.42 MB 268 kB 3.68 MB

Req/Bytes counts sampled once per second.

57k requests in 60.09s, 265 MB read

Все включено

 

Минимально необходимый набор

 

2X разница в производительности

 

Оптимизация кода

  • асинхронные компоненты
<template>
 <div>
   <SyncComponent />
   <AsyncComponent />
 </div>
</template>
<script>
import AsyncComponent from '~/components/AsyncComponent.vue'
import SyncComponent from '~/components/SyncComponent.vue'

export default {
  components: {
    SyncComponent,
    AsyncComponent: () => import('~/components/AsyncComponent.vue')
  }
}
</script>
  • ClientOnly тег для тяжелых комопнентов

Vue-lazy-hydration

<!-- по списку событий-->
<LazyHydrate on-interaction="['fullscreen', 'mousedown']">
...
</LazyHydrate>


<!-- По видимости -->
<LazyHydrate when-visible>
...
</LazyHydrate>

<!-- когда процессор не занят -->
<LazyHydrate when-idle>
....     
</LazyHydrate>

<!-- только на сервере -->
<LazyHydrate ssr-only>
  ...
</LazyHydrate>

<!-- контролируемая гидрация -->
<LazyHydrate ssr-only :trigger-hydration="isItReady">
 <ArticleContent :content="article.content"/>
</LazyHydrate>

    
<script>
import LazyHydrate from 'vue-lazy-hydration';

export default {
  components: {
    LazyHydrate,
    // The `ArticleContent` будет импортирован только если isItReady true
    ArticleContent: () => import('./ArticleContent.vue'),
  },
  // ...
};
</script>
yarn add vue-lazy-hydration
<template>
  <div class="ArticlePage">
    <ImageSlider/>
    <ArticleContent :content="article.content"/>
    <AdSlider/>
    <CommentForm :article-id="article.id"/>
  </div>
</template>

<script>
import {
  hydrateOnInteraction,
  hydrateSsrOnly,
  hydrateWhenIdle,
  hydrateWhenVisible,
} from 'vue-lazy-hydration';

export default {
  components: {
    AdSlider: hydrateWhenVisible(
      () => import('./AdSlider.vue'),
      // Optional.
      { observerOptions: { rootMargin: '100px' } },
    ),
    ArticleContent: hydrateSsrOnly(
      () => import('./ArticleContent.vue'),
      { ignoredProps: ['content'] },
    ),
    CommentForm: hydrateOnInteraction(
      () => import('./CommentForm.vue'),
      // `focus` is the default event.
      { event: 'focus', ignoredProps: ['articleId'] },
    ),
    ImageSlider: hydrateWhenIdle(() => import('./ImageSlider.vue')),
  },
  // ...
};
</script>

Врапперы импортов

Vue-lazy-hydration

После

 

До

 

Vue-lazy-hydration

Анализирование бандла

nuxt build --analyze

Что нового готовит NUXT 3

  • Новое cli для создание проекта nuxt create 
  • Новый метод fetch, asyncData deprecated
  • Режимы билда nuxt для разных платформ

server

static

serverless

  • Автоматический импорт плагинов, компонентов, миддлваре
  • Полностью статический режим
  • Webpack 5

nuxt/blueprints

 

  • микро фреймворки на основе модулей nuxt
  • создано на основе NuxtPress
  • микро фреймворки на основе модулей nuxt
  • множественные инстансы одного blueprint
  • поддержка вебпак алиасов в  темплейтах
  • автоматическое определение и добавление шаблонов .tmpl
  • копирование темплейтов из каждого инстанса blueprint

nuxt/blueprints

 

import ExampleBlueprint from './blueprint'

export default {
  modules: [
    function exampleBlueprint () {
      const options1 = {
        id: '1',
        backgroundColor: 'gold'
      }

      const options2 = {
        id: '2',
        backgroundColor: 'silver'
      }

      new ExampleBlueprint(this.nuxt, options1).init()
      new ExampleBlueprint(this.nuxt, options2).init()
    }
  ]
}

Использование blueprint

blueprint/css/style.tmpl.css

div {
  background-color: <%= options.backgroundColor %>;
  padding: 1rem;
  margin: 1rem auto;
}

blueprint/components/hello.tmpl.vue

<template>
  <div>
    <h2>Hello from ExampleBlueprint instance <%= options.id %></h2>
    <p>With a fancy background</p>
  </div>
</template>

<style scoped>
@import url('../css/style.css')
</style>

Шаблоны

Немного о том, как Nuxt.js устроен изнутри

 

Пакеты nuxt

@nuxt/builder

@nuxt/cli

@nuxt/core

@nuxt/generator

@nuxt/webpack

@nuxt/webpack

Внешние плагины

@nuxt/friendly-errors-webpack-plugin
time-fix-plugin
extract-css-chunks-webpack-plugin
hard-source-webpack-plugin
terser-webpack-plugin
webpackbar
optimize-css-assets-webpack-plugin
html-webpack-plugin

Middleware

webpack-dev-middleware
webpack-hot-middleware

Внутренние плагины

warning-ignore
CorsPlugin
ModernModePlugin
VueSSRServerPlugin
VueSSRClientPlugin

Postcss Config

@nuxt/core

Resolver 

Module

Nuxt

@nuxt/config
@nuxt/server
@nuxt/vue-renderer

addPlugin

addTemplate

addLayout

addErrorLayout

addModule

resolveAlias

resolveModule

resolvePath

Обработка nuxt.config

Настройка сервера, используется библиотека connect

Компиляция vue шаблонов

Renderer

SPA

SSR

MODERN

@nuxt/cli

NuxtCommand

Options

build

dev

generate

help

index

start

common

locking

server

list

run

@nuxt/builder

watch

@nuxt/devalue

валидация ( validatePages, validateTemplate )

serialize-javascript

Builder

Сериализация данных

резолвинг ( resolveRoutes, resolveLayouts, resolveStore, resolveMiddleware, resolveCustomTemplates, resolvePlugins)

build & generate

TemplateContext

router, store, plugins, isDev, etc

@nuxt/vue-app

lodash темплейты

'App.js',
  'client.js',
  'index.js',
  'router.js',
  'router.scrollBehavior.js',
  'server.js',
  'utils.js',
  'empty.js',
  'components/nuxt-error.vue',
  'components/nuxt-child.js',
  'components/nuxt-link.server.js',
  'components/nuxt-link.client.js',
  'components/nuxt.js',
  'views/app.template.html',
  'views/error.html'

пакеты nuxt

@nuxt/builder

@nuxt/cli

@nuxt/core

@nuxt/generator

@nuxt/webpack

nuxt

nuxt-start

@nuxt/cli

@nuxt/core

nuxt-edge & nuxt-start-edge