Tina支持使用外部媒体提供商,但需要用户设置/托管一个轻量级的后端媒体处理器。Tina提供了一些帮助工具来简化这一过程,适用于cloudinary
、s3
和dos
("Digital Ocean Spaces")。
你还需要定义自己的授权函数,以检查用户是否被允许访问处理器。
yarn add @tinacms/auth
根据你的网站框架和托管提供商,有多种方式来托管媒体处理器。
在以下示例中,将<YOUR_MEDIA_STORE_NAME>
替换为cloudinary
、s3
或dos
。
在你的Next.js应用的pages
目录下设置一个新的API路由,路径为pages/api/<YOUR_MEDIA_STORE_NAME>/[...media].ts
。
然后通过调用你的媒体存储库的createMediaHandler方法添加一个新的全捕获API路由。
从"@tinacms/auth"导入isAuthorized
。
authorized
键将使得只有TinaCloud内的授权用户才能上传和编辑媒体。
// pages/api/<YOUR_MEDIA_STORE_NAME>/[...media].tsimport { createMediaHandler } from 'next-tinacms-<YOUR_MEDIA_STORE_NAME>/dist/handlers'import { isAuthorized } from '@tinacms/auth'export default createMediaHandler({// ...authorized: async (req, _res) => {try {if (process.env.NODE_ENV == 'development') {return true}const user = await isAuthorized(req)return user && user.verified} catch (e) {console.error(e)return false}},})
Vercel支持通过在项目根目录创建一个/api
目录来创建无服务器函数。要设置此项,请遵循上述NextJS特定说明,但使用/api/<YOUR_MEDIA_STORE_NAME>/[...media].ts
而不是/pages/api/<YOUR_MEDIA_STORE_NAME>/[...media].ts
注意:你可能会注意到包名可能包含"next"(例如:next-tinacms-cloudinary
)。你仍然可以将这些包用于其他框架。
如果你的网站托管在Netlify上,你可以使用"Netlify Functions"来托管你的媒体处理器。
首先,你必须设置重定向,以便所有请求到/api/*
可以重定向到Netlify Functions。你可以在netlify.toml
中设置重定向。我们还将使用esbuild来构建我们的函数,因此我们也将在netlify.toml
中设置这一点。
在项目根目录的netlify.toml
文件中添加以下内容。
[[redirects]]from = '/api/*'to = '/.netlify/functions/api/:splat'status = 200[functions]node_bundler = 'esbuild'
接下来,你必须为媒体处理器设置API路由。
安装以下依赖项。
yarn add serverless-http express @tinacms/auth next-tinacms-<YOUR_MEDIA_STORE_NAME>
创建一个名为netlify/functions/api/api.js
的新文件,并添加以下代码。
注意:如果你使用不同的函数目录,文件路径可能会有所不同。
import ServerlessHttp from 'serverless-http'import express, { Router } from 'express'import { isAuthorized } from '@tinacms/auth'import { createMediaHandler } from 'next-tinacms-<YOUR_MEDIA_STORE_NAME>/dist/handlers'const app = express()const router = Router()const mediaHandler = createMediaHandler({// ...// 有关createMediaHandler中内容的更多详细信息,请参见下一节authorized: async (req, _res) => {try {if (process.env.NODE_ENV == 'development') {return true}const user = await isAuthorized(req)return user && user.verified} catch (e) {console.error(e)return false}},})router.get('/cloudinary/media', mediaHandler)router.post('/cloudinary/media', mediaHandler)router.delete('/cloudinary/media/:media', (req, res) => {req.query.media = ['media', req.params.media]return mediaHandler(req, res)})app.use('/api/', router)app.use('/.netlify/functions/api/', router)export const handler = ServerlessHttp(app)
如果你的网站托管在AWS上,你可以使用AWS Lambda来托管你的媒体处理器。以下示例 使用S3媒体处理器,但你可以使用任何媒体处理器。
npm install express @vendia/serverless-express @tinacms/auth body-parser
// index.tsimport express, { Router } from 'express'import serverlessExpress from '@vendia/serverless-express'import { isAuthorized } from '@tinacms/auth'import { createMediaHandler } from 'next-tinacms-s3/dist/handlers'import bodyParser from 'body-parser'// 配置TinaCMSconst mediaHandler = createMediaHandler({config: {credentials: {accessKeyId: process.env.TINA_AWS_ACCESS_KEY_ID || '',secretAccessKey: process.env.TINA_AWS_SECRET_ACCESS_KEY || '',},region: process.env.TINA_AWS_REGION,},bucket: process.env.TINA_AWS_BUCKET_NAME || '',authorized: async (req, _res): Promise<any> => {if (process.env.NODE_ENV === 'development') {return true}try {const user = await isAuthorized(req)return user && user.verified} catch (e) {console.error(e)return false}},})// 设置express应用和路由器const app = express()const router = Router()app.use(bodyParser.json())// 定义媒体处理的路由router.get('/s3/media', mediaHandler)router.post('/s3/media', mediaHandler)router.delete('/s3/media/:media', (req, res) => {req.query.media = ['media', req.params.media]return mediaHandler(req, res)})// 将路由器挂载到应用上app.use('/api/', router)// 导出处理函数exports.handler = serverlessExpress({ app })
TINA_AWS_ACCESS_KEY_ID=******************TINA_AWS_BUCKET_NAME=******************TINA_AWS_REGION=********TINA_AWS_SECRET_ACCESS_KEY=******************
Create API
**/api
**的资源,方法是进入Resources并选择Create Resource{proxy+}
特殊语法来获取所有/api
子路径。确保勾选Configure as proxy resource.**save
**并允许API Gateway向Lambda函数添加权限[New Stage]
**并输入Stage name/*
通配符来配置Binary Media Types**/api/s3/media*
路径的请求,并使用刚创建的API Gateway origin。确保允许以下HTTP方法:GET
、HEAD
、OPTIONS
、PUT
、POST
、PATCH
和DELETE
**。/api/s3/media/*
**路径的请求。现在,你可以用外部媒体存储替换默认的基于仓库的媒体。你可以通过loadCustomStore
属性注册一个媒体存储。
loadCustomStore
属性可以在tina/config
文件中配置。
// tina/config.{ts,js,jsx}// ...export default defineConfig({// ...media: {- tina: {- publicFolder: "",- mediaRoot: ""- },+ loadCustomStore: async () => {+ const pack = await import("next-tinacms-<YOUR_MEDIA_STORE_NAME>");+ return pack.TinaCloud<YOUR_MEDIA_STORE>;+ },}})
确保在推送到TinaCloud生产环境时同时提交对配置和tina-lock.json
文件的更改,否则你的资产仍将以https://assets.tina.io
为前缀,就像你仍在使用基于仓库的媒体一样。
现在你可以在TinaCMS中管理外部媒体存储。要详细了解每个媒体存储,请参考下一节。