How to use PMKIN with Remix
This guide comprehensively integrates PMKIN, a powerful headless CMS, with your Remix application. We'll walk through each process step, from initial setup to rendering content and optimizing for SEO.
Start by adding the necessary packages to your Remix project. Open your terminal and run:
npm install @apollo/client graphql react-markdown
These packages will allow you to interact with PMKIN's GraphQL API (@apollo/client and graphql) and render markdown content (react-markdown) in your Remix application.
To securely use PMKIN's API, you must set up your API key as an environment variable. Create a .env file in your project root if it doesn't already exist, and add the following line:
PMKIN_API_KEY=your_api_key_here
Replace your_api_key_here with the actual API key you obtained from your PMKIN dashboard.
To interact with PMKIN's GraphQL API, you must set up an Apollo Client instance. Create a new file app/lib/apollo-client.ts and add the following code:
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
const httpLink = createHttpLink({
uri: 'https://content.pmkin.io/graphql'
})
const authLink = setContext((_, { headers }) => {
// Get the API key from the environment variable
const token = process.env.PMKIN_API_KEY
// Return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ''
}
}
})
export const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
})
This setup creates an Apollo Client instance that points to PMKIN's GraphQL endpoint, includes your API key in the authorization header of each request, and uses an in-memory cache for efficient data management. You'll use this client
to query PMKIN's API throughout your application.
To fetch and display a list of documents from PMKIN, you'll need to create a GraphQL query and use it in a loader function. Create a new file for your blog list page, e.g., app/routes/blog.tsx
, and add the following code:
import { useLoaderData, Link } from '@remix-run/react'
import { json } from '@remix-run/node'
import { gql } from '@apollo/client'
import { client } from '~/lib/apollo-client'
const GET_DOCUMENTS = gql`
query GetDocuments {
documents(includeDrafts: false) {
id
title
slug
metaDescription
}
}
`
export const loader = async () => {
const { data } = await client.query({ query: GET_DOCUMENTS })
return json({ documents: data.documents })
}
export default function BlogList() {
const { documents } = useLoaderData<typeof loader>()
return (
<div>
<h1>Blog Posts</h1>
{documents.map((doc) => (
<article key={doc.id}>
<h2><Link to={doc.slug}>{doc.title}</Link></h2>
<p>{doc.metaDescription}</p>
</article>
))}
</div>
)
}
This code defines a GraphQL query to fetch all published documents, uses the query in a loader function to fetch the data server-side, and renders a list of blog posts with links to individual post pages.
PMKIN provides HTML and Markdown versions of your content. You have two options for rendering individual document content.
To use the pre-rendered HTML version of your content, create a new file for individual blog posts, e.g., app/routes/blog.$slug.tsx, and add the following code:
import { useLoaderData } from '@remix-run/react'
import { json, LoaderFunction } from '@remix-run/node'
import { gql } from '@apollo/client'
import { client } from '~/lib/apollo-client'
const GET_DOCUMENT = gql`
query GetDocument($slug: String!) {
documentBySlug(slug: $slug) {
id
title
html
}
}
`
export const loader: LoaderFunction = async ({ params }) => {
const { data } = await client.query({
query: GET_DOCUMENT,
variables: { slug: params.slug }
})
return json({ document: data.documentBySlug })
}
export default function BlogPost() {
const { document } = useLoaderData<typeof loader>()
return (
<article>
<h1>{document.title}</h1>
<div dangerouslySetInnerHTML={{ __html: document.html }} />
</article>
)
}
This approach uses the pre-rendered HTML from PMKIN, which can be faster but gives you less control over the rendering process.
Alternatively, to render the Markdown version of your content, modify the GraphQL query to fetch the markdown instead of HTML and use ReactMarkdown to render the content:
import ReactMarkdown from 'react-markdown'
const GET_DOCUMENT = gql`
query GetDocument($slug: String!) {
documentBySlug(slug: $slug) {
id
title
markdown
}
}
`
export default function BlogPost() {
const { document } = useLoaderData<typeof loader>()
return (
<article>
<h1>{document.title}</h1>
<ReactMarkdown>{document.markdown}</ReactMarkdown>
</article>
)
}
This approach gives you more control over the rendering process and allows you to customize how different elements are displayed.
To optimize your pages for SEO, you can add dynamic meta tags using Remix's meta export. Modify your GraphQL query to fetch meta information:
const GET_DOCUMENT = gql`
query GetDocument($slug: String!) {
documentBySlug(slug: $slug) {
id
title
markdown # or html, depending on your rendering choice
metaTitle
metaDescription
}
}
`
Then, add a meta export to your route file:
import type { MetaFunction } from '@remix-run/node'
export const meta: MetaFunction = ({ data }) => {
return [
{ title: data.document.metaTitle },
{ name: 'description', content: data.document.metaDescription },
// Add more meta tags as needed
]
}
This setup will dynamically set the page title and description based on the data from PMKIN, improving your SEO and social media sharing capabilities.
Now, you are ready to style your components and add additional features specific to your blog or website. You can expand on this basic setup by adding pagination, categories, or search functionality using PMKIN's API.