Серверный рендеринг Vue (SSR), Nuxt.js — от входа к практике

сервер Vue.js axios Nuxt.js

предисловие

В начале октября мне посчастливилось получить от компании официальный запрос на пересмотр веб-сайта, требующий использования режима рендеринга на стороне сервера для оптимизации исходного веб-сайта для SEO.

Из-за стека технологий vue, который использовала команда, первое, о чем я подумал, это использовать vue server-side rendering (SSR) для выполнения этого требования, что может снизить стоимость последующего обслуживания другими членами команды и инкапсулировать другие. существующие проекты. Контент можно напрямую копировать и использовать с небольшими изменениями, что значительно экономит время разработки (за исключением промежуточной настройки пользовательского интерфейса, общее время преобразования заняло всего 2-3 дня).

Сравнение до и после ремонта

1. Оригинальный сайт компании (до доработки), с использованиемвью (СПА)разработка шаблона

URL-адрес:www2.nicomama.com/временно закрыт

2. Новый сайт компании (после доработки), с использованиемРендеринг на стороне сервера Vue (SSR)разработка шаблона

URL-адрес:www.nicomama.com/

Конечно, когда вы открываете его прямо из браузера, вы видите только два веб-сайта, но стиль и интерфейс были обновлены.

Затем давайте посмотрим на разницу между двумя веб-сайтами.Используйте браузер Chrome, чтобы открыть два веб-сайта соответственно, и щелкните правой кнопкой мыши, чтобы просмотреть исходный код.

Скриншот ниже:

1. До ревизии

2. После доработки

Хорошо видно, что после доработки исходный код сайта увеличился более чем в несколько раз.Короче говоря, режим серверной отрисовки таков: при запросе URL-адреса серверная сторона сначала генерирует html-контент, а затем затем возвращается после получения запроса в браузер. Таким образом, поисковая система может сканировать другие страницы веб-сайта с помощью возвращенного вами тега и т. д., поисковая система может включать все (открытые) пути веб-сайта, и я покажу вам веб-сайт после проверки. , Некоторые данные поиска меняются.

Прежде чем читать следующий контент, рекомендуется ознакомиться с «Руководством по Vue SSR», это адрес документаBirthday.v UE JS.org/this/#%E4%BB%…

текст

Далее, введение концепции Vue SSR и сравнение преимуществ и недостатков являются тезисами концепции, упомянутыми в документе.Те, кто читал документ, могут его игнорировать~

Vue SSR

Короче говоря, это поместить компоненты, которые были изначально созданы в браузере, создать их на сервере, затем сгенерировать соответствующий html и отправить их непосредственно в браузер, и, наконец, «активировать» эти статические теги на клиенте.Полностью интерактивный заявление.

Преимущества и недостатки Vue SSR по сравнению с SPA (одностраничное приложение)

1. Преимущества

  1. Лучшее SEO, так как сканеры поисковых систем могут напрямую просматривать полностью обработанные страницы.

  2. Более быстрое получение контента, особенно для медленных сетевых условий или медленных устройств.

2. Недостатки

1) Ограничено условиями разработки. Код, зависящий от браузера, который можно использовать только в определенных обработчиках жизненного цикла; некоторые внешние библиотеки могут потребовать специальной обработки для запуска в приложениях, отображаемых на сервере.

2) Дополнительные требования, связанные с установкой и развертыванием сборки. В отличие от полностью статических одностраничных приложений (SPA), которые можно развернуть на любом статическом файловом сервере, для приложений, отображаемых на сервере, требуется среда выполнения сервера Node.js.

3) Большая нагрузка на сервер. Рендеринг полного приложения в Node.js, очевидно, потребует больше ресурсов ЦП, чем сервер, который просто обслуживает статические файлы (интенсивность ЦП — интенсивный ЦП), поэтому, если вы планируете использовать его в среде с высоким трафиком, подготовьтесь к соответствующему загружайте сервер и разумно применяйте стратегию кэширования.

