胖罗汉 發表於 2021-9-10 18:11:00

Next.js + 云开发Webify 打造绝佳网站

<h2 id="nextjs酷在哪里"><strong>Next.js酷在哪里?</strong></h2>
<p>之前使用 Next.js + strapi 做了一个简单博客站点也顺道写了一篇 Next.js 简明教程,之后 Next 本身一直在迅猛发展。利用代 js 能力来说做到了:</p>
<ul>
<li>极佳的开发体验</li>
<li>极佳的网站最佳的”动“,“静”平衡</li>
</ul>
<p>从特性上来说,支持:</p>
<ul>
<li>SSR(Server Side Rendering)<br>
提供 getServerSideProps 方法,在用户访问时请求数据,适用于实时数据页面。</li>
<li>SSG(Static Site Generation)<br>
提供 getStaticProps,getStaticPaths 方法来预先生产静态页面;</li>
</ul>
<p>而更酷的一点是:使用 fallback,revalidate 来支持一定的动态性。</p>
<p>这种能“动”的 SSG 自然是我所需要的,保持静态访问,而又能在我新增修改文章的时候,站点能够自动更新。绝佳!!</p>
<h2 id="为什么还需要来webify折腾一番"><strong>为什么还需要来Webify“折腾”一番?</strong></h2>
<p>既然上面已经很酷了,为什么会有今天的文章,为什么还需要折腾一番?</p>
<p>原因也很简单:成本略高,为了不错的访问速度,你需要一台性能不错的虚拟机,一定的带宽。对于一般个人博客,投入不划算。</p>
<p>在这里就隆重地有请我们的解决方案:<strong>腾讯云开发Webify</strong>,简单来说就是类似 vercel 的 Serverless 托管服务,不过支持更多的框架,而且是国内服务商,便宜且访问速度一流。</p>
<p>有图为证:</p>
<p><img src="https://main.qcloudimg.com/raw/beacfddf0ab07b75ddb20a449be91839.jpeg"></p>
<p>而且现在托管,能免费领300元无门槛代金券,香啊~感兴趣的可以点击下方链接了解一下:https://cloud.tencent.com/developer/article/1871549</p>
<h2 id="cloudbase-webify实战"><strong>CloudBase Webify实战</strong></h2>
<p>对于一般文章使用类似 github 管理的就简单了,Webify支持版本 Github、Gitlab、Gitee 服务商,听说即将支持 Coding:</p>
<ul>
<li>Vue.js (vue-cli)</li>
<li>React.js (create-react-app)</li>
<li>Hexo</li>
<li>Gatsby.js</li>
<li>Angular</li>
<li>Next.js SSG</li>
<li>Nuxt.js SSG</li>
<li>以及自动适配框架</li>
</ul>
<p>以本博客 next 为例,Webify实际上使用时了 next export 的能力,构建后,直接部署静态文件到 server。</p>
<p>如果你的博客文章,直接使用 md,git 管理,看到这里就OK了,git 提交,Webify自动会重新部署你的站点。cool~~</p>
<p>问题是如果你的站点数据来源于类似 strapi 这种 serverless cms 怎么办?next export 不支持next SSG中“动”的特性(fallback,revalidate)。</p>
<h2 id="webify高阶自动化webify"><strong>Webify高阶——自动化Webify</strong></h2>
<p>其实方法也很简单,加一个桥接服务,让你的 serverless cms 的更新变动到 git 就好。</p>
<p>具体以 strapi 为例子:</p>
<ol>
<li>strapi 数据发布</li>
<li>web hook到自定义的桥接服务。</li>
<li>桥接服务更新站点git。</li>
<li>Weify触发重新部署。</li>
</ol>
<p>当然如果后续 webify 支持更多的重新部署方式,这里会更简单一点。</p>
<p>这样乍看,似乎又回到了原点,我们还是需要一台服务器,这里又要引入本文的另一个嘉宾了,tcb 云函数。上述这种按需调用的服务,使用云函数最合适了,你不需要一个一直开机的虚拟机,你只需要在更新文章时候才需要唤起云函数就好,随用随停,成本低廉。</p>
<p>按照本博客的场景,我们让桥接服务在运行的时候,自动生成站点的 sitemap 到github来一举两得。</p>
<ul>
<li>用来sitemap生成站点地图xml;</li>
<li>使用@octokit/rest,@octokit/plugin-create-or-update-text-file来更新github中文件。</li>
</ul>
<p>下面是精简过的代码:</p>
<h3 id="生成站点地图sitemapxml">生成站点地图sitemap.xml</h3>
<pre><code>const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;SitemapStream,
&nbsp;&nbsp;&nbsp;&nbsp;streamToPromise
} =&nbsp;require('sitemap')
const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;Readable,
&nbsp;&nbsp;&nbsp;&nbsp;Transform,
&nbsp;&nbsp;&nbsp;&nbsp;pipeline
} =&nbsp;require('stream')
const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;apiRequest,
&nbsp;&nbsp;&nbsp;&nbsp;getPostsWithGraphql
} =&nbsp;require('./request')
const&nbsp;PaginationLimit =&nbsp;30
module.exports = ({
&nbsp;&nbsp;&nbsp;&nbsp;hostname,
&nbsp;&nbsp;&nbsp;&nbsp;cmsUrl
}) =&gt; {

&nbsp;&nbsp;&nbsp;&nbsp;async&nbsp;function&nbsp;getPostSitemap()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;smStream =&nbsp;new&nbsp;SitemapStream({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostname,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;page =&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;postStream =&nbsp;new&nbsp;Readable({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objectMode:&nbsp;true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;async&nbsp;read(size) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;result =&nbsp;await&nbsp;getPostsWithGraphql(`${cmsUrl}/graphql`, page++, PaginationLimit);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(result.error || !Array.isArray(result.data.posts)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.push(null);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;else&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.data.posts.forEach((item) =&gt;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.push(item);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(result.data.posts.length &lt; PaginationLimit) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.push(null);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;trans =&nbsp;new&nbsp;Transform({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objectMode:&nbsp;true,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transform(data, encoding, callback) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;callback(null, {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;url:&nbsp;`/p/${data.book.slug || data.book.uuid}/${
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data.slug || data.uuid
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}`,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;changefreq:&nbsp;'daily',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;priority:&nbsp;1,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastmod:&nbsp;new&nbsp;Date(data.updated_at),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;buffer =&nbsp;await&nbsp;streamToPromise(pipeline(postStream, trans, smStream,&nbsp;(e) =&gt;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// throw e;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path:&nbsp;'public/sitemap.xml',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;content: buffer.toString()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;Promise.all([
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// getHomeSitemap(),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// getBookSitemap(),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getPostSitemap()
&nbsp;&nbsp;&nbsp;&nbsp;])
}
</code></pre>
<h3 id="更新github中文件">更新Github中文件</h3>
<pre><code>'use strict';
const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;Octokit
} =&nbsp;require("@octokit/rest");
const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;createOrUpdateTextFile,
} =&nbsp;require("@octokit/plugin-create-or-update-text-file");
const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;throttling
} =&nbsp;require("@octokit/plugin-throttling");
const&nbsp;getSitemaps =&nbsp;require('./sitemap')

const&nbsp;MyOctokit = Octokit.plugin(createOrUpdateTextFile, throttling);

exports.main =&nbsp;async&nbsp;(event, context) =&gt; {
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;headers: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;authorization,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'x-strapi-event': strapiEvent
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;body
&nbsp;&nbsp;&nbsp;&nbsp;} = event;
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;model,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;entry
&nbsp;&nbsp;&nbsp;&nbsp;} =&nbsp;JSON.parse(body)
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMS_TOKEN,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GITHUB_ACCESS_TOKEN,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BLOG_URL =&nbsp;'https://hicc.pro',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CMS_URL =&nbsp;'https://cms.hicc.pro'
&nbsp;&nbsp;&nbsp;&nbsp;} = process.env;
&nbsp;&nbsp;&nbsp;&nbsp;// strapi 上添加密钥来确保安全
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(CMS_TOKEN !== authorization) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doTrigger:&nbsp;false
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;doTrigger =&nbsp;false&nbsp;//&nbsp;TODO:&nbsp;识别真正的发布
&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;siteMaps =&nbsp;await&nbsp;getSitemaps({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hostname: BLOG_URL,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmsUrl: CMS_URL
&nbsp;&nbsp;&nbsp;&nbsp;})

&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;octokit =&nbsp;new&nbsp;MyOctokit({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;auth: GITHUB_ACCESS_TOKEN,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throttle: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onRateLimit:&nbsp;(retryAfter, options) =&gt;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.warn(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`Request quota exhausted for request&nbsp;${options.method}&nbsp;${options.url}`
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Retry twice after hitting a rate limit error, then give up
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(options.request.retryCount &lt;=&nbsp;2) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(`Retrying after&nbsp;${retryAfter}&nbsp;seconds!`);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onAbuseLimit:&nbsp;(retryAfter, options) =&gt;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// does not retry, only logs a warning
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.warn(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`Abuse detected for request&nbsp;${options.method}&nbsp;${options.url}`
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;&nbsp;&nbsp;await&nbsp;Promise.all(siteMaps.map(({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;content
&nbsp;&nbsp;&nbsp;&nbsp;}) =&gt; {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;octokit.createOrUpdateTextFile({
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// replace the owner and email with your own details
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;owner:&nbsp;"xxx",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;repo:&nbsp;"xxx",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message:&nbsp;`feat: update&nbsp;${path}&nbsp;programatically`,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;content: content,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;branch:&nbsp;'master',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sha:&nbsp;'',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;committer: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;"xxx",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;email:&nbsp;"xxxx@outlook.com",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;author: {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;"xxx",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;email:&nbsp;"xxxx@outlook.com",
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})
&nbsp;&nbsp;&nbsp;&nbsp;}))


&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;doTrigger
&nbsp;&nbsp;&nbsp;&nbsp;}
};
</code></pre>
<p>作者:hicc,腾讯高级前端开发工程师。</p>
<p>欢迎访问Webify官网:https://webify.cloudbase.net/</p>
<p>个人站点扶持计划,免费领300元无门槛代金券:https://webify.cloudbase.net/blog/personal-site-plan</p><br><br>
来源:https://www.cnblogs.com/CloudBase/p/15252646.html
頁: [1]
查看完整版本: Next.js + 云开发Webify 打造绝佳网站