What’s cool about next.js?

After creating a simple blog site using nex.js + strapi and writing a brief tutorial on nex.js, Next itself has been growing rapidly. Using generation JS ability to do:

  • Great development experience
  • Excellent site for optimal “dynamic” and “static” balance

In terms of features, it supports:

  • SSR(Server Side Rendering) provides the getServerSideProps method to request data during user access, which is suitable for real-time data pages.
  • Static Site Generation (SSG) provides getStaticProps and getStaticPaths to pre-produce Static pages.

The cool thing is to use fallback, revalidate to support some dynamics.

This kind of “moving” SSG is naturally what I need to keep static access while the site automatically updates as I add and modify articles. Perfect!!!!!

Why is there a need for Webify?

If it’s already cool, why is there today’s article and why does it need to be done?

The reason is simple: it costs a little more, and for decent access speed, you need a decent VIRTUAL machine with a decent amount of bandwidth. For the average individual blog, investment is not cost-effective.

Here is our grand solution: Tencent Cloud development Webify, in simple terms, is similar to Vercel Serverless hosting service, but supports more frameworks, and is a domestic service provider, cheap and first-class access speed.

There are pictures to prove:

And hosting now, can bring 300 yuan threshold vouchers, free sweet ~ interested can click on the link below to understand: cloud.tencent.com/developer/a…

CloudBase Webify of actual combat

Github, Gitlab, and Gitee will support Coding soon:

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

In the case of next on this blog, Webify actually uses the next Export capability and, once built, deploys static files directly to the server.

If your blog posts are managed directly using MD, git, and you can see it here, Git submission and Webify will automatically redeploy your site. Cool ~ ~

The question is what if your site data comes from a Serverless CMS like StrAPI? Next Export does not support the “move” feature (fallback, revalidate) in next SSG.

Advanced Webify – Automated Webify

In fact, the method is very simple, add a bridge service, let your serverless CMS update changes to Git.

Take StrAPI as an example:

  1. Strapi data distribution
  2. Web hooks to custom bridging services.
  3. Bridge service update site Git.
  4. Weify triggers redeployment.

Of course, this will be easier if webify supports more redeployment options later on.

At first glance, it seems that we are back to square one, we still need a server, here again to introduce another guest of this article, TCB cloud function. You don’t need to have a virtual machine running all the time. You only need to invoke the cloud function when you update your article.

In the scenario of this blog, we have the bridge service automatically generate the sitemap of the site to Github while running to kill two birds with one stone.

  • Generate sitemap XML for sitemap;
  • Use @octokit/rest, @octokit/plugin-create-or-update-text-file to update github files.

Here is the simplified code:

Generate the 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() ]) }Copy the code

Update Github files

'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; // add key to strapi to ensure security 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: "[email protected]", }, author: { name: "xxx", email: "[email protected]", }, }) })) return { doTrigger } };Copy the code

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

Welcome to Webify website: webify.cloudbase.net/

Personal site support: webify.cloudbase.net/blog/person…