<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: LaughingZhu</title>
    <description>The latest articles on DEV Community by LaughingZhu (@laughingzhu).</description>
    <link>https://dev.to/laughingzhu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1926922%2F5bdccc65-388c-4fa5-af44-2e300b7342e4.png</url>
      <title>DEV Community: LaughingZhu</title>
      <link>https://dev.to/laughingzhu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/laughingzhu"/>
    <language>en</language>
    <item>
      <title>DevNow：支持集成 Tina CMS</title>
      <dc:creator>LaughingZhu</dc:creator>
      <pubDate>Wed, 14 Aug 2024 06:59:05 +0000</pubDate>
      <link>https://dev.to/laughingzhu/devnowzhi-chi-ji-cheng-tina-cms-1o66</link>
      <guid>https://dev.to/laughingzhu/devnowzhi-chi-ji-cheng-tina-cms-1o66</guid>
      <description>&lt;h2&gt;
  
  
  前言
&lt;/h2&gt;

&lt;p&gt;想了很久是否要集成一个类似 CMS 的管理平台来管理这些文章的内容，终于在这周开始落地了。简单说一下我为什么有这个想法的：由于 &lt;a href="https://github.com/LaughingZhu/DevNow" rel="noopener noreferrer"&gt;DevNow&lt;/a&gt; 的定位📌是一个开源的博客项目，所以我在努力的跳出我自己的想法，避免因为一些自己想要的一些功能来让 DevNow 看起来更加的臃肿。集成 &lt;code&gt;Headless CMS&lt;/code&gt; 的主要目的是优化现在的工作流，由于我们是基于 &lt;a href="https://astro.build/" rel="noopener noreferrer"&gt;Astro&lt;/a&gt; 来构建的一个博客项目，所以我们正常的工作流一般是：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;在本地新建一个 &lt;code&gt;.mdx&lt;/code&gt; 文件&lt;/li&gt;
&lt;li&gt;完成文章内容的编辑&lt;/li&gt;
&lt;li&gt;push 到线上环境，重新 &lt;code&gt;build&lt;/code&gt; 生成新的文章内容从而完成网站内容的更新&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这个 workflow 比较恶心的是我们必须要在本地去编辑文档，为了预览可能还需要再一个支持 &lt;code&gt;markdown&lt;/code&gt; 或者 &lt;code&gt;.mdx&lt;/code&gt; 预览的编辑器中来编辑，整体来说感觉这个过程会比较复杂。所以希望通过一些平台来优化这个 &lt;code&gt;workflow&lt;/code&gt; 。然后就有了集成 &lt;code&gt;CMS&lt;/code&gt; 想法，过程中也调研了一些常用的 &lt;code&gt;CMS&lt;/code&gt; 平台，最终选择了 &lt;a href="https://tina.io/" rel="noopener noreferrer"&gt;Tian CMS&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;一些 CMS 平台的对比：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kI190X3W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/985add0258a0673591e07acc23241e26-d73f58.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kI190X3W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/985add0258a0673591e07acc23241e26-d73f58.png" alt="CMS平台功能对比" width="800" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tina 的优势
&lt;/h2&gt;

