头图

Where is Next.js cool?

I used Next.js + strapi to make a simple blog site and wrote a concise tutorial on Next.js by the way. After that, Next itself has been developing rapidly. Using the ability of generation js to do:

  • Excellent development experience
  • Excellent website, the best "dynamic" and "static" balance

In terms of features, it supports:

  • SSR(Server Side Rendering)
    Provides the getServerSideProps method to request data when the user accesses it, which is suitable for real-time data pages.
  • SSG(Static Site Generation)
    Provide getStaticProps and getStaticPaths methods to produce static pages in advance;

And the cooler point is: use fallback, revalidate to support a certain degree of dynamics.

This kind of "movable" SSG is naturally what I need, to maintain static access, and the site can be automatically updated when I add or modify articles. Excellent! !

Why do we still need to come to Webify to "toss" it?

Now that the above is pretty cool, why is there today's article, and why do I need to toss it?

The reason is also very simple: the cost is slightly higher, for a good access speed, you need a virtual machine with good performance and a certain amount of bandwidth. For general personal blogs, the investment is not cost-effective.

Here are our solutions: Tencent Cloud develops Webify , in simple terms it is a serverless hosting service similar to vercel, but supports more frameworks, and is a domestic service provider, cheap and first-class access speed .

There are pictures as proof:

图片

And now hosting, you can get a 300 yuan no-threshold voucher for free, and you can click on the link below to find out if you are interested: https://cloud.tencent.com/developer/article/1871549

CloudBase Webify Actual Combat

For general articles, it is simple to use github management. Webify supports Github, Gitlab, and Gitee service providers. I heard that Coding will be supported soon:

  • Vue.js (vue-cli)
  • React.js (create-react-app)
  • Hexo
  • Gatsby.js
  • Angular
  • Next.js SSG
  • Nuxt.js SSG
  • And automatic adaptation framework

Take this blog next as an example. Webify actually uses the next export capability. After building, it directly deploys static files to the server.

If your blog post is directly managed by md and git, it will be OK if you see it here. Submit git and Webify will automatically redeploy your site. cool~~

The question is, what if your site data comes from serverless cms like strapi? Next export does not support the "moving" feature (fallback, revalidate) in the next SSG.

Webify Advanced-Automate Webify

In fact, the method is very simple, just add a bridge service and let your serverless cms update change to git.

Take strapi as an example:

  1. strapi data release
  2. Web hook to custom bridge service.
  3. The bridge service update site git.
  4. Weify triggers redeployment.

Of course, if subsequent webify supports more redeployment methods, it will be simpler here.

At first glance, it seems to be back to the original point. We still need a server. Here we will introduce another guest of this article, the tcb cloud function. The above-mentioned on-demand invocation service is most suitable to use cloud functions. You don't need a virtual machine that is always on. You only need to call up the cloud functions when you update the article. It will stop when you use it, and the cost is low.

According to the scenario of this blog, we let the bridging service automatically generate the sitemap of the site to github when the bridge service is running to do two things with one stone.

  • Used for sitemap to generate sitemap xml;
  • Use @octokit/rest, @octokit/plugin-create-or-update-text-file to update the files in github.

Here is the simplified code:

Generate sitemap sitemap.xml

const {
    SitemapStream,
    streamToPromise
} = require('sitemap')
const {
    Readable,
    Transform,
    pipeline
} = require('stream')
const {
    apiRequest,
    getPostsWithGraphql
} = require('./request')
const PaginationLimit = 30
module.exports = ({
    hostname,
    cmsUrl
}) => {

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

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

        const buffer = await streamToPromise(pipeline(postStream, trans, smStream, (e) => {
            // throw e;
        }))
        return {
            path: 'public/sitemap.xml',
            content: buffer.toString()
        }
    }
    
    return Promise.all([
        // getHomeSitemap(),
        // getBookSitemap(),
        getPostSitemap()
    ])
}

Update files in Github

'use strict';
const {
    Octokit
} = require("@octokit/rest");
const {
    createOrUpdateTextFile,
} = require("@octokit/plugin-create-or-update-text-file");
const {
    throttling
} = require("@octokit/plugin-throttling");
const getSitemaps = require('./sitemap')

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

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

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

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


    return {
        doTrigger
    }
};

Author: hicc, Tencent senior front-end development engineer.

Welcome to the official website of Webify: https://webify.cloudbase.net/

Personal site support plan, free 300 yuan voucher without threshold: https://webify.cloudbase.net/blog/personal-site-plan


CloudBase云开发
425 声望438 粉丝

云开发(Tencent CloudBase,TCB)是云端一体化的后端云服务 ,采用 serverless 架构,免去了移动应用构建中繁琐的服务器搭建和运维。同时云开发提供的静态托管、命令行工具(CLI)、Flutter SDK 等能力极大的降...