Fernando Botero, Still Life with Fruits, Oil on canvas, 78.1 x 99.1 cm, Rosenbaum Contemporary
Six months ago I started working on a my first *real* Saas app called Checkly. This post is a snapshot of five learnings that stuck with me over the last half year. I hope it helps other self-starting solo developers that have embraced the gooey warmth and bliss that is Vue.js.
To give you some context, this is what Checkly does in a nutshell. Checkly is a tool for IT Ops and Developer people. It does two things.
Enough sales talk. These are the five things that I learned.
Users will probably interact more with your login page than with your landing page, pricing page or some other irrelevant part of your app that only YOU think is really really cool. That’s why login and its related authentication buddies should not suck.
In a typical and non-trivial authentication scenario you have multiple hoops you have to jump through:
Checkly login page
That is already a fair amount of complexity and a lot of things that need to go right before your user can actually start doing stuff. Also, testing of these components can be tricky, as there is a lot of backend and third-party service interaction going on that is hard to mock out or otherwise work around.
In my solution, I took two specific architectural decisions to ease this pain:
Here’s a visual representation of the whole setup. The dancing hamster means you fully signed up and/or logged in.
Auth flow in Checkly
When a user’s JWT token expires, the API backend will say so by responding with a 401 Unauthorised header. You probably want to redirect the user to your login page or show some friendly message. Using the Axios http client and Vue this is about five lines of code.
Using Axios interceptors with the Vue.js bus.
What is a component? A button can be a component. But also a full screen can be a component. Your whole app is a component! Turns out, the split between “components” and “not-components” is not really fine grained enough when making sense of how an app is built.
Of course, I’m not the only one who stumbled onto that. Dan Abramov ‘s article, in a ReactJS context of course, kinda sums it up: split components into containers and things you look at (representational components in Dan’s post, views in mine). The only thing really specific to my solution is that views are always mapped to sub routes.
In the example below you see a typical edit screen. In this case an edit screen for editing an API check. This is the container and it maps to url /checks/<id>/edit/api
The screen is on the “locations & scheduling” tab, which is mapped to its own sub route at /scheduling
This tab contains the country selection and time scheduling components (the red ones). However, these components also live in three other screens: two times in a create wizard and one time in the edit screen for browser checks.
Each of these screens is different and provides a different data context and visual context for each of the components, like whether we are in “edit” mode or “create” mode. In other words, not only the data injected into the component changes (via props), but also the visual arrangement on the screen. Using the containers / views split helps organise this.
And now for something completely different!
The Checkly backend is deployed on Heroku, so I looked into serving the web app also from Heroku. The fewer moving parts the better! However, this is more hassle than you would think.
I looked at third party deployment/CI/CD services. I looked at Netlify. But in the end, I just used some simple NPM scripting together with the knowledge I already had from AWS.
Whip up an S3 bucket and just install the s3-deploy NPM package. Add three lines in the package.json scripts section.
Three lines for great deploys
This set of scripts pushes a Vue.js app that was initially started with Vue-CLI to an AWS S3 bucket. In my situation, I also fronted the S3 bucket with AWS Cloudfront as a CDN. There are a couple of initial setup gotcha’s when creating this setup:
Set your S3 Bucket to hosting and return the index.hml on every error
Create “fake” error pages that just return your app in Cloudfront
Time out. I’ve been in IT for about 20 years now. I have nerdy war stories about the first internet bubble. But as much as technology, the market and the world has changed, one thing has never changed
DEVELOPING NICE AND USEFUL APPLICATIONS IS A SH*T TON OF WORK
And everyone STILL underestimates this: managers, engineers, customers, me. Therefore, the sole reason for me to use third party solutions, open source frameworks, plugins etc. is whether I can reduce the amount of work. Not to integrate with something fancy, not to be the latest to use x or y. Not because Facebook uses it. Seems totally obvious, but many people seem to forget.
Rant over. Here are three Vue.js plugins I can recommend. I use them heavily. What they do is probably clear. They are not perfect, but they will help you reduce your workload.
Bootstrap Vue
Vue-i18n
vee-validate
The Vue.js dev tools Chrome extension is incredible. I use it every day. For me, it is an integral part of the Vue.js eco system, like Vuex and Vue Router. Here’s an example of why it rocks.
I’m fairly sensitive to UI and UX concerns. I don’t mind spending a lot of time getting
This means that in error situations, or other corner cases, I still want something nice to happen. Making this work during development for the frontend can be quite tricky.
Toggling true/false states with quick edit really, really REALLY helps when transitions and stuff depend on complex backend states and XHR messages.
In the example above, the backend API needs to be in a specific state to trigger a certain screen on the frontend. However, that state is not static: it depends on time and other variables that continuously change.
Short of adding your own debug buttons to toggle these states, there is not much else you can do. Vue.js dev tools takes this pain away. Thanks Vue.js dev tools.
I’m building an active monitoring solution for dev & ops team at https://checklyhq.com. Sign up for a free 15-day trial. Not sure yet? Try just clapping 👏 below! or…
Cray cray! 🍍