From Web to App 2
FWTA is a project embraces the vision to create cross-platform mobile first applications using morden web technologies and best practices, such as Server Side Rendering (SSR), Progressive Web Application (PWA), Accelerated Mobile Pages (AMP), PRPL Pattern, Severless Backend.
This is one of the article series which records thoughts and notes during my implementation of FWTA.
In the previous article, I have setup a very simple web app with next.js and react.js. It feaures hot reloading in development and SSR, and has only one DOM in the index page:
1 | <div>FWTA first web app</div> |
In this article, I will setup cloud infrastructure, deploy and publish the web app to the world. Then continue setup with some of my favorite settings. From this point, it makes sense to use my favorite IDE or editor, a.k.a VS Code.
Cloud
Cloud has been a popular term in the industry for years, it provides services and tools to help startups and developers to establish their business. There are a lot of cloud services providers now, and it will be more, just like the clouds on the sky.
I personally have some experience with AWS, Azure, GCP, Zeit, Firebase, as well as cloud services providers from China, such as Alibaba Cloud, Tencent Cloud, Qi Niu.
If you’d like to run business in Chinese Market, I recommend to host your web app and purchase domain with providers from China for easier and faster compliance.
All of the cloud servcies mentioned above are great candidates for consideration when start something new. I would use Firebase with free plan here for simplicity and keep everything under control, it’s backed by Google Cloud.
Serverless
In the “stone age”, people bought physical machines, put them on the rack in a clean glass sealed room. They also bought a lot of network devices, such as routers, switcher in order to turn those machines into servers. They spent a big amount of time configuring routers, switchers, DNS and paying electricity bills. And hire others to keep the machines working 24h x 7. If they still have time and money, they hire somebody else to write code for business.
In the “age of cloud”, large companies bought those machines and devices, put them into large warehouses, and does every single dirty but common job for you. Let you focus on writing code for business by renting you the well prepared and maintained machines. They encourage customers to use their cloud services by buying out all the machine, SSD, RAM on the market. They maximize profits by cutting the machines into multiple pieces then rent the pieces out, they call them Virtual Machines, sometimes also called Containers when cutting into even more pieces.
Now, in the “age of serverless cloud”, those large companies hide the process of signing contracts for those pieces of machines. You hand over your codes, they will execute them for you. Though these codes would likely to be executed on the same pieces of machines, you don’t have to touch them anymore and even not feeling they exist. Yep, this is what I am about to do.
Prepare
Restructure Source Code
Before I mess things up, I’d like to restructure source code. This will give me benefits which is not so obvious now. Simply move pages
folder inside a new folder src/app
. View the new folder structure.
Update Dependencies and Scripts
Update package.json
like this. Remove node_modules
, reinstall dependencies with yarn install
.
Note that I moved next react react-dom
into dev dependencies, because I will use next.js 8 build serverless target feature, which will bundle up everthing needed and there is no runtime dependencies needed from node_modules
on next.js side.
The second thing to notice is I added engines configuration
1 | ... |
This is needed to tell firebase functions to use node.js 8 as running environment, otherwise the default version is 6. Currently only node.js 6 and 8 are supported. Google just made node.js 10 available as beta on GCP Cloud Functions, but not on firebase side, so hope this would be my option soon.
The third thing to notice is that I use npm-run-all to run sequential and parallel scripts, this is the technique really works for me to organize steps and tasks, keep things nice and clean.
Scripts For Release and Clean Up
Add these simple scripts scripts/release.js and scripts/clean.js. This may not make sense yet, but what it’s trying to do is pretty clear. The former copy some files into some locations under dist
folder to get ready for deployment, the latter cleans those folders up.
Add
dist/
folder to .gitignore as it’s produced by release process.
Firebase Setup
Create Project
Go to Firebase, sign up free account and create new project, note down the project ID: fwta-weiwio
.
Add Configuration
Add .firebaserc
in root folder with
1 | { |
This file is git ignored per my setting, so won’t appear in my repo.
Add firebase.json
with this. This file defines how I’m going to use firebase services and how to deploy them. There are two parts hosting
, and functions
.
Hosting is used to host static web resources, traditional websites are static html
with optional js
and css
, in which case hosting service is enough.
But since I need SSR for better performance, I use Functions to response real http requests, and use hosting rewrite rule to rewrite traffics to corresponding serverless functions.
Read more about those rules.
Add Dependencies
1 | yarn add firebase-admin firebase-functions |
Serverless Next.js app
Add next.config.js
to src/app/
with following
1 | module.exports = { |
Try to build with
1 | yarn build |
Under the src/app
, there is a new .next
folder, which contains build output files. Inside this foler, sverless/pages
contains serverless functions for each page, static
folder contains static website resources (.js) which need to be put into dist/_next/static
for firebase hosting to host them statically.
Read more about Next.js 8 Serverless.
Firebase Functions
Write Functions
Add index.js
to new folder src/functions/
with
1 | const functions = require('firebase-functions') |
The code above looks more complex than the example on official documentation for firebase functions. It is because I uses a technique to optimize performance, which use a FUNCTION_NAME environment variable to avoid loading unnecessary resources when only one function is triggered. As serverless functions tends to shutdown environment (docker container) after idling for a certain amount of time. It will cold start after any function is triggered, the cold start is time consuming and it would be ideal to only load things that’s needed.
Deploy
Deployment is easy at this point, just run yarn deploy
. After deployment, you can find the url from firebase console to access the web app. I also hooked my custom domain, so you can see it at fwta.weiw.io. The SSL is enabled on firebase by default, but using SSL on custom domain needs extra configuration.
I bought my domain from namecheap.com and used cloudflare.com for SSL, DNS and CDN. These services are awesome and the latter is free!
Performance
It make sense to do some measurements through the development process as to analyze performance and bottle neck as I implement more and more on this app.
1 | weiwio:FWTA weiw$ ls -ohSR dist/functions/pages |
Cold starts time 78 ms
- Performance: 100
- Accessibility: 70
- Best Practices: 100
- SEO: 80
Summary
To recap, I have setup cloud infrastructure using firebase, and successfully deploy my dummy web app to firebase hosting and serverless functions services. A snapshot commit could be found here.
Next
Setup TypeScript support, add some UI with Material-UI to make it more like an app rather than a web page …