andrew-codes / gatsby-plugin-elasticlunr-search

Gatsby search plugin via elastic lunr client-side search index.
http://gatsby-plugin-search.andrew.codes/
MIT License
88 stars 45 forks source link

Error: SiteSearchIndex.index field type must be Output Type but got: SiteSearc hIndex_Index. #10

Open ciokan opened 6 years ago

ciokan commented 6 years ago

Any idea why I get this error when I enter your code in gatsby-config file?

andrew-codes commented 6 years ago

@ciokan: Hi! Thank you for submitting an issue. Hopefully, we can get it resolved quickly.

Would you mind posting the relevant gatsby-config.js file? Also, what version of the plugin are you using? Finally, did you follow an example to configure the plugin in gatsby-config.js and, if so, which example did you use? There is a demo site using this plugin in another repo that may be of help.

Let me know some of this information and I'll try to reproduce/troubleshoot your problem. Thanks again!

ciokan commented 6 years ago

Hi,

Here's my gatsby config:

module.exports = {
    siteMetadata: {
        title: 'Gatsby',
    },
    plugins: [
        'gatsby-plugin-sass',
        'gatsby-plugin-react-helmet',
        {
            resolve: `gatsby-source-filesystem`,
            options: {
                path: `${__dirname}/src/blog/posts`,
                name: "markdown-pages",
            },
        },
        'gatsby-transformer-remark',
        {
            resolve: `gatsby-plugin-google-analytics`,
            options: {
                trackingId: `UA-36099094-18`,
            },
        },
        {
            resolve: `gatsby-transformer-remark`,
            options: {
                plugins: [
                    {
                        resolve: `gatsby-remark-prismjs`,
                        options: {
                            // Class prefix for <pre> tags containing syntax highlighting;
                            // defaults to 'language-' (eg <pre class="language-js">).
                            // If your site loads Prism into the browser at runtime,
                            // (eg for use with libraries like react-live),
                            // you may use this to prevent Prism from re-processing syntax.
                            // This is an uncommon use-case though;
                            // If you're unsure, it's best to use the default value.
                            classPrefix: "language-",
                            // This is used to allow setting a language for inline code
                            // (i.e. single backticks) by creating a separator.
                            // This separator is a string and will do no white-space
                            // stripping.
                            // A suggested value for English speakers is the non-ascii
                            // character '›'.
                            inlineCodeMarker: null,
                            // This lets you set up language aliases.  For example,
                            // setting this to '{ sh: "bash" }' will let you use
                            // the language "sh" which will highlight using the
                            // bash highlighter.
                            aliases: {},
                        },
                    },
                ],
            },
        },
        {
            resolve: `@andrew-codes/gatsby-plugin-elasticlunr-search`,
            options: {
                // Fields to index
                fields: [
                    'title',
                ],
                // How to resolve each field's value for a supported node type
                resolvers: {
                    // For any node of type MarkdownRemark, list how to resolve the fields' values
                    MarkdownRemark: {
                        title: node => node.frontmatter.title,
                    },
                },
            },
        },
    ],
};

package.json:

{
 ...
  "dependencies": {
    "compass-mixins": "^0.12.10",
    "country-iso-2-to-3": "^1.0.1",
    "elasticlunr": "^0.9.5",
    "gatsby": "^1.9.260",
    "gatsby-link": "^1.6.40",
    "gatsby-paginate": "^1.0.14",
    "gatsby-plugin-google-analytics": "^1.0.31",
    "gatsby-plugin-react-helmet": "^2.0.11",
    "gatsby-plugin-sass": "^1.0.25",
    "gatsby-remark-prismjs": "^2.0.2",
    "gatsby-source-filesystem": "^1.5.35",
    "gatsby-transformer-remark": "^1.7.40",
    "jquery": "^3.3.1",
    "lodash": "^4.17.10",
    "prismjs": "^1.14.0",
    "prop-types": "^15.6.1",
    "rc-slider": "^8.6.1",
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-helmet": "^5.2.0",
    "react-redux": "^5.0.7",
    "react-router-dom": "^4.2.2",
    "react-simple-maps": "^0.12.0",
    "redux": "^4.0.0",
    "redux-saga": "^0.16.0",
    "redux-tooltip": "^0.7.2"
  },
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write 'src/**/*.js'",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "@andrew-codes/gatsby-plugin-elasticlunr-search": "^1.0.4",
    "prettier": "^1.11.1"
  }
}

As an example I only used your github page for this plugin.

Thank you.

andrew-codes commented 6 years ago

@ciokan When do you see this error? Is it during runtime or while building the site? I am going to try to set up a demo using your gatsby config and versions in your package.json to try to troubleshoot. I'll let you know what I find.

