Vue meta не получает обновлений

#javascript #laravel #vue.js #vuejs2 #vue-meta

#javascript #laravel #vue.js #vuejs2 #vue-meta

Вопрос:

Когда я посещаю мои внутренние страницы vue-meta , они не будут обновляться новыми значениями страницы.

Код

app.js

 import VueMeta from 'vue-meta'
Vue.use(VueMeta, {
    refreshOnceOnNavigation: true
})
 

App.vue (основной компонент)

 export default {
  metaInfo() {
    return {
      title: process.env.MIX_APP_NAME,
      titleTemplate: `%s | ${process.env.MIX_APP_NAME}`,
      meta: [
        { name: "robots", content: "index,follow" },
        {
          vmid: "description",
          name: "description",
          content:
            "..........",
        },
        // and many more....
      ],
   }
  }
}
 

post.vue (внутренний компонент)

 export default {
  name: "singePost",
  data() {
    return {
      post: "",
    };
},
metaInfo() {
    return {
        title: this.post.name, // not receiving data
        meta: [
            {
                vmid: "description",
                name: "description",
                content: this.post.metas[0].description, // not receiving data
            },
            // others......
        ],
    }
},
mounted() {
    this.getPost();
},
methods: {
    getPost() {
        axios
        .get("/api/articles/"   this.$route.params.slug, {
          headers: {
            Authorization: localStorage.getItem("access_token"),
          },
        })
        .then((response) => {
          this.post = response.data.data;
        })
        .catch((error) => {
            //....
        });
    },
},
 

Есть идеи?

Обновить

К тому времени, когда я опубликовал этот вопрос, речь шла о том, чтобы не обновляться, а затем, проведя некоторые исследования и поиграв со своим кодом, я понял, что моя vue-meta обновляется, но с опозданием, и это приводит к тому, что сайты социальных сетей и SEO-контролеры не могут правильно получить мои URL-адреса.

Уточнить

  1. Vue-meta получает обновление, но с опозданием
  2. Это позднее обновление приводит к тому, что SEO не отображается при публикации и проверке временной ссылки.

My full meta tags code

 metaInfo() {
    return {
      title: this.post.name,
      meta: [
        {
          vmid: "keyword",
          name: "keyword",
          content: this.post.metas[0].tags,
        },
        {
          vmid: "description",
          name: "description",
          content: this.post.metas[0].description,
        },
        // Open Graph / Facebook
        { vmid: "og:type", name: "og:type", content: "website" },
        {
          vmid: "og:url",
          name: "og:url",
          content: process.env.MIX_APP_URL   this.$router.currentRoute.fullPath,
        },
        {
          vmid: "og:site_name",
          name: "og:site_name",
          content: `"${process.env.MIX_APP_NAME}"`,
        },
        {
          vmid: "og:title",
          name: "og:title",
          content: this.post.name,
        },
        {
          vmid: "og:description",
          name: "og:description",
          content: this.post.metas[0].description,
        },
        {
          vmid: "og:image",
          name: "og:image",
          content: this.post.imagebig,
        },
        //   Twitter
        {
          vmid: "twitter:card",
          name: "twitter:card",
          content: "summary",
        },

        {
          vmid: "twitter:author",
          name: "twitter:author",
          content: "@xxxxxx",
        },
        {
          vmid: "twitter:site",
          name: "twitter:site",
          content: "@xxxxxx",
        },
        {
          vmid: "twitter:creator",
          name: "twitter:creator",
          content: "@xxxxxx",
        },
        {
          vmid: "twitter:url",
          name: "twitter:url",
          content: process.env.MIX_APP_URL   this.$router.currentRoute.fullPath,
        },
        {
          vmid: "twitter:title",
          name: "twitter:title",
          content: this.post.name,
        },
        {
          vmid: "twitter:description",
          name: "twitter:description",
          content: this.post.metas[0].description,
        },
        {
          vmid: "twitter:image",
          name: "twitter:image",
          content: this.post.imagebig,
        },
      ],
    };
},
 

Дополнительно

  1. Недавно я прочитал статью о том, что, поскольку vue-meta (Vue в целом) загружается на основе JavaScript, сканеры социальных сетей не будут кэшировать их, поэтому невозможно увидеть мои данные о ссылках, когда я делюсь ими в FB или Twitter и т. Д.
  2. Предлагаемое решение заключалось в использовании Nuxt и возврате метаданных на стороне сервера.

Вопросы

  1. Я не уверен, насколько # 1 выше верно, но это возможно
  2. Мое приложение в целом не использует Nuxt, но я только что установил его пакет npm, поэтому, возможно, стоит попробовать (как я уже упоминал, я никогда не использовал Nuxt, поэтому, если это касается вашего решения helping, я был бы признателен, если бы вы добавили немного дополнительной информации в свои ответы по этому поводу).

Ответ №1:

Сам Vue является JS-фреймворком на стороне клиента. Когда вы создаете, у index.html вас нет никакого содержимого — только JS, который генерирует содержимое при выполнении. То же самое относится и к VueMeta. Проблема в том, что когда вы делитесь ссылками (FB, Twitter и т. Д.), Они загружают связанную страницу с помощью своего собственного бота (по сути, сканера) и анализируют содержимое без выполнения какого-либо JS внутри — так что да, они не видят никаких метаданных, созданных VueMeta…

Единственным решением этой проблемы является предоставление полностью (или частично) предварительно отображаемой страницы, содержащей всю важную информацию, без выполнения JS

Один из способов сделать это — использовать рендеринг на стороне сервера Vue — и вы правы, такие фреймворки, как Nuxt, используют именно это.

Как правило, существует два вкуса:

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

SSG — генерация на стороне сервера. Страницы генерируются во время сборки, включая весь HTML. При загрузке в браузер сервер возвращает HTML все JS / CSS, но при загрузке это тот же Vue SPA. Для этого вам не нужен сервер узла, поэтому вы можете размещать на CDN или любой статической службе хостинга, такой как Netlify. Примерами в мире Vue являются Gridsome, VuePress, Nuxt тоже могут это сделать…

Примечание: существуют и другие способы, например, с использованием безголового chrome / puppeteer или таких сервисов, как https://prerender.io /

Nuxt

Как уже говорилось ранее, Nuxt великолепен, но очень самоуверен в том, как структурировано ваше приложение (маршрутизация на основе файлов), как получать данные и т. Д. Таким образом, переход на Nuxt может означать полную перезапись приложения. Кроме того, для этого требуется запущенный сервер УЗЛА, который имеет свои собственные последствия (хостинг).

НО мне кажется, что вы уже используете server — Laravel. Поэтому лучше всего, вероятно, реализовать ваш мета-рендеринг непосредственно в Laravel.

ОБНОВЛЕНИЕ: кажется, можно выполнить Vue SSR непосредственно в Laravel

Комментарии:

1. Меня интересует ваша UPDATE часть, и я прочитал статью, но я не понял, как я должен возвращать, например, мои мета-теги post (как в моем коде выше), там ничего не говорилось о возврате фактических данных из базы данных.

2. Из статьи это похоже на обычный Vue SSR. Короче говоря, прежде чем сервер вернет ответ, он запускает ваше приложение Vue внутри виртуальной машины JS версии 8 ВНУТРИ сервера и возвращает любой HTML, отображаемый им. Таким образом, вы не пишете никакого PHP-кода для генерации мета-тегов или запросов к базе данных. Все это делается внутри приложения Vue. Я не говорю, что ваш код Vue будет работать так же, как сейчас, но для получения более подробной информации вам нужно будет проверить ссылку на рендеринг на стороне сервера Vue в моем посте….

3. Но я действительно мало что знаю о Laravel. Возможно, попытка SSR здесь просто излишняя. Может быть, вы можете просто создать контроллер с тем же маршрутом, что и ваш Post компонент, добавить некоторый вызов DB, сгенерировать meta теги на PHP и прикрепить скрипты VUE js к ответу…

4. в моем проекте SSR имеет значение false и использует Nuxt, есть ли какой-либо другой способ обновить тег заголовка перед загрузкой страницы. Я столкнулся с точно такой же проблемой, но в моем случае просто SSR имеет значение false. просто я хочу обновить тег заголовка в ответе Api, и заголовок должен отображаться в источнике просмотра. Если кто-нибудь может мне помочь в этом.

Ответ №2:

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

  1. Продолжайте использовать vue-meta для тех сканеров, которые запускают JavaScript (в этом нет вреда, верно?).
  2. Внедрите решение на стороне сервера (используя пакет Laravel).

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

Для варианта 2, вот мой подход:

  • Я выбрал этот пакет для своего приложения Laravel. Его легко установить и зарегистрировать. Я уверен, что есть много пакетов для Laravel или других фреймворков и языков, которые делают то же самое.
  • Я добавил этот маршрут в конец моих файлов маршрутов ( web.php если вы используете Laravel), который улавливает все запросы интерфейсных маршрутов:
 Route::get('/{any}', 'IndexController@index')->where('any', '.*');
 

Сначала IndexController я проверяю запрос, чтобы узнать, поступает ли он от сканера. Если это так, я применяю соответствующие мета-теги. Вот краткий обзор:

 <?php

declare(strict_types=1);

namespace AppHttpControllers;

use ButschsterHeadFacadesMeta;
use ButschsterHeadPackagesEntitiesOpenGraphPackage;

class IndexController extends Controller
{
    const CRAWLERS = [
        'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1;  http://www.google.com/bot.html)',
        'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1 (compatible; AdsBot-Google-Mobile;  http://www.google.com/mobile/adsbot.html)',
        'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; Googlebot/2.1;  http://www.google.com/bot.html) Safari/537.36',
        'Mozilla/5.0 (compatible; Googlebot/2.1;  http://www.google.com/bot.html)',
        'Mozilla/5.0 (compatible; bingbot/2.0;  http://www.bing.com/bingbot.htm)',
        'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534  (KHTML, like Gecko) BingPreview/1.0b',
        'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53 (compatible; bingbot/2.0;  http://www.bing.com/bingbot.htm)',
        'Googlebot-Image/1.0',
        'Mediapartners-Google',
        'facebookexternalhit/1.1 ( http://www.facebook.com/externalhit_uatext.php)',
        'facebookexternalhit/1.1',
        'Twitterbot/1.0',
        'TelegramBot (like TwitterBot)',
    ];

    public function index()
    {
        if ($this->isACrawler()) {
            $this->applyMetaTags();

            return view('layouts.crawler');
        }

        return view('layouts.index');
    }

    public function isACrawler()
    {
        if (in_array(request()->userAgent(), self::CRAWLERS)) {
            return true;
        }

        return false;
    }

    private function applyMetaTags()
    {
        // Here you can check the request and apply the tags accordingly
        // e.g.
        //        preg_match("/articles/[0-9] /i", request()->path(), $url)
        //        preg_match("/[0-9] /i", $url[0], $id);
        //        $article = Article::find($id);
        //
        //        Meta::prependTitle($article->name)
        //            ->addMeta('description', ['content' => $article->description]);
        //
        //        $og = new OpenGraphPackage('some_name');
        //
        //        $og->setType('Website')
        //            ->setSiteName('Your website')
        //            ->setTitle($article->name)
        //            ->setUrl(request()->fullUrl())
        //            ->setDescription($article->description);
        //
        //        if ($article->picture) {
        //            $og->addImage(asset($article->picture));
        //        }
        //
        //        Meta::registerPackage($og);
    }
}

 

И, наконец, я создал шаблон, содержащий только head раздел (это единственная часть html, о которой заботится сканер), и применил мета-теги:

 <!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        @meta_tags

        <link rel="shortcut icon" href="{{ asset('favicon.ico') }}">
    </head>
</html>

 

Предостережения:

  • Вам необходимо настроить мета-теги для каждого запроса
  • Вам необходимо поддерживать список сканеров

Преимущества:

  • Это просто и не требует особых изменений в вашем коде
  • Он возвращает быстрый и легкий HTML-код для сканера
  • У вас есть полный контроль над серверной частью, и с небольшой корректировкой вы можете реализовать поддерживаемое решение

Надеюсь, это поможет! Пожалуйста, дайте мне знать, если что-то неясно.

Комментарии:

1. Привет, hatef, спасибо за ответ, если я использую пакет, о котором вы упомянули, нужно ли мне по-прежнему предоставлять список краулеров? поскольку этот список может меняться, и я не смогу предоставить для этого каждого бота, наличие пользовательских ботов, во-первых, сложно, во-вторых, не имеет смысла. и при этом, как говорится, предоставление vue-meta на всех интерфейсных страницах, помимо заботы о контроллерах, кажется большой работой по предоставлению meta в 2 разных местах. что вы думаете?

2. Привет, пакет применяет только мета-теги. Список сканеров был моим собственным дополнением. Причина в том, что я хочу применять внутренние мета-теги только тогда, когда запрос поступает от сканера. Вы можете опустить это и применить их прямо к каждому запросу. В целом, наличие хорошего SEO — это большая работа, которая зависит от ваших потребностей. В моем случае я решил применить внутренние мета-теги только к тем страницам, которые, как я знаю, могут быть доступны в социальных сетях (для поддержки функции предварительного просмотра). Может показаться излишним иметь его в двух местах, но я думаю, что в конце концов это окупается.

3. Кроме того, вы могли бы просто использовать этот серверный пакет, и он мог бы удовлетворить ваши потребности. Вам просто нужно посмотреть, как это работает с маршрутизацией внешнего интерфейса, поскольку вы, скорее всего, будете выполнять вызовы API, которые не обновляют <head> ваш html. Например, вы могли бы придумать способ, которым при получении определенного ответа API вы динамически обновляете заголовок своей страницы. Я сам толком не вникал в это, но такая возможность есть. Я мог бы покопаться в этом, когда у меня будет немного свободного времени 🙂

4. Да, я только что попробовал это сегодня утром, и у меня возникли некоторые проблемы с этим, и я до сих пор не получил ответа на эти проблемы на github, как вы упомянули, вы не так много вникали в это, поэтому я думаю, что мне нет смысла отсылать вас к этим проблемам 🙂 Большое спасибо за объяснение и ваше время.

5. Конечно. Я обновлю свой ответ, если у меня будут какие-либо выводы. Кстати, я добавил laravel в ваши теги вопросов, таким образом, возможно, некоторые разработчики Laravel также могли бы внести свой вклад в ответы

Ответ №3:

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

Вот пример для PHP — Laravel.

Как мы знаем vue.js это одностраничное приложение. И так каждый раз, когда он рендерится с одной корневой страницы.

Итак, для laravel я настроил маршрут как есть, и каждый раз, когда я возвращаю индексную страницу с массивом тегов и отображаю эту страницу в представлении (индексная страница)

  1. Маршрутизация Laravel
 <?php
    
    use IlluminateSupportFacadesRoute;
    
    Route::get('users/{id}', 'UserController@show');
    
    Route::get('posts/{id}', function () {
        $tags = [
            'og:app_id' => '4549589748545',
            'og:image' => 'image.jpg',
            'og:description' => 'Testing'
        ];
    
        return view('index', compact('tags'));
    });
    
    Route::get('/{any}', function () {
        $tags = [
            'description' => 'Testing',
            'keywords' => 'Testing, Hello world',
        ];
    
        return view('index', compact('tags'));
    })->where('any', '.*');
    
    ?> 

  1. Контроллер
 <?php
    
    use AppHttpControllersController;
    use AppModelsUser;
    
    class UserController extends Controller
    {
        public function show(User $user)
        {
            $tags = [
                'og:app_id' => '4549589748545',
                'og:image' => 'image.jpg',
                'og:description' => 'Testing'
            ];
    
            return view('index', compact('tags'));
        }
    }
    
    ?> 

  1. Индексная страница
 <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        @foreach($tags as $key => $value)
            <meta property="{{$key}}" content="{{$value}}">
        @endforeach
    </head>
    <body id="app">
    
    <script type="text/javascript" src="{{ asset('js/app.js') }}"></script>
    </body>
    </html> 

Ответ №4:

вы можете настроить webpack для введения статических тегов

vue-cli 3 абстрагирует конфигурационные файлы webpack (генерируемые во время выполнения), поэтому для его настройки вам необходимо добавить vue.config.js к корню вашего проекта (если у вас его нет, чего обычно у вас не будет)

например:

 // vue.config.js
module.exports = {
    configureWebpack: {
        output: {
            publicPath: '/static/'
        },

        plugins: [
          new HtmlWebpackPlugin(),
          new HtmlWebpackTagsPlugin(
            {tags: ['a.js', 'b.css'], append: true },
            {metas: [{
                path: 'asset/path',
                attributes: {
                    name: 'the-meta-name'
                    }}]
            })
        ]
    }
}
 

(используя https://github.com/jharris4/html-webpack-tags-plugin смотрите Примеры по ссылке для его конкретного вывода)

Комментарии:

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