/nuxt-payload-template

nuxt3 + payload + typescript + pinia + tailwind

Primary LanguageTypeScript

nuxt-payload-template

⚠️ Work In Progress

This template is slightly opinionated based on my main use case for client work, but the core monorepo structure is still a good basis for any Nuxt/Payload project.

I update the repo and packages manually as I continue to refine things during the course of my projects.

If you have any questions/suggestions, feel free to open up an issue.

A Nuxt 3 + TypeScript starter template, with Payload CMS.

Requirements

Usage

# Install packages
pnpm install

# Create .env interactively
pnpm run configure-env

# Update packages interactively (minor versions)
pnpm run update

# Update packages interactively (major versions)
pnpm run update-latest

# Start dev server
pnpm run dev

# Generate gql exports, possibleTypes, and Payload types (run while dev server is active)
pnpm run generate

# Build for production
pnpm run build

# Start server
pnpm run start

Setup

Nitro Dev Proxy

Nitro acts as a proxy for all Payload requests during development, using the nitro.devProxy option in nuxt.config.js. If you need to proxy additional routes, you can add the to the payloadProxyRoutes array.

Environment Variables

Environment variables are defined in .env and shared between apps with dotenv-cli. Variables prefixed with PAYLOAD_PUBLIC_ are exposed to Payload's client-side app.

Running pnpm configure-env will guide you through creating a .env file.

Variable Default Description
NITRO_HOST 0.0.0.0 Host for Nuxt's Nitro server
NITRO_PORT 3000 Port used by Nitro's server
PAYLOAD_PUBLIC_SITE_NAME Nuxt x Payload Template The title of the site (used for page title templates, etc.)
PAYLOAD_PUBLIC_SITE_URL https://localhost:3000 URL of the site, including protocol
PAYLOAD_PUBLIC_PORT 3001 Port used by Payload's Express app
PAYLOAD_PUBLIC_API_ROUTE /_payload Route used for Payload's API
PAYLOAD_PUBLIC_UPLOAD_ROUTE /media Route used for Payload's upload collections
DATABASE_NAME nuxt-payload The name of the MongoDB database
PAYLOAD_SECRET - A secret key used for encrypting Payload data/sessions

Custom Local Hostname

You will need to set up a custom local hostname for local development, using NGINX and the provided nginx-conf-examples/local.conf config. If you use mkcert for local SSL certificates, you can use the provided nginx-conf-examples/local-mkcert.conf.

Make sure the update the server_name directive, any changes to the default ports, and the ssl_certificate and ssl_certificate_key paths if required.

You will also need our hosts file so the custom hostname resolves to 127.0.0.1:

# /etc/hosts

127.0.0.1       example.test

💡 hostctl is a nice CLI tool for managing your hosts file

DX

Payload Types

Payload types can be generated by running the generate command

pnpm run generate --filter payload

You can easily access Payload's generated types within the Nuxt workspace using the #payload alias

import type { Image } from '#payload/types'

💡 Type imports must be explicit since Nuxt 3.8, so make sure to use import type ...

Type-safe Relationship Fields

Payload Relationship fields for GraphQL queries are typed as string | MyCollectionType (or string[] | MyCollectionType[] when the field uses the hasMany option). This is because querying the field without any subfields will return the document ID:

# Will return an ID
query GetRelationship {
  doc {
    relationshipField
  }
}

# Will return an object
query GetRelationship {
  doc {
    relationshipField {
      subField
    }
  }
}

This can cause type issues when using these fields within Nuxt, so there are two composables that can be used to check the type of relationship fields.

<script lang="ts" setup>
const doc = useRelationshipField(data.doc.relationshipField) // RelationshipType | null
const docs = useRelationshipArrayField(data.doc.relationshipHasManyField) // RelationshipType[]
</script>

GraphQL Exports

GraphQL documents are generated from the .gql files in apps/nuxt/graphql, and output to apps/nuxt/graphql/index.js. You can regenerate the exports using the generate script

pnpm run generate --filter nuxt

💡 Nuxt's generate script will also query the Payload schema, so make sure the Payload app is running (via dev server or otherwise)

usePayloadPage composable

The Pages collection is set up for building predefined page templates, and the usePayloadPage composable makes it easy to retrieve page data using Apollo, while also automatically set any SEO/Meta values provided by @payloadcms/plugin-seo.

<script lang="ts" setup>
const doc = await usePayloadPage('Home')
const fields = doc.value?.homeFields
</script>

Globals

Globals data is located in the @/stores/globals store, and is preloaded during SSR (see apps/nuxt/app.vue).

Thanks

@sifferhans for telling me about Turborepo and Nitro proxies.