andrew-codes commented 6 years ago

I also noticed you have gatsby-transformer-remark registered twice. I am not sure if this will cause problems with the search plugin, but it probably is worth removing in either case.

andrew-codes commented 6 years ago

I have a couple of additional questions. How are you converting markdown files into actual pages (typically in a gatsby-node.js file. Also, what does the consuming search component code look like? The plugin provides a way to retrieve a search index via GraphQL, but does not implement a search component to leverage it. This is primarily up to you to decide how you want the search interactions to work on your site. Would you mind posting what the search component(s) look like?

humphreybc commented 5 years ago

I have the same problem at build time. My error is slightly different, but I think it's the same issue. I've included the error message and relevant files below. Any help would be appreciated @andrew-codes!

Error: SiteSearchIndex.index provided incorrect OutputType: '"SiteSearchIndex_  Index"

package.json

{
  "name": "@dvtl/website",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "apollo:client:codegen": "apollo client:codegen --outputFlat --customScalarsPrefix=GraphQL_ '--queries={{src,node_modules/gatsby-transformer-sharp}/**/*,*.tsx}' --target=typescript --tagName graphql src/types/graphql.tsx",
    "build": "tsc --build",
    "deploy:redirects": "ts-node ./bin/deployRedirects.ts",
    "gatsby:build": "node --optimize_for_size -r ts-node/register ./node_modules/.bin/gatsby build",
    "gatsby:serve": "./node_modules/.bin/gatsby serve",
    "generate:svgs": "svg-to-react src",
    "generate:zapier": "ts-node ./bin/fetch-zapier-templates.ts",
    "start": "tsc --build && concurrently -n gatsby,tsc -c green,blue \"ts-node -r tsconfig-paths -P tsconfig.json ./node_modules/.bin/gatsby develop -H 0.0.0.0 -p 8000\" \"tsc -b -w --preserveWatchOutput\"",
    "lint": "tsc --build && tslint -p tsconfig.lint.json"
  },
  "jest": {
    "globals": {
      "ts-jest": {
        "tsConfig": "tsconfig.json"
      },
      "NODE_ENV": "test"
    },
    "moduleFileExtensions": [
      "js",
      "ts",
      "tsx",
      "json"
    ],
    "moduleNameMapper": {
      ".*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/.jest/imageMock.tsx",
      "@dvtl/website/(.*)": "<rootDir>/src/$1"
    },
    "modulePaths": [
      "<rootDir>/src"
    ],
    "testRegex": "\\.spec\\.tsx?$",
    "testURL": "http://localhost/",
    "transform": {
      "\\.tsx?$": "ts-jest"
    }
  },
  "dependencies": {
    "@babel/core": "^7.2.2",
    "@gatsby-contrib/gatsby-plugin-elasticlunr-search": "^2.2.1",
    "@types/date-fns": "^2.6.0",
    "@types/jest": "^23.3.11",
    "@types/lodash": "^4.14.123",
    "@types/node": "^10.0.0",
    "@types/node-fetch": "^1.6.9",
    "@types/react": "^16.8.2",
    "@types/react-dom": "^16.8.0",
    "@types/react-helmet": "^5.0.5",
    "@types/react-transition-group": "^2.0.15",
    "awesome-typescript-loader": "^5.2.1",
    "babel-core": "6.26.3",
    "date-fns": "^1.30.1",
    "gatsby": "^2.3.3",
    "gatsby-image": "^2.0.5",
    "gatsby-plugin-canonical-urls": "^2.0.5",
    "gatsby-plugin-google-tagmanager": "^2.0.5",
    "gatsby-plugin-react-helmet": "^3.0.0",
    "gatsby-plugin-remove-trailing-slashes": "^2.0.6",
    "gatsby-plugin-robots-txt": "^1.3.0",
    "gatsby-plugin-sentry": "^1.0.1",
    "gatsby-plugin-sharp": "^2.0.32",
    "gatsby-plugin-sitemap": "^2.0.1",
    "gatsby-plugin-typescript": "^2.0.3",
    "gatsby-remark-autolink-headers": "^2.0.10",
    "gatsby-remark-copy-linked-files": "^2.0.8",
    "gatsby-remark-embed-gist": "^1.1.7",
    "gatsby-remark-images": "^2.0.1",
    "gatsby-source-filesystem": "^2.0.1",
    "gatsby-transformer-json": "^2.1.6",
    "gatsby-transformer-remark": "^2.2.5",
    "gatsby-transformer-sharp": "^2.1.17",
    "graphql": "0.13.2",
    "jest": "^23.6.0",
    "jest-cli": "^23.6.0",
    "lodash": "^4.17.11",
    "node-fetch": "^2.1.2",
    "prettier": "^1.11.1",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-helmet": "^5.2.0",
    "react-transition-group": "^2.5.2",
    "strip-markdown": "^3.0.3",
    "ts-jest": "^23.10.5",
    "ts-node": "^7.0.1",
    "tslib": "^1.9.0",
    "typeface-source-serif-pro": "^0.0.73",
    "typescript": "^3.4.1"
  },
  "devDependencies": {
    "@types/react-test-renderer": "^16.0.3",
    "@types/yargs": "^12.0.5",
    "apollo": "^2.6.1",
    "gatsby-remark-smartypants": "^2.0.9",
    "react-test-renderer": "^16.8.6",
    "require-env": "^0.2.1",
    "tagged-template-noop": "^2.1.0",
    "tsconfig-paths": "^3.7.0",
    "yargs": "^12.0.5"
  },
  "apollo": {
    "client": {
      "service": {
        "endpoint": {
          "url": "http://localhost:8000/___graphql"
        }
      }
    }
  }
}