После понимания концепции давайте реализуем первый экземпляр Vue SSR~

Примечание. Для следующего содержимого требуется определенная основа vue.

По сравнению с vue SPA (одностраничное приложение), Vue добавил некоторые инструменты расширения.Во-первых, давайте взглянем на более важный инструмент, vue-server-renderer.Из названия видно, что он используется для серверной части. рендеринг.

Давайте посмотрим на его функции и использование

1. Создайте пустой проектmkdir vuessr && cd vuessr

2. Бегиnpm initинициализировать

3. Устанавливаем нужные нам зависимостиcnpm install vue vue-server-renderer --save

4. Создатьindex.jsкод показывает, как показано ниже:

// 第 1 步:创建一个 Vue 实例
const Vue = require('vue')
const app = new Vue({
  template: `<div>Hello World</div>`
})

// 第 2 步:创建一个 renderer
const renderer = require('vue-server-renderer').createRenderer()

// 第 3 步:将 Vue 实例渲染为 HTML
renderer.renderToString(app, (err, html) => {
  if (err) throw err
  console.log(html)
  // => <div data-server-rendered="true">Hello World</div>
})

5. Бегиnode index.jsВы можете увидеть вывод в консоли

    <div data-server-rendered="true">Hello World</div>

Мы помещаем сгенерированный html в указанный шаблон html, а затем возвращаемся в браузер, чтобы реализовать функцию рендеринга на стороне сервера?

6. Зависимости установкиcnpm install express --save

7. Создатьapp.jsкод показывает, как показано ниже:

const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()

server.get('*', (req, res) => {
  const app = new Vue({
    data: {
      url: req.url
    },
    template: `<div>访问的 URL 是: {{ url }}</div>`
  })

  renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.end(`
      <!DOCTYPE html>
      <html lang="en">
        <head><title>Hello</title></head>
        <body>${html}</body>
      </html>
    `)
  })
})

server.listen(8080)

8. Бегиnode app.js

9, откройте ввод браузераhttp://localhost:8080/Обнаружено, что наш контент был отображен.Если некоторые учащиеся обнаружат проблему с искаженными китайскими иероглифами, они могут установить код:

renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    //设置编码
    res.writeHead(200, {'Content-Type':'text/html;charset=utf-8'});
    res.end(`
      <!DOCTYPE html>
      <html lang="zh">
        <head><title>Hello</title></head>
        <body>${html}</body>
      </html>
    `)
})

Затем попробуйте запустить его снова.

10. Конечно, использовать строки для склейки html-контента напрямую очень некрасиво, да и ошибиться легко, можно переписать в шаблонную форму для создания файлаindex.template.htmlкод показывает, как показано ниже:

<!DOCTYPE html>
<html lang="en">
  <head><title>Hello</title></head>
  <body>
    <!--vue-ssr-outlet-->
  </body>
</html>

Уведомление:<!--vue-ssr-outlet-->Комментарии — сюда будет вставлена ​​HTML-разметка приложения.

11. Модификацияapp.js

const renderer = require('vue-server-renderer').createRenderer({
    template: require('fs').readFileSync('./index.template.html', 'utf-8')
})
//***
renderer.renderToString(app, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.writeHead(200, {'Content-Type':'text/html;charset=utf-8'});
    res.end(html)
})

12. Попробуйте запустить его еще раз, чтобы убедиться, что он работает правильно.

13. Он также поддерживает операции интерполяции шаблонов, изменение файловindex.template.html, код показан ниже:

<html>
  <head>
    <!-- 使用双花括号(double-mustache)进行 HTML 转义插值(HTML-escaped interpolation) -->
    <title>{{ title }}</title>

    <!-- 使用三花括号(triple-mustache)进行 HTML 不转义插值(non-HTML-escaped interpolation) -->
    {{{ meta }}}
  </head>
  <body>
    <!--vue-ssr-outlet-->
  </body>