&lt;h3&gt;
  
  
  基于 Git 的内容管理
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tina 使用 Git 为内容和代码提供单一真实来源，增强开发人员和内容编辑者之间的协作。&lt;/li&gt;
&lt;li&gt;内容更改直接提交到您的存储库，确保版本控制和内容历史记录。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  实时视觉编辑
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;使用 Tina 的实时可视化编辑器直接在您的网站或应用程序环境中创建和编辑内容。&lt;/li&gt;
&lt;li&gt;可定制的内容块允许内容编辑者组装页面并直观地管理内容，类似于使用网站构建器。&lt;/li&gt;
&lt;li&gt;编辑所做的修改可以在发布前实时预览，确保内容的质量。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  内容控制
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Tina 的开源模型让您对您的内容拥有完全的控制权和所有权。&lt;/li&gt;
&lt;li&gt;Tina（可选）的自托管后端让您免受供应商锁定的困扰。&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  可扩展性
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;大规模性能： Tina 专为大型项目而设计。无论您的网站有数百或数万个页面，Tina 都能确保最佳性能。&lt;/li&gt;
&lt;li&gt;强大的查询功能：借助 Tina 独特的数据层，您的 Markdown 内容变得像在数据库中一样灵活且可查询。&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;总结一下：&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;数据存储：Tina 是一款开源的、由 Git 支持的无头内容管理系统 (CMS)，这个正好符合我们的项目结构，文件都是基于 Git 来管理的。其他平台多为在自己的 cloud 端存储，避免后期如果有数据迁移带来的数据问题。&lt;/li&gt;
&lt;li&gt;文件格式：同时支持 Markdown、MDX 和 JSON 等多种内容类型。&lt;/li&gt;
&lt;li&gt;支持实时可视化的编辑器&lt;/li&gt;
&lt;li&gt;支持根据分支来管理版本内容&lt;/li&gt;
&lt;li&gt;Tina 提供了一些自己的数据层，可以灵活的查询&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  具体的集成步骤如下
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://tina.io/docs/frameworks/astro/" rel="noopener noreferrer"&gt;1. 在项目中集成 Tina&lt;/a&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 通过 tina cli 集成，按提示进行配置就好&lt;/span&gt;
&lt;span class="nx"&gt;pnpm&lt;/span&gt; &lt;span class="nx"&gt;dlx&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;tinacms&lt;/span&gt;&lt;span class="sr"&gt;/cli@latest ini&lt;/span&gt;&lt;span class="err"&gt;t
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--erMAVztz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/333135d5eda7089841ddf1c9b4685dae-de253d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--erMAVztz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/333135d5eda7089841ddf1c9b4685dae-de253d.png" alt="tina cli steps" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;到这里就已经在本地集成好了，需要注意的是图中标记的这个路径，需要根据自己项目中文档存储的路径来更换，这里是 DevNow 中的目录。这里如果配置错了也不用急，后边也可以在 &lt;code&gt;tina/config.ts&lt;/code&gt; 中进行修改。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;接下来替换项目运行的命令:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 在 package.json 中修改 scripts 的 dev 和 build 即可&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tinacms dev -c &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;astro dev&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tinacms build &amp;amp;&amp;amp; astro check &amp;amp;&amp;amp; astro build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;根据项目替换 schema ，集体可参考 &lt;a href="https://tina.io/docs/schema/" rel="noopener noreferrer"&gt;schema 配置&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;collections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;doc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Posts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src/content/doc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mdx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Desc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The image used for the cover of the post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;draft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Draft&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;If this is checked the post will not be published&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Category&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Select an category for this post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;
              &lt;span class="p"&gt;};&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// 作者&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Author&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// 标签&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Tags&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// 封面图&lt;/span&gt;
        &lt;span class="c1"&gt;// 发布时间&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;publishDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;PublishDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="c1"&gt;// 是否置顶&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;isTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rich-text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;isBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;:::tip[注意]&lt;/p&gt;

&lt;p&gt;这里需要主要的是在首次运行的时候，会根据 &lt;code&gt;tina/config.ts&lt;/code&gt; 生成一个 &lt;code&gt;tina/tina-lock.json&lt;/code&gt; 的文件，每次修改完都 &lt;code&gt;config.ts&lt;/code&gt; 的时候，都需要在本地运行一下来更新 &lt;code&gt;tina-lock.json&lt;/code&gt; 的内容，否则无法成功 &lt;code&gt;build&lt;/code&gt; 。&lt;/p&gt;

&lt;p&gt;:::&lt;/p&gt;

&lt;p&gt;运行项目：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;pnpm&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;然后访问：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--brQ56z6C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/e28b3684bd31b393d719f01067412df4-c39875.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--brQ56z6C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/e28b3684bd31b393d719f01067412df4-c39875.png" alt="tina 成功集成" width="800" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;看到这样的界面，恭喜你，成功完成了配置 [庆祝][庆祝]&lt;br&gt;
接下来就可以在这里去更新文章的内容了&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Geg75ml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/0a325b503459121c17de1e24ed6ee9f5-4fda95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Geg75ml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/0a325b503459121c17de1e24ed6ee9f5-4fda95.png" alt="更新文章" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. 线上环境集成
&lt;/h3&gt;

&lt;p&gt;通过以上的一些配置，我们已经完成了 &lt;code&gt;local&lt;/code&gt; 的配置，接下来我们需要配置一下线上环境，我们可能主要的场景是在线上环境直接进行文件的更新。&lt;br&gt;
&lt;a href="https://tina.io/docs/tina-cloud/" rel="noopener noreferrer"&gt;Tina&lt;/a&gt; 在这里提供了两套解决方案:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://tina.io/docs/tina-cloud/overview/" rel="noopener noreferrer"&gt;Tina Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tina.io/docs/self-hosted/overview/" rel="noopener noreferrer"&gt;使用自托管后端&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这里我选择了 &lt;code&gt;Tina Cloud&lt;/code&gt; ，具体的思考一个是自托管的配置成本比较高，需要自己的配置实现：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://tina.io/docs/reference/self-hosted/auth-provider/overview" rel="noopener noreferrer"&gt;Auth Provider&lt;/a&gt;：处理 CMS 操作的身份验证和授权。提供由数据库中的用户集合支持的默认Auth.js实现。&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tina.io/docs/reference/self-hosted/database-adapter/overview" rel="noopener noreferrer"&gt;Database Adapter&lt;/a&gt;：处理索引和与数据库的交互（例如MongoDB，Postgres等）&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tina.io/docs/reference/self-hosted/git-provider/overview" rel="noopener noreferrer"&gt;Git Provider&lt;/a&gt;：处理将内容保存到 &lt;code&gt;Git&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;每个模块都是独立的，这意味着您可以选择用不同的实现替换任何模块，或者开发定制解决方案来满足您的特定需求。&lt;/p&gt;