gatsby-config.tsx

const { GATSBY_BASE_URL = "https://dovetailapp.com", SENTRY_DSN = "" } = process.env;

export const siteMetadata = {
  siteName: "Dovetail",
  siteUrl: GATSBY_BASE_URL,
};

export const plugins = [
  "gatsby-plugin-react-helmet",
  "gatsby-plugin-remove-trailing-slashes",
  "gatsby-plugin-sitemap",
  "gatsby-plugin-typescript",
  "gatsby-plugin-typestyle",
  "gatsby-transformer-sharp",
  "gatsby-transformer-json",
  {
    resolve: `@gatsby-contrib/gatsby-plugin-elasticlunr-search`,
    options: {
      fields: ["authors", "title", "path"],
      resolvers: {
        MarkdownRemark: {
          authors: (node: { frontmatter: { authors: string[] | null } }) => node.frontmatter.authors,
          title: (node: { frontmatter: { title: string | null } }) => node.frontmatter.title,
          path: (node: { fields: { path: string | null } }) => node.fields.path,
        },
      },
    },
  },
  {
    resolve: "gatsby-plugin-sharp",
    options: {
      defaultQuality: 80,
      stripMetadata: true,
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      path: "./src/pages/blog",
      name: "blog",
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      path: "./src/pages/company/careers",
      name: "careers",
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      path: "./src/pages/customers",
      name: "customers",
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      path: "./src/data",
      name: "data",
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      path: "./src/pages/help",
      name: "help",
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      path: "./src/pages/legal",
      name: "legal",
    },
  },
  {
    resolve: "gatsby-source-filesystem",
    options: {
      ignore: ["**/*.tsx", "**/*.md", "**/*.ts", "**/*.svg", "**/*.gif"],
      path: "./src/pages",
      name: "images",
    },
  },
  {
    resolve: "gatsby-transformer-remark",
    options: {
      plugins: [
        {
          resolve: "gatsby-remark-smartypants",
          options: {
            backticks: false,
          },
        },
        "gatsby-remark-copy-linked-files",
        {
          resolve: "gatsby-remark-embed-gist",
          options: {
            includeDefaultCss: false,
          },
        },
        {
          resolve: "gatsby-remark-images",
          options: {
            backgroundColor: "transparent",
            linkImagesToOriginal: true,
            maxWidth: 800,
            quality: 80,
            withWebp: true,
          },
        },
        {
          resolve: "gatsby-remark-autolink-headers",
          options: {
            offsetY: 64,
            icon: false,
          },
        },
      ],
    },
  },
  {
    resolve: "gatsby-plugin-google-tagmanager",
    options: {
      id: "GTM-M2PTNW9",
      includeInDevelopment: false,
    },
  },
  {
    resolve: "gatsby-plugin-sentry",
    options: {
      dsn: SENTRY_DSN,
      config: {
        environment: process.env.SENTRY_ENVIRONMENT,
        release: process.env.SENTRY_RELEASE,
        version: "3.24.2",
      },
    },
  },
  {
    resolve: "gatsby-plugin-canonical-urls",
    options: {
      siteUrl: "https://dovetailapp.com",
    },
  },
  {
    resolve: "gatsby-plugin-robots-txt",
    options:
      process.env.PREVENT_CRAWLING === "true"
        ? {
            policy: [{ userAgent: "*", disallow: ["/"] }],
            sitemap: null,
            host: null,
          }
        : { policy: [{ userAgent: "*", disallow: ["/confirm", "/404", "/504", "/users/*"] }] },
  },
];

gatsby-node.tsx