</html>

Изменить файлindex.js, код, который необходимо скорректировать, выглядит следующим образом:

const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer({
  template: require('fs').readFileSync('./index.template.html', 'utf-8')
})
const context = {
  title: 'hello vuessr',
  meta: `
    <meta charset="utf-8">
  `
}

server.get('*', (req, res) => {
  const app = new Vue({
    data: {
      url: req.url
    },
    template: `<div>访问的 URL 是: {{ url }}</div>`
  })

  renderer.renderToString(app, context, (err, html) => {
    if (err) {
      res.status(500).end('Internal Server Error')
      return
    }
    res.writeHead(200, {'Content-Type':'text/html;charset=utf-8'});
    res.end(html)
  })
})

server.listen(8080)

14. Попробуйте запустить его еще раз, чтобы убедиться, что он работает правильно. Ниже приведен скриншот просмотра исходного кода браузера.Вы можете видеть, что содержимое, определенное шаблоном, было заменено соответствующими данными.

Кодовый адрес:

GitHub.com/тао любит улыбку/…

Для конкретного и подробного ознакомления с API вы можете перейти к документации, Вышеупомянутое простое использование.

До сих пор мы реализовали самый простой проект рендеринга на стороне сервера vue.

Разве это не просто? Однако создание полного набора Vue SSR с нуля по-прежнему является очень утомительным процессом.

В будущем я также представлю Nuxt.js, готовый фреймворк VueSSR, фактически это инкапсуляция Vue SSR, и концепция остается той же. Конечно, если вы не понимаете основной процесс реализации Vue SSR, вы все равно будете сбиты с толку, когда будете использовать Nuxt.js напрямую (бог игнорирует~).

Прежде чем создавать проект, давайте взглянем на эту схему работы, представленную в руководстве:

Из рисунка можно примерно увидеть процесс работы vue ssr: сначала мы упаковываем его через webpack — серверу нужен «серверный бандл» и далее используется для рендеринга на стороне сервера (SSR), а «клиентский бандл» будет отправлен на браузер для гибридной статической разметки. После того, как у нас есть теоретическая база, давайте попрактикуемся вместе.

Сборка VueSSR с помощью Vue-cli

Код, сгенерированный шаблоном веб-пакета vue-cli, можно в основном повторно использовать в VueSSR, что избавляет от утомительного процесса настройки веб-пакета.

1. Установите vue-cli, обратитесь к документацииprocess.v uejs.org/this/expensive/кроме..., я не буду вводить здесь слишком много, я использую версию 2.9.6.

2. Бегиvue init webpack vuessr-vuecliВыберите конфигурацию следующим образом

? Project name vuessr-vuecli
? Project description A Vue.js project
? Author taoxinhua <taoxhsmile@163.com>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

3. Войдите в папку и запуститеcnpm run dev; чтобы увидеть, может ли проект нормально работать

4. Далее давайте вместе преобразуем код~

新增
src/components
    --about.vue
    --home.vue 

about.vue

<template>
  <div class="hello">
    <h1>这是关于我页面</h1>
  </div>
</template>

home.vue

<template>
  <div class="hello">
    <h1>这是首页</h1>
  </div>
</template>
修改
src/router
    --index.js

index.js

import Vue from 'vue'
import Router from 'vue-router'
import home from '@/components/home'
import about from '@/components/about'

Vue.use(Router)

export default () => {
  return new Router({
    mode:'history',
    routes: [
      {
        path: '/',
        name: 'home',
        component: home
      },
      {
        path: '/about',
        name: 'about',
        component: about
      }
    ]
  })
}
新增
src
    --app.js
    --App.vue 
    --entry-client.js 客户端打包入口文件
    --entry-server.js 服务端打包入口文件

app.js

import Vue from 'vue'
import createRouter from './router'
import App from './App.vue'

