如何使用 Apollo 在 Nuxt 生成的动态页面中正确填充页眉?

Posted

技术标签:

【中文标题】如何使用 Apollo 在 Nuxt 生成的动态页面中正确填充页眉?【英文标题】:How to properly populate page headers in Nuxt generated dynamic pages using Apollo? 【发布时间】:2019-09-29 18:48:35 【问题描述】:

我有一个 Nuxt.js,它是静态生成的站点,其中包含一些动态页面。我正在使用基于 GraphQL 的无头 CMS (DatoCMS) 为这些页面提供数据,这些页面使用 Apollo (@nuxt/apollo) 访问。我让它正确生成所有路线,但是当我从我的站点导航导航到这些页面时,我收到以下错误 3 次:

TypeError: Cannot read property '_seoMetaTags' of undefined
at f.head (cf150f1920d36ab67139.js:1)
at wn.get (008dfc959ff6e6a713a0.js:2)
at wn.evaluate (008dfc959ff6e6a713a0.js:2)
at f.$metaInfo (008dfc959ff6e6a713a0.js:2)
at f.created (008dfc959ff6e6a713a0.js:2)
at Qt (008dfc959ff6e6a713a0.js:2)
at fn (008dfc959ff6e6a713a0.js:2)
at f.t._init (008dfc959ff6e6a713a0.js:2)
at new f (008dfc959ff6e6a713a0.js:2)
at 008dfc959ff6e6a713a0.js:2

这来自我的页面组件中的头部代码,因此很明显有些东西没有正确生成。我还可以在 Chrome 网络选项卡中看到正在对 GraphQL 接口进行调用,这也告诉我静态生成工作不正常。

这是我的页面组件的 head() 和 apollo 部分:

head() 
    return 
        title: this.blogPost._seoMetaTags.find(element => 
            return element.tag === 'title';
        ).content,
        meta: [
             hid: 'keywords', keywords: this.blogPost.keywords ,
             hid: 'description', description: this.blogPost._seoMetaTags.find(element => 
                return element.tag === 'meta' && element.attributes.name === 'description';
            ).attributes.content
        ],
        script: [
             src: 'https://cdn.commento.io/js/commento.js', defer: true 
        ]
    
,
apollo: 
    blogPost: 
        query: gpl`
            query BlogPost($slug: String!) 
                blogPost(filter:  slug: eq: $slug ) 
                    title
                    titleColor 
                        hex
                    
                    slug
                    author
                    keywords
                    _seoMetaTags 
                        tag
                        attributes
                        content
                    
                    _firstPublishedAt
                    banner 
                      id
                      url
                      title
                    
                    content 
                        ... on HeadingRecord 
                            _modelApiKey
                            heading
                        
                        ... on SubHeadingRecord 
                            _modelApiKey
                            subHeading
                        
                        ... on TextRecord 
                            _modelApiKey
                            content
                        
                        ... on CodeRecord 
                            _modelApiKey
                            codeBlock
                        
                        ... on ImageRecord 
                            _modelApiKey
                            image 
                                id
                                height
                                width
                                url
                                title
                                alt
                            
                        
                        ... on VideoRecord 
                            _modelApiKey
                            video 
                                height
                                provider
                                providerUid
                                thumbnailUrl
                                title
                                url
                                width
                            
                        
                    
                
            
        `,
        prefetch( route ) 
            return 
                slug: route.params.slug
            ;
        ,
        variables() 
            return 
                slug: this.$route.params.slug
            ;
        

如果有帮助,还有我的 nuxt.config.js:

const pkg = require('./package')

const webpack = require('webpack'); 从“节点获取”导入获取; 从'apollo-link'导入执行,makePromise; 从“apollo-link-http”导入 createHttpLink ; 从'graphql-tag'导入gql;

module.exports = 模式:'通用',

/*
** Headers of the page
*/
head: 
    title: pkg.name,
    htmlAttrs: 
        lang: 'en'
    ,
    meta: [
         charset: 'utf-8' ,
         name: 'viewport', content: 'width=device-width, initial-scale=1' ,
         hid: 'description', name: 'description', content: pkg.description 
    ],
    link: [
         rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' ,
         rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/gh/tonsky/FiraCode@1.206/distr/fira_code.css' 
    ]
,

/*
** Customize the progress-bar color
*/
loading:  color: '#fff' ,

/*
** Global CSS
*/
css: [
],

/*
** Plugins to load before mounting the App
*/
plugins: [
],

/*
** Nuxt.js modules
*/
modules: [
    '@nuxtjs/style-resources',
    '@nuxtjs/apollo',
    '@nuxtjs/google-analytics'
],

/*
** @nuxtjs/google-analytics settings
*/
googleAnalytics: 
    id: 'UA-136517294-1'
,

/*
** @nuxtjs/style-resources settings
*/
styleResources: 
    scss: [
        './assets/css/*.scss'
    ]
,

/*
** Apollo setup for DatoCMS graphql queries
*/
apollo: 
    includeNodeModules: true,
    clientConfigs: 
        default: '@/apollo/default.js'
    
,

/*
** Build configuration
*/
build: 
    postcss: 
        preset: 
            features: 
                customProperties: false
            
        
    ,
    /*
    ** You can extend webpack config here
    */
    extend(config, ctx) 
    
,

/*
** Generate configuration
*/
generate: 
    routes: function(callback) 
        // Get the list of posts
        const uri = 'https://graphql.datocms.com';
        const link = new createHttpLink( uri: uri, fetch: fetch );
        const operation = 
            query: gql`
            
                allBlogPosts 
                    id
                    slug
                    keywords
                    _seoMetaTags 
                        tag
                        attributes
                        content
                    
                
            `,
            context: 
                headers: 
                    authorization: 'Bearer <my token>'
                
            
        ;

        makePromise(execute(link, operation))
            .then(data => 
                // Build the routes from the posts
                const postRoutes = data.data.allBlogPosts.map(item => 
                    return  route: `/blog/$item.slug`, payload:  keywords: item.keywords, seoData: item._seoMetaTags ;
                );

                // Register the routes
                callback(null, postRoutes);
            )
            .catch(error => console.log(`received error $error`));
    

【问题讨论】:

仍会发出请求。见github.com/nuxt/rfcs/issues/22 @Aldarund 是的!这正是我遇到的。静态页面似乎可以生成,但头部代码正在重新触发数据查询或其他内容。不幸的是,它看起来并没有太多的解决方案。可能是时候使用 Gridsome 而不是 Nuxt 了。如果您创建一个答案,我会接受它。 【参考方案1】:

如果您希望所有 api 请求都捆绑到应用程序中并且不再发出,那么 nuxt 目前不是这样工作的。它仍然会在应用程序的客户端导航上向 api 发出请求。

nuxt有制作全静态模式的计划,可以在这里追踪https://github.com/nuxt/rfcs/issues/22

【讨论】:

以上是关于如何使用 Apollo 在 Nuxt 生成的动态页面中正确填充页眉?的主要内容,如果未能解决你的问题,请参考以下文章

使用 nuxt-apollo 时如何使用 GraphQL 查询?

在 nuxt/vue 中来自 apollo 的数据发生变化后,子元素不更新道具

在 Apollo Nuxt 中,如何在方法中访问非默认客户端?

如何调试 nuxt-apollo 服务器端 graphql 请求

@Nuxt/Apollo 如何从 gql 查询中删除“__typeName”

生成后在 Nuxt SPA 中使用动态路由