npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hashicorp/react-search

v6.6.0

Published

Algolia-powered search component

Downloads

2,137

Readme

@hashicorp/react-search

Props

renderHitContent

function | ({ hit: object, Highlight: React.Node }) => React.Component | Required

A render function whose result is used to display each query "hit"

Params

| Property | Type | Description | | --------- | ------------ | ----------------------------------------------------------------------------------- | | hit | object | https://www.algolia.com/doc/api-reference/widgets/highlight/react/#widget-param-hit | | Highlight | React.Node | https://www.algolia.com/doc/api-reference/widgets/highlight/react/ |

resolveHitLink

function | | ( hit: object ) => NextLinkProps | Optional | Default: (hit) => ({ href:/${hit.objectID} })

A function whose return value is spread as props to next/link. For more information about the available props, reference the next/link documentation: https://nextjs.org/docs/api-reference/next/link

Params

| Property | Type | Description | | -------- | -------- | ----------------------------------------------------------------------------------- | | hit | object | https://www.algolia.com/doc/api-reference/widgets/highlight/react/#widget-param-hit |

placeholder

string | Optional | Default: Search

Usage

import Search from '@hashicorp/react-search'

function SearchBar() {
  return (
    <Search
      renderHitContent={({ hit, Highlight }) => <div>...</div>}
      resolveHitLink={(hit) => ({ href: { pathname: `/${hit.objectID}`, query: { id: hit.__queryID} } })}
      placeholder="Search documentation"
    />
}

Environment Variables

This component relies on the presence of the following environment variables to be available client side:

NEXT_PUBLIC_ALGOLIA_APP_ID
NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_API_KEY
NEXT_PUBLIC_ALGOLIA_INDEX

React

To use the primary <Search /> component, ensure it exists as a child of the <SearchProvider /> component. For example:

App.jsx

import Search, { SearchProvider } from '@hashicorp/react-search'

function App() {
  return (
    <>
      <SearchProvider>
        <Search
          renderHitContent={({hit, Highlight}) => (
            <span className="name">
              <Highlight attribute="name" hit={hit} tagName="span" />
            </span>
          )}
          resolveHitLink={(hit) => ({ href: `/${hit.objectID}` })}
        />
        <ComponentA>
        <ComponentB>
      </SearchProvider>
      <ComponentC__WithoutSearchContext>
    </>
  )
}

Any child component of <SearchProvider /> can utilize the provided useSearch() hook and access search-specific information. For example:

import { useSearch } from '@hashicorp/react-search'

function ComponentA() {
  const { query } = useSearch()

  return <code>Search query: {query}</code>
}

useSearch()

useSearch() exposes the following values:

  • client (object) - Initialized Algolia client
  • indexName (string) - The name of the Algolia index that search is performed upon
  • initAlgoliaInsights (function) - Required to initialize Algolia
  • isCancelled (boolean) - Indicates if search is currently cancelled or not
  • logClick (function) - Fires an analytics event via the search-insights package
  • query (string) - Current search query
  • setIsCancelled (function) - Setter function that updates the search cancel state
  • setQuery (function) - Setter function that updates the search query

Tools

This package includes a tools.js file that includes Algolia-related Node.js scripts

Usage

const {
  indexDocsContent,
  indexContent,
} = require('@hashicorp/react-search/tools')
/* It's worth noting that you'd only want to use *one* of the two exported functions */

indexDocsContent

function | (config: object) This specific helper function is designed specifically for perfoming search indexing on our various product sites' documentation pages.

config.algoliaConfig: { appId: string, apiKey: string, index: string }

Algolia-related configuration

Default:

{
  apiKey: process.env.ALGOLIA_API_KEY,
  appId: process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
  index: process.env.NEXT_PUBLIC_ALGOLIA_INDEX,
}
config.contentDir: string

Path to directory that contains the content to be indexed by Algolia

Default: path.join(__dirname, 'pages')

config.filesPattern: string

minimatch-style string to be performed within config.contentDir. The results of this pattern match will determine which files to index.

Default: '**/*.mdx'

config.globOptions: { [k:string]: any }

Additional options to include to the glob match. Available options here

Default: { ignore: path.join(config.contentDir, 'partials/**/*') }

config.frontmatterKeys: string[]

Assuming your search-indexed content includes frontmatter, the keys included in this array will be included as search criteria.

Default: ['page_title', 'description']

indexContent

function | (config: object) This generic helper function allows for custom Algolia indexing

config.algoliaConfig: { appId: string, apiKey: string, index: string }

Algolia-related configuration

Default:

{
  apiKey: process.env.ALGOLIA_API_KEY,
  appId: process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
  index: process.env.NEXT_PUBLIC_ALGOLIA_INDEX,
}
config.getSearchObjects: () => any

This function should return an array of objects that will get passed to Algolias partialUpdateObjects function

Setting Up Algolia

In order for this component to work at all, you will need to configure an algolia index. Steps to manage this are below:

  • Log in to algolia.com using HashiCorp SSO. If you do not have access to algolia, reach out to IT and request access.

  • Within algolia, select "incices", then "create new index". See existing indices for naming patterns when choosing your index name. For docs sites, it is usually product_NAME.

  • In your local .env file, use the index name as your NEXT_PUBLIC_ALGOLIA_INDEX value

  • Make sure that you have created a file in your project that runs the indexDocsContent script out of `tools. The file should be quite simple, and look like this:

    const { indexDocsContent } = require('@hashicorp/react-search/tools')
    indexDocsContent()
  • Typically we run this script via circleci. Head over to your project's circle configuration and add a block along these lines to jobs:

    jobs:
      algolia-index:
        docker:
          - image: docker.mirror.hashicorp.services/node:12
        steps:
          - checkout
          - run:
              name: Push content to Algolia Index
              command: |
                cd website/
                npm install
                node scripts/index_search_content.js
  • Then make sure to run the job in the workflows section as well, only when the website is deployed. For docs sites this is on merge to the stable-website branch. For most other HashiCorp websites, this is on merge to main or master.

    workflows:
      - algolia-index:
          filters:
            branches:
              only:
                - stable-website
  • Next, you'll want to setup two API keys for (1) searching and (2) indexing. Our Algolia keys are currently managed via a Terraform configuration. The ACL for the keys should be configured as follows:

    | Index | ACL | Example Descrption | |-----------|--------------------------------------------------------------------------------------------|-------------------------------------| | search | search, browse, listIndexes | {product/project name}: search UI | | index | addObject, deleteObject, search, browse, listIndexes, settings, editSettings | {product/project name}: write key |

  • Open a PR to update the Terraform Configuration with the new pair of keys.

  • Grab the index API key, which is sensitive and should not be public, and add it to the environment variables in circleci as ALGOLIA_API_KEY.

  • Grab the search API key, which is public, and add it to the .env file in the project: NEXT_PUBLIC_ALGOLIA_SEARCH_ONLY_API_KEY=xxxx.

  • With this in place, you should be all set! Run the index script once locally, manually setting the algolia API key (like ALGOLIA_API_KEY=xxxx node scripts/index_search_content.js) to seed the index and make sure that the component is fully functional locally, then everything should be set!