// 实例 每次请求都会创建新的实例

export default (context) => {

  const router = createRouter()

  const app = new Vue({
    router,
    components: { App },
    template: '<App/>'
  })
  return { router, app }

}

App.vue

<template>
  <div id="app">
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于我</router-link>
    <router-view/>
  </div>
</template>

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

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

entry-client.js

import createApp from './app'

let { app, router } = createApp()

router.onReady(() => {
  app.$mount('#app')
})

entry-server.js

// 服务端这边,需要把访问的路径给到vue-router

import createApp from './app'

// 外面的express服务使用  {url: / /about}
export default (context) => {
  return new Promise((resolve, reject) => {

    let { app, router } = createApp(context);
    router.push(context.url);

    router.onReady(() => {
      // 访问路径,可定匹配到组件
      let matchedCompoents = router.getMatchedComponents();

      if (!matchedCompoents.length) {
        return reject({ code: 404 })
      }
      resolve(app)
    }, reject)

  })
}
新增
build/dev-server.js
server.js

dev-server.js

const serverConf = require('./webpack.server.conf');

const webpack = require('webpack')
const fs  =require('fs')
const path = require('path');
const Mfs = require('memory-fs')
const axios = require('axios')

module.exports = (cb) => {

  const webpackComplier = webpack(serverConf);

  var mfs = new Mfs();
  webpackComplier.outputFileSystem = mfs;

  webpackComplier.watch({}, async (error, stats) => {
    if (error) return console.log(error);

    stats = stats.toJson();
    stats.errors.forEach(err => console.log(err))
    stats.warnings.forEach(err => console.log(err))

    // server Bundle json文件
    let serverBundlePath = path.join(
      serverConf.output.path,
      'vue-ssr-server-bundle.json'
    )

    let serverBundle = JSON.parse(mfs.readFileSync(serverBundlePath, "utf-8"))

    //console.log(serverBundle)

    // client Bundle json文件
    let clientBundle = await axios.get('http://localhost:8080/vue-ssr-client-manifest.json')

    // 模板

    let template = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf-8');

    cb(serverBundle, clientBundle, template)

  })
}

server.js

const devServer = require('./build/dev-server');
const express = require('express');
const app = express();
const vueRenderer = require('vue-server-renderer')
const path = require('path');

app.get('*', async (req, res) => {


  res.status(200);
  res.setHeader('Content-Type', 'text/html;charset=utf-8;')

  devServer(function(serverBundle,clientBundle,template){
    let renderer = vueRenderer.createBundleRenderer(serverBundle,{
      template,
      clientManifest: clientBundle.data,
      runInNewContext: false
    })

    renderer.renderToString({ url: req.url }).then((html) => {
      res.end(html)
    }).catch(err => console.log(err))
  })

})

app.listen(5000, () => {
  console.log('启动成功')
})
修改
build/webpack.dev.conf.js

webpack.dev.conf.js

//...忽略
const portfinder = require('portfinder')
//新增内容-start
const vueSSRClientPlugin = require('vue-server-renderer/client-plugin')
//新增内容-end
const HOST = process.env.HOST
//...忽略
new CopyWebpackPlugin([
  {
    from: path.resolve(__dirname, '../static'),
    to: config.dev.assetsSubDirectory,
    ignore: ['.*']
  }
]),
//新增内容-start
new vueSSRClientPlugin()
//新增内容-end
//...忽略

новый файл

build/webpack.server.conf.js

webpack.server.conf.js

const webpack = require('webpack');
const merge = require('webpack-merge')
const base = require('./webpack.base.conf');
const vueSSRServerPlugin = require('vue-server-renderer/server-plugin')
const webpackNodeExternals = require('webpack-node-externals')