import { TsConfigPathsPlugin } from "awesome-typescript-loader";
import * as path from "path";
import { GatsbyCreatePages, OnCreateNode, OnCreateWebpackConfig } from "./src/types/gatsby";
import { createBlogPosts } from "./src/util/createBlogPosts";
import { createCaseStudies } from "./src/util/createCaseStudies";
import { createHelpArticles } from "./src/util/createHelpArticles";
import { createIntegrationPages } from "./src/util/createIntegrationPages";
import { createJobPosts } from "./src/util/createJobPosts";
import { createLegalDocuments } from "./src/util/createLegalDocuments";

export const onCreateWebpackConfig: OnCreateWebpackConfig = ({ actions }) => {
  actions.setWebpackConfig({
    resolve: {
      plugins: [new TsConfigPathsPlugin({ configFileName: "tsconfig.json" })],
    },
  });
};

export const onCreateNode: OnCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions;

  if (node.internal.type === "MarkdownRemark") {
    // Get the parent node
    const parentNode = getNode(node.parent);

    // Create a field on this node for the "collection" of the parent
    // NOTE: This is necessary so we can filter `allMarkdownRemark` by
    // `collection` otherwise there is no way to filter for only markdown
    // documents of type `post`.
    // tslint:disable-next-line
    if (typeof parentNode.sourceInstanceName === "string") {
      createNodeField({
        node,
        name: "collection",
        value: parentNode.sourceInstanceName,
      });
    }

    if (node.fileAbsolutePath.match(/\/src\/pages\/blog\//) !== null) {
      const blogPath = path.join(__dirname, "src", "pages", "blog");
      const value = "/" + path.normalize(path.relative(path.dirname(blogPath), path.dirname(node.fileAbsolutePath)));
      createNodeField({ node, name: "path", value });
    }

    if (node.fileAbsolutePath.match(/\/src\/pages\/customers\//) !== null) {
      const customersPath = path.join(__dirname, "src", "pages", "customers");
      const value = "/" + path.normalize(path.relative(path.dirname(customersPath), path.dirname(node.fileAbsolutePath)));
      createNodeField({ node, name: "path", value });
    }

    if (node.fileAbsolutePath.match(/\/src\/pages\/company\/careers\//) !== null) {
      const postPath = path.join(__dirname, "src", "pages", "company", "careers");
      const value =
        "/" + path.normalize(path.relative(path.dirname(path.dirname(postPath)), path.dirname(node.fileAbsolutePath)));
      createNodeField({ node, name: "path", value });
    }

    if (node.fileAbsolutePath.match(/\/src\/pages\/help\//) !== null) {
      const helpPath = path.join(__dirname, "src", "pages", "help");
      const value = "/" + path.normalize(path.relative(path.dirname(helpPath), path.dirname(node.fileAbsolutePath)));
      createNodeField({ node, name: "path", value });
    }

    if (node.fileAbsolutePath.match(/\/src\/pages\/legal\//) !== null) {
      const legalPath = path.join(__dirname, "src", "pages", "legal");
      const value = "/" + path.normalize(path.relative(path.dirname(legalPath), path.dirname(node.fileAbsolutePath)));
      createNodeField({ node, name: "path", value });
    }
  }
};

export const createPages: GatsbyCreatePages = async api => {
  await createBlogPosts(api);
  await createCaseStudies(api);
  await createHelpArticles(api);
  await createIntegrationPages(api);
  await createJobPosts(api);
  await createLegalDocuments(api);
};

Search component

import { LocationLink } from "@dvtl/ui-components";
import { Index } from "elasticlunr";
import { graphql, useStaticQuery } from "gatsby";
import React, { useMemo, useState } from "react";

interface SearchResult {
  authors: string[] | null;
  id: string;
  title: string | null;
  path: string | null;
}

// Search component
export const SearchInput: React.FC = () => {
  const [query, setQuery] = useState<string>("");
  const [results, setResults] = useState<ReadonlyArray<SearchResult>>([]);

  const data = useStaticQuery(graphql`
    query SearchIndexQuery {
      siteSearchIndex {
        index
      }
    }
  `);

  const index = useMemo(() => Index.load(data), [data]);

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={e => {
          const query = e.target.value;
          setQuery(query);
          // tslint:disable-next-line:no-any
          setResults(index.search(query, {}).map(({ ref }: { ref: any }) => index.documentStore.getDoc(ref)));
        }}
      />
      <ul>
        {results.map(page => (
          <li key={page.id}>
            {page.path !== null ? (
              <LocationLink location={{ internal: true, path: page.path }}>{page.title}</LocationLink>
            ) : (
              page.title
            )}
          </li>
        ))}
      </ul>
    </div>
  );
};
ldeny commented 5 years ago

I had the same issue, likely due to the use of V2 for Gatsby, the fork @gatsby-contrib/gatsby-plugin-elasticlunr-search solved my issue.