首页 > 解决方案 > 如何从组件中抽象出一个 graphQL 查询?

问题描述

我有一个带有基本组件的 NextJS 项目,我使用该模块<PostList />从 GraphQL 服务器检索一些测试数据:react-apollo

import { gql, graphql } from "react-apollo";
import withData from "../../apollo/withData";

const GET_POSTS = gql`
{
  posts {
    _id
    title
  }
}
`;

const PostList = ({data: {loading, posts}}) => {
    if(loading) {
        return (<div>Loading...</div>);
    } else {
        return (
      <ul>
        {posts.map(post => <li key={post._id}>{post.title}</li>)}
      </ul>
    );
    }
};

export default withData(graphql(GET_POSTS)(PostList));

这很完美。但现在我想把那个查询定义拿出来,给它一个单独的.graphql(或.gql)自己的文件。像这样的东西:

// apollo/get-posts-query.graphql

{
  posts {
    _id
    title
  }
}

我的问题是,如何将这个文件导入到我的组件中,而不必将其转换为 javascript 代码?我的意思是,我不想在我的.graphql文件中使用任何非 graphql 代码(所以 nomodule.exports export default等)。

这是我尝试过的所有内容:

使用 webpack

/* eslint-disable no-unused-vars */

import withCSS from '@zeit/next-css';
import withSass from '@zeit/next-sass';
import dotenv from 'dotenv';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import glob from 'glob';
import withPurgeCss from 'next-purgecss';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import path from 'path';
import webpack from 'webpack';
import 'graphql-tag/loader';

const { parsed: localEnv } = dotenv.config();

module.exports = withCSS(withSass(withPurgeCss({
  distDir: '.build',
  purgeCssPaths: [
    'pages/**/*',
    'components/**/*',
  ],
  webpack: (config, { dev, isServer }) => {
    if (isServer) {
      return config;
    }
    config.module.rules.push({
      test: /\.(graphql|gql)$/,
      exclude: /node_modules/,
      loader: 'graphql-tag/loader',
    });
    config.plugins.push(
      new webpack.DefinePlugin({
        'process.env': {
          BASE_URL: JSON.stringify(process.env.BASE_URL),
        },
      }),
      new webpack.EnvironmentPlugin(localEnv),
      new webpack.optimize.LimitChunkCountPlugin({
        maxChunks: 1,
      }),
    );
    config.optimization.minimizer.push(
      new OptimizeCSSAssetsPlugin({}),
    );
    return config;
  },
  env: {
    REDIS_PORT: process.env.REDIS_PORT,
    REDIS_HOST: process.env.REDIS_HOST,
  },
})));

此设置引发以下错误(甚至拒绝识别加载程序!):

./apollo/test.graphql 2:8 Module parse failed: Unexpected token (2:8) 您可能需要适当的加载器来处理此文件类型,目前没有配置加载器来处理此文件。见https://webpack.js.org/concepts#loaders | { 帖子 { | _id | 标题

使用通天塔

我添加了babel-plugin-import-graphqlbabel 插件(yarn add -D babel-plugin-import-graphql到我的开发依赖项中)。然后更新我.babelrc的如下:

{
  "presets": [
    "next/babel"
  ],
  "plugins": [["styled-components", { "ssr": true }], "import-graphql"]
}

这会引发以下错误:

发生构建错误 { Invariant Violation: Argument of { posts { _id title secondaryTitle } } 传递给解析器不是有效的 GraphQL DocumentNode。您可能需要使用 'graphql-tag' 或其他方法将您的操作转换为 invariant 的文档(/home/ubuntu/proost/web-no-apollo/node_modules/invariant/invariant.js:40:15)

还有第三种选择吗?

标签: graphqlnext.jsreact-apolloapollo-client

解决方案


你需要一个像 Webpack 这样的捆绑器,它可以让你定义如何加载.graphql文件。然后您只需导入 graphql 文件并像以前一样使用生成的查询字符串/对象。

一种可能是webpack-graphql-loader,但 Apollo建议使用graphql-tag

在任何情况下,您都可以专门针对 Next.js 尝试这种方法


推荐阅读