module.exports = merge(base,{
  target: 'node',
  devtool: 'source-map',
  entry: './src/entry-server.js',
  output: {
    filename: 'server-bundle.js',
    libraryTarget: 'commonjs2'
  },
  externals: [webpackNodeExternals({
    whitelist: /\.css$/
  })],
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"devlopment"',
      'process.env.VUE_ENV': '"server"'
    }),
    new vueSSRServerPlugin()
  ]
})
修改
index.html

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>vuessr-vuecli</title>
  </head>
  <body>
    <div id="app">
      <!--vue-ssr-outlet-->
    </div>
    <!-- built files will be auto injected -->
  </body>
</html>
修改
package.json
增加server脚本

package.json

"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "build": "node build/build.js",
    "server": "node server.js"
},

Пока наши файлы были скорректированы, давайте сначала запустим их.

cnpm run dev
cnpm run server

Вы видите, что наша программа работает нормально, давайте посмотрим, возвращается ли исходный код веб-страницы после рендеринга через сервер.

Правильно, на этом этапе мы добились больших успехов, а теперь вернемся назад и посмотрим на принцип работы всего проекта~ Ведь в этом и есть смысл.

Для начала вспомним предыдущую схему принципа работы.Первый шаг — упаковать бандл для сервера и бандл для клиента отдельно через webpack.

Давайте сначала выясним, где генерируется бандл, используемый клиентом.

мы бежимcnpm run devФактически, он используется для генерации пакета, используемого клиентом. Этот шаг относительно прост, вспомните, если бы мы настроилиwebpack.dev.conf.jsДобавлен плагинvue-server-renderer/client-pluginОн используется для создания пакета для клиента, Просто мы не генерировали напрямую конкретный файл для этой связки, а помещали его в кеш, и мы можем получить к нему доступ напрямую через браузерhttp://localhost:8080/vue-ssr-client-manifest.jsonПроверьте этот файл json.

пакет на стороне сервера

На самом деле он тоже генерируется в кеше,build/dev-server.jsСначала мы проходимwebpackComplier.outputFileSystem = mfs;Модифицировал форму вывода вебпака (изменил на вывод в кеш), а потом получил файл из кеша

let serverBundlePath = path.join(
  serverConf.output.path,
  'vue-ssr-server-bundle.json'
)

let serverBundle = JSON.parse(mfs.readFileSync(serverBundlePath, "utf-8"))

давайте посмотрим еще разserver.js

devServer(function(serverBundle,clientBundle,template){
let renderer = vueRenderer.createBundleRenderer(serverBundle,{
  template,
  clientManifest: clientBundle.data,
  runInNewContext: false
})

renderer.renderToString({ url: req.url }).then((html) => {
  res.end(html)
}).catch(err => console.log(err))
})

Вы можете видеть, что serverBundle (серверный пакет), clientBundle (клиентский пакет), шаблон (шаблон index.html), которые мы получим, будут переданыvue-server-rendererдля окончательной обработки.

кодовый адрес

GitHub.com/тао любит улыбку/…

Большой успех~ Принцип наверное такой, детали кода еще нужно просмотреть и переварить самому

Поговорив о принципе, давайте посмотрим, что происходит с Nuxt.js.

Перед переходом по следующей ссылке рекомендуется сначала прочитать официальную документацию.zh.nuxtjs.org/guide/

Что такое Nuxt.js?

Короче говоря, Nuxt.js — это готовый фреймворк для Vue SSR. После установки вы можете напрямую писать бизнес-код без особой настройки.

Поскольку это фреймворк, мы должны настраивать и писать код в соответствии с его правилами.В официальной документации, предоставленной ранее, содержится очень подробное введение. Я не буду вводить здесь слишком много, давайте перейдем непосредственно к реальному бою. Сначала создадим новый проект.

Во время реконструкции официального сайта NUXT.JS 2.0 просто произошло выпущено. После прочтения изменений все еще есть много изменений. Для того, чтобы обеспечить нормальный запуск проекта, я решил использовать стабильную версию 1.0+ для Кодирование (в конце концов, будут некоторые проблемы с выпуском новой версии). Ниже приведены также некоторые проблемы, встречающиеся в процессе разработки версии 1.0+, вы можете узнать из следующих.

Следующий контент в основном посвящен некоторым проблемам, возникающим в реальном боевом процессе:

Первый шаг — создать новый проект и установить адрес документа:Это Angry Heart Beats.org/Gui/INSHe…Мы используемcreate-nuxt-appкоманда для установки, запуска

npx create-nuxt-app vuessr-nuxt 

или

cnpm install -g create-nuxt-app
create-nuxt-app vuessr-nuxt

Выберите конфигурацию следующим образом

? Project name vuessr-nuxt
? Project description My unreal Nuxt.js project
? Use a custom server framework express
? Use a custom UI framework none
? Choose rendering mode Universal
? Use axios module yes
? Use eslint no
? Use prettier no
? Author name taoxinhua
? Choose a package manager npm

Затем войдите в проект для запуска,cnpm run devПосмотрите, может ли проект работать нормально, если нет, первым шагом будет проверка следующей версии узла, моя версия узла — v8.12.0. Второй шаг, если нода все еще не работает после обновления, запуститеcnpm installПроверьте, установлены ли какие-либо зависимые пакеты. Если эти два шага не решают проблему, вы можете задавать вопросы в области комментариев.

Откройте браузер и введитеhttp://127.0.0.1:3000, вы можете видеть, что наш проект готов к запуску. да это так просто

1. Используйте яму, с которой столкнулся axios.

Уведомление

В процессе разработки с использованием версии 1.0+ было обнаружено, что каждый раз, когда файл изменяется, код сервера будет перезагружаться и выполняться снова.Если вы напрямую поместите функцию ловушки axios в плагин для выполнения, вы обнаружите, что хук-функция будет добавляться повторно после каждой модификации.Один раз, параметры многократно обрабатываются.Например, перед отправкой запроса мне нужно преобразовать переданные данные в строку. Вы обнаружите, что config.data следующего кода будет многократно накапливаться.

axios.interceptors.request.use(function (config) {
    let data = config.data || {};
    let auth = buildHttpHeaders();

    config.url = getApiUrl(config.url);
    
    config.data = qs.stringify({
        data: JSON.stringify(data),
        auth: JSON.stringify(auth)
    })
    //在请求发出之前进行一些操作
    return config;
}, function (err) {
    //Do something with request error
    return Promise.reject(err);
});

Решение

Создать файл

assets/js/config/config-axios.js

import Axios from 'axios'
import qs from 'qs'
import { getUUID } from '~/assets/js/tools/index'
import { getApiUrl } from '~/assets/js/config/config-urls.js'

function buildHttpHeaders() {
    return {
        "x-user-id": '',
        "x-access-token": '',
        "x-platform": 'pc',
        "x-client-token": getUUID(),
        "x-system-version": '10.1.1',
        "x-client-version": '2.0.1',
        "x-method-version": '1.0',
        "x-network-type": '3g',
    }
}

let axios = Axios.create();

// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
    let data = config.data || {};
    let auth = buildHttpHeaders();

    config.url = getApiUrl(config.url);
    
    config.data = qs.stringify({
        data: JSON.stringify(data),
        auth: JSON.stringify(auth)
    })
    //在请求发出之前进行一些操作
    return config;
}, function (err) {
    //Do something with request error
    return Promise.reject(err);
});

//添加一个响应拦截器
axios.interceptors.response.use(function (res) {
    //在这里对返回的数据进行处理
    return res.data;
}, function (err) {
    //Do something with response error
    return Promise.reject(err);
});

export default axios

Каждый раз через Axios.create возвращается новый экземпляр axios.

Выше приведен код, скопированный из проекта, который не может быть запущен отдельно, вы можете настроить его в соответствии с вашими потребностями.

plugins/axios.js

import Vue from 'vue';
import axios from '~/assets/js/config/config-axios'

Vue.prototype.$$axios = axios;

export default ({ app }, inject) => {
    // Set the function directly on the context.app object
    app.$$axios = axios;
}

Таким образом, описанная выше проблема не будет возникать каждый раз при горячем обновлении кода.

Здесь также подвешивается axios под прототипом Vue и под объектом приложения, и страницу можно вызывать без обращения к axios.

2. асинхронные данные

Метод asyncData, объявленный файлом компонента в nuxt, будет игнорироваться, поэтому вся загрузка данных должна размещаться в asyncData соответствующей страницы.

3. Как добавить дополнительные глобальные файлы js

Мы можем справиться с этим, настроив шаблон, создав его в корневом каталоге.app.htmlФайл шаблона, шаблон nuxt по умолчанию:

<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head>
    {{ HEAD }}
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

Например, если мы хотим увеличить код индексации поисковой системы, мы можем

<!DOCTYPE html>
<html {{ HTML_ATTRS }}>
  <head>
    {{ HEAD }}
    <!-- 百度自动收录脚本 -->
    <script>
        (function(){
            var bp = document.createElement('script');
            var curProtocol = window.location.protocol.split(':')[0];
            if (curProtocol === 'https') {
                bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
            }
            else {
                bp.src = 'http://push.zhanzhang.baidu.com/push.js';
            }
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(bp, s);
        })();
    </script>
    <!-- 360自动搜录脚本 -->
    <script>(function(){
        var src = (document.location.protocol == "http:") ? "http://js.passport.qihucdn.com/11.0.1.js******":"https://jspassport.ssl.qhimg.com/11.0.1.js?******";
        document.write('<script src="' + src + '" id="sozz"><\/script>');
        })();
    </script>
    <!-- 百度统计 -->
    <script>
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?******";
          var s = document.getElementsByTagName("script")[0]; 
          s.parentNode.insertBefore(hm, s);
        })();
    </script>
  </head>
  <body {{ BODY_ATTRS }}>
    {{ APP }}
  </body>
</html>

4. Пусть проект поддерживает IP-доступ существуетpackage.jsonДобавьте следующую конфигурацию в файл

"config": {
    "nuxt": {
      "host": "0.0.0.0",
      "port": "3000"
    }
},

5. Различайте конфигурацию между формальной средой и тестовой средой.

package.json

"scripts": {
    "dev": "cross-env API_ENV=local nuxt",
    "build_beta": "cross-env API_ENV=beta nuxt build",
    "build_pro": "cross-env API_ENV=pro nuxt build",
    "start": "nuxt start",
    "generate": "nuxt generate",
    "lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
    "precommit": "npm run lint"
  },

Добавьте build_beta, build_pro, а затем установите среду через cross-env

nuxt.config.js

env: {
    API_ENV: process.env.API_ENV
},

Таким образом, в коде,process.env.API_ENVчтобы получить значение переменной окружения.

6. Запускаем проект через pm2

pm2-config.json

{
    "apps": [
        {
            "name": "nicomama-site",
            "script": "npm",
            "args" : "start",
            "watch": [".nuxt"]
        }
    ]
}

7. Развертывание проекта

беги первымcnpm run build_betaилиcnpm run build_proУпакуйте его, затем запустите проект, запустив pm2 start pm2-config.json.

Я дам вам структуру проекта позже, когда у меня будет время.

Давайте посмотрим на ситуацию с индексацией поисковыми системами после запуска.

SEO. Что за .com/? Пожалуйста = woo woo woo. Нико…

Видно, что статьи на веб-сайте в основном были включены Google.Что касается относительно небольшого количества данных, включенных в Baidu, это может быть вызвано общей ревизией веб-сайта.Поисковику требуется определенный период времени для обновления , что еще предстоит увидеть.

Тогда иди сюда первым

подпись

by:Tao