&lt;p&gt;当然自托管也是有一些 &lt;a href="https://tina.io/docs/tina-cloud/faq/#features-unavailable-in-self-hosted-tina-compared-to-tina-cloud" rel="noopener noreferrer"&gt;限制&lt;/a&gt; 的，不过限制部分对我来说不是最主要的问题，是上边三个配置的实现成本。还有就是作为一个博客项目，稳定的存储都在 &lt;code&gt;Git&lt;/code&gt; 上，所以 &lt;code&gt;Tina Cloud&lt;/code&gt; 对我来说是一个更好且简单的实现。&lt;/p&gt;

&lt;h4&gt;
  
  
  2.1 注册 &lt;a href="https://app.tina.io/" rel="noopener noreferrer"&gt;Tina Cloud 账号&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8Bi5uOIx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/c33e15146075697d24a48417fbc497f4-8d5d72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Bi5uOIx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/c33e15146075697d24a48417fbc497f4-8d5d72.png" alt="注册 tina cloud" width="800" height="972"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2.2 创建项目
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ysp9FfJ---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/c96665d56b19ddb78fa9d6e2bf69aff0-550fa5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ysp9FfJ---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/c96665d56b19ddb78fa9d6e2bf69aff0-550fa5.png" alt="创建项目" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tina 提供了两种方式，我们选择第一个，选择导入一个已有的项目开始。根据提示的步骤一步一步来就好，&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2C8OJirA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/79f23a2158ed074b4ff53b745eb7784e-1b1341.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2C8OJirA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/79f23a2158ed074b4ff53b745eb7784e-1b1341.png" alt="创建项目2" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不出意外的话你会看到这样的一个界面。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FY1glEAv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/2b8fd947f3f231fd06bbea05bc990152-bd5f7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FY1glEAv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/2b8fd947f3f231fd06bbea05bc990152-bd5f7f.png" alt="创建项目3" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2.3 &lt;a href="https://tina.io/docs/tina-cloud/deployment-options/vercel/" rel="noopener noreferrer"&gt;配置环境变量&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;这里我是通过 &lt;code&gt;Vercel&lt;/code&gt; 构建项目的，直接在上边配置环境变量就好了，具体如下：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PGwNYWnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/df38d9d935e23f54351e28b245143c39-573988.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PGwNYWnf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/df38d9d935e23f54351e28b245143c39-573988.png" alt="配置环境变量" width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;需要注意的是，如果环境变量名改变的话，记得在项目配置在修改对应的值，具体实在 &lt;code&gt;tina/cinfig.ts&lt;/code&gt; 中：&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lMKRs6Q9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/3aa97ebefed4f675ce23746299383e95-e90698.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lMKRs6Q9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/3aa97ebefed4f675ce23746299383e95-e90698.png" alt="修改项目环境变量名" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2.4 把我们集成好的项目分支推到 Git 上进行构建
&lt;/h4&gt;

&lt;p&gt;如果是首次集成的话需要把我们上一步配置的 &lt;code&gt;PUBLIC_GITHUB_BRANCH&lt;/code&gt; 这个分支名改成当先对应的分支名，否则 &lt;code&gt;Tian Cloud&lt;/code&gt; 无法检测到对应分支，会导致构建失败，等成功推到 &lt;code&gt;mian&lt;/code&gt; 主分支的时候，再将 &lt;code&gt;PUBLIC_GITHUB_BRANCH&lt;/code&gt; 改回主分支名。&lt;/p&gt;

&lt;p&gt;然后回到 Tina Cloud 刷新即可看到：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0MwwPbaS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/6582f25f28d9023feffcb7613e48b77b-21e7aa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0MwwPbaS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn.laughingzhu.cn/DevNow/6582f25f28d9023feffcb7613e48b77b-21e7aa.png" alt="配置完成" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;到这里我们就成功在 &lt;a href="https://github.com/LaughingZhu/DevNow" rel="noopener noreferrer"&gt;DevNow&lt;/a&gt; 中集成了 Tina ，后续可以直接通过线上环境访问即可进行文件更新。直接访问我们配置好的域名 &lt;code&gt;https://www.laughingzhu.cn/admin&lt;/code&gt; 即可。&lt;/p&gt;

&lt;p&gt;也欢迎大家体验开源博客项目 &lt;a href="https://github.com/LaughingZhu/DevNow" rel="noopener noreferrer"&gt;DevNow&lt;/a&gt; ，可以提一些反馈建议，当然也可以顺手点个赞👍🏻&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原文链接&lt;/strong&gt; ：&lt;a href="https://www.laughingzhu.cn/posts/tina-cms" rel="noopener noreferrer"&gt;DevNow：支持集成 Tina CMS&lt;/a&gt;&lt;/p&gt;

</description>
      <category>astro</category>
      <category>opensource</category>
      <category>markdown</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
