The TinaProvider
component makes it possible to attach forms to the Tina sidebar, but we need to wire up a backend in order for content changes to be persisted anywhere. Let's set up the default Git backend.
The Git backend consists of two parts:
Because backends in Tina are designed as Express-compatible middleware, we need a way to add middleware to our Next.js dev server. To do this, we will need to use Next.js with a custom development server that will use Express and allow us to attach the Git middleware.
Run the following installation command:
yarn add express cors @tinacms/api-git @tinacms/git-client
Start by creating a custom server file to run your dev server. Next.js provides an example of using an Express server in this GitHub repository, which we'll be following pretty closely.
A bare-bones server.js
file might look something like this:
const express = require('express')
const next = require('next')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
In order to run this server instead of the default Next.js dev server, you will need to set up a script in your package.json
file to run this file:
"scripts": {
- "dev": "next",
+ "dev": "node server.js",
"build": "next build",
"start": "cross-env NODE_ENV=production node server.js"
}
As mentioned previously, backends in Tina are written as middleware that can be attached to any Express server. Now that we have our custom dev server running Express and handling requests, all that's left to do is attach the necessary middleware in server.js
:
const express = require('express')
const next = require('next')
+ const cors = require('cors')
+ const gitApi = require('@tinacms/api-git')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
+ server.use(cors())
+ server.use('/___tina', gitApi.router({
+ pathToRepo: process.cwd(),
+ pathToContent: "",
+ }))
server.all('*', (req, res) => {
return handle(req, res)
})
server.listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
Now we need to configure the CMS to consume the Git API now running on the backend. We can do this easily with the GitClient
class from the @tinacms/git-client
package.
When creating an instance of GitClient
, we need to pass it the URL where the API endpoints can be reached. Since we're running the server locally on port 3000, the full URL to our Git backend is http://localhost:3000/___tina
. We could then instantiate the Git client as follows:
const client = new GitClient('/___tina')
We'll need to amend our _app.js
application wrapper to register this with the CMS. We can pass APIs, Media, and UI settings in a config object to TinaCMS
.
The pages/_app.js
file should now look something like this:
import React from 'react'
import App from 'next/app'
import { TinaProvider, TinaCMS } from 'tinacms'
import { GitClient, GitMediaStore } from '@tinacms/git-client'
class MyApp extends App {
constructor() {
super()
const client = new GitClient('/___tina')
this.cms = new TinaCMS({
enabled: true,
apis: {
git: client,
},
media: new GitMediaStore(client),
sidebar: {
position: 'overlay',
},
})
}
render() {
const { Component, pageProps } = this.props
return (
<TinaProvider cms={this.cms}>
<Component {...pageProps} />
</TinaProvider>
)
}
}
export default MyApp
If you restart the dev server, you should see an 'edit icon' in the lower left-hand corner. If you open that, you'll see and empty Tina sidebar! Let's create some forms to edit content from the sidebar.