Content coming soon! [some Notion.so types are not yet supported]For public websites, loading time is crucial. For SEO and good UX, you can not just serve SPA apps without server-side-prerendering them first. However, this introduces a lot of code complexity. Worse, it requires you to re-build all the paths/routes after every change to the content (using Webhooks). For an app with many routes and a lot of content, it will take a long time to build and publish. For very small changes, rebuilding everything every time is overkill.
Option 1: Webhooks
If using a headless CMS like Contentful, or even Wordpress, I'm sure it has a webhook option. Call your server after some content changes. This is a proven and reliable option. It's not as good as Next.js Incremental Builds for regularly changing content, but if your content paths are generated dynamically from some API, then this may be the best option. After done editing, call the webhook (visit some url likehttps://yoursite.co:9999/_prerender) to rebuild the entire site.
Content coming soon! [some Notion.so types are not yet supported]Option 2: Next.js Incremental Builds
Next.js solves this usingIncremental builds. Here is a great quick explanation of server-side rendering by a Next.js developer:https://www.youtube.com/watch?v=IJkTpR7sSwIFor every route/page you can tell Next.js to periodically re-pre-render the page using latest data. So, every 60 seconds or whatever, each of your pages will re-pre-render.
Content coming soon! [some Notion.so types are not yet supported]Option 3: Go back to using PHP
Pass a URL parameter to the specific page you wish to re-render. If the page has sub-pages then those could be re-rendered also. If you pass it to the entire sitehttps://mysite.com?rerender=truethen the entire site can be re-rendered.
Back in my PHP days, this is what we did. The Next.js video above is a bit misleading. It starts out explaining the old-fashioned way of rendering data on the server - for every request, the backend language (PHP, ruby, python) would go and fetch the data, and render it according to the templating markup. However, it was not mentioned that those old-fashioned websites usually cached their data, instead of getting it new for every request. Every so often, the cache would expire and the new data would be fetched before or after the next time a user landed on that page (depending how the site is configured). Or the cache could be cleared manually.
Why not do the same thing with a JAMstack? Well, because the site pages are static files, and separate from the back-end or build process. A JavaScript component in one of the routes in the app can not trigger a build process on itself. See my article "PHP: back to the future".
Content coming soon! [some Notion.so types are not yet supported]Option 4: Separate functionality into micro apps
Next.jsenables mini-apps. You can run the app in a "basepath". So, instead of the React app taking over all your routes (/, /about, /product, /etc), it can be run on just one of the paths!
Content coming soon! [some Notion.so types are not yet supported]Content coming soon! [some Notion.so types are not yet supported]Most first-level routes will be built from your main app. The routes,/,/about,/products/..., and/contactwill be rendered and built by the main app. They'll be put into the "dist" folder or wherever. When linking between these pages, you can use theaboutprovided by your app's router, as any normal built app.
Some of the first-level routes however, will be micro apps, not rendered by the main app. Their "src" code will live outside of this app, wherever you want to store it./app,/support,/blogEach will start out as it's own app. In development environment, will be previewed on a separate portlocalhost:8001,localhost:8002,localhost:8003, etc. They shall not use routing. Instead, use query params to navigate between content. Then, you build it, and it will go from "src" to "dist" folder. After, write a bash script which will copy./distto./main-app/dist/aboutor whatever route you want this micro app to be served at.
When linking to and from these micro-apps, you will not be able to use the app's router. Instead, you have to use regular HTML anchor element. The visitor's browser will have to reload the page when entering the micro app, or coming back to the main app. This should be OK however, for 2 reasons.Micro-apps shall be pre-rendered and very tiny and efficient.They should usePreactor similar small efficient framework. Coming back to the main app, most likely the user started out on the main app, so all the heavy files will already be cached on their browser. So, loading each page should be very quick! However, realistically, this means ALL links to new pages will have to use HTMLtags. So, it still won't be as fast as the router's.
Content coming soon! [some Notion.so types are not yet supported]Content coming soon! [some Notion.so types are not yet supported]Work in progress... mostly obsolete stuff below...
Let's see some code...
What tech to use?
React app (Gatsby or whatever) for the main app. Preact for the mini apps.
How to share CSS/assets between main app and mini apps?
Unfortunately, they'll have to be plain css files. Bad idea to use SCSS or whatever component styles and compile them separately for each build - that would lead to lots of duplicate redundant css included individually into each app. Has to be one css file for all apps. You can still use SCSS or StyledComponents, but it has to be kept in a central location and imported by both main app and mini apps. Then, each when each app edits the SCSS, it can compile it to a CSS version right next to it. Images, svg files, JSON files, etc also in that central assets folder.
node_modules
Projects outside of the project folder can actually reference a different node_modules folder
Build process...
Unfortunately, I don't think this setup will work in a standard pre-configured setup like Netlify. This requires a very custom build process.
Content coming soon! [unfinished content type]{
"object": "block",
"id": "2b28ee38-f504-4a39-94ad-615ffe6ad071",
"created_time": "2021-06-17T14:46:00.000Z",
"last_edited_time": "2021-06-17T14:46:00.000Z",
"has_children": true,
"type": "bulleted_list_item",
"bulleted_list_item": {
"text": [
{
"type": "text",
"text": {
"content": "main app",
"link": null
},
"annotations": {
"bold": true,
"italic": false,
"strikethrough": false,
"underline": false,
"code": false,
"color": "default"
},
"plain_text": "main app",
"href": null
}
]
},
"pageMentions": {},
"sitePreviews": {}
}Content coming soon! [unfinished content type]{
"object": "block",
"id": "bafcdf0c-db2c-4052-8f1e-8060ccbefb0e",
"created_time": "2021-06-17T14:46:00.000Z",
"last_edited_time": "2021-06-17T14:46:00.000Z",
"has_children": true,
"type": "bulleted_list_item",
"bulleted_list_item": {
"text": [
{
"type": "text",
"text": {
"content": "each mini app",
"link": null
},
"annotations": {
"bold": true,
"italic": false,
"strikethrough": false,
"underline": false,
"code": false,
"color": "default"
},
"plain_text": "each mini app",
"href": null
}
]
},
"pageMentions": {},
"sitePreviews": {}
}Wait, why am I doing this?
It'd be nice to separate a huge app with a ton of content into several smaller apps each with a small enough amount of content to be re-built anytime the content is edited.
But I don't have a huge app. I can build my entire app just fine.
So I'm just doing this for the possibility of suggesting it to an enterprise client or employer? That will never happen. The only time a project can completely change its architecture and technology is when it's starting out.
But I do want to start a large app. Lets plan out my idea for a business/web-development resource. I plan to host a lot of content, in many categories, and use Notion as a CMS. So, for each category, I'd have to crawl a published Notion page, and all its sub-pages.
Or something like this. Anyway, it will scrape a few Notion sites. Each one I imagine will be a separate API with very much content and meny routes, so each will take a while to re-build. Next.js incremental builds will not be a great solution, because I don't plan to get data from a CMS for each individual page, but instead get a whole lot of data for an entire set of pages.
Smaller site. Contains one set of "blog" type pages crawled from Notion or similar source. This can be rendered all at once. The demo app also could be managed as part of the main app too.
So, I'm putting this idea of combining multiple micro apps on hold until I get content together for the large site, and practice crawling Notion or whatever for a smaller site.
For now, will continue with theOption 1: Webhooks!