Utility Belt App Extension

Speeding up the development of SSR and offline-first apps

Tobias Mesquita
Oct 5, 2019 · 5 min read
Image for post
Image for post

Note: This article was originally released on Dev.to.

Table Of Contents

1 Introduction

I developed a small app extension with the goal to speed up the development/prototyping of the SSR and offline-first apps. I’ll try to explain all the helpers, how to use them and what problem they try to solve.

2 Installing

quasar ext add "@toby.mosque/utils"

Remember, the full package name is @toby.mosque/quasar-app-extension-utils, but for convenience, the extension will register @toby.mosque/utils as an alias to @toby.mosque/quasar-app-extension-utils/src/utils.

3 Timer

3.1 Sleep

time.sleep is as simple as:

the goal is to enable the dev to suspend an async method for sometime.

outputs:

start:  {"time":1567290656567,"iso":"2019-08-31T22:30:56.567Z"}
end: {"time":1567290661570,"iso":"2019-08-31T22:31:01.570Z"}

4 UUID

A common issue that happens when you use UUID/GUID as primary key, is the order of insertion of your records/docs becomes unpredictable, which can potentially slow down the insertion of new records/docs, or even make the order by id a problem with the UX, since the records/docs will look like it's been shuffled around.

4.1 comb

The comb method is inspired by the C# lib RT.Comb, but I implemented only the Postgre provider, that replaces the first 6 bytes of the UUID with the current date.

4.1.1 parameters

4.2 extractDate

The extractDate method allows the dev to retrieve the date used to create the COMB.

4.2.1 parameters

4.3 Demos

4.3.1 Basic Usage

outputs

comb a:  016ce9d4-cb8f-4b88-b049-8569e9bec009
comb b: 016cee81-321b-f5ee-92ab-fdafda9612fe
date a: {"time":1567291132815,"iso":"2019-08-31T22:38:52.815Z"}
date b: {"time":1567369540123,"iso":"2019-09-01T20:25:40.123Z"}

4.3.2 Sorting

outputs

ascending:
{"index":1,"value":"016ce9dc-9422-be1b-d70f-8769fa62380c"}
{"index":2,"value":"016ce9dc-94e1-40e4-5a16-7db2c0fb109d"}
{"index":3,"value":"016ce9dc-94e3-1316-8633-23694b929895"}
{"index":4,"value":"016ce9dc-94e5-04e3-d043-2b147af04f19"}
{"index":5,"value":"016ce9dc-98ca-8307-1ea1-54a488a1195c"}
{"index":6,"value":"016ce9dc-9cb2-468b-23d6-3bbe47c70539"}
{"index":7,"value":"016ce9dc-a099-fc93-8edf-68f3c00b4fcc"}
{"index":8,"value":"016ce9dc-a482-5f80-b40d-a64b0e8a23a9"}
{"index":9,"value":"016ce9dc-a86a-d6c5-1359-ce0c7b9d053e"}
{"index":10,"value":"016ce9dc-abc4-7d81-e27b-9f1868a48be8"}
descending:
{"index":10,"value":"016ce9dc-abc4-7d81-e27b-9f1868a48be8"}
{"index":9,"value":"016ce9dc-a86a-d6c5-1359-ce0c7b9d053e"}
{"index":8,"value":"016ce9dc-a482-5f80-b40d-a64b0e8a23a9"}
{"index":7,"value":"016ce9dc-a099-fc93-8edf-68f3c00b4fcc"}
{"index":6,"value":"016ce9dc-9cb2-468b-23d6-3bbe47c70539"}
{"index":5,"value":"016ce9dc-98ca-8307-1ea1-54a488a1195c"}
{"index":4,"value":"016ce9dc-94e5-04e3-d043-2b147af04f19"}
{"index":3,"value":"016ce9dc-94e3-1316-8633-23694b929895"}
{"index":2,"value":"016ce9dc-94e1-40e4-5a16-7db2c0fb109d"}
{"index":1,"value":"016ce9dc-9422-be1b-d70f-8769fa62380c"}

5 Store

If you’re developing an SSR or offline-first app, you’re probably overusing Vuex modules; and I know, you don’t have much choice here. So let’s try to make parts of the module definition more reusable.

5.1 mapStoreMutations

mapStoreMutations maps all classes fields to a mutations-like object.

5.1.1 parameters

5.1.2 Demos

5.1.2.1 Basic Usage

Expected Output

Image for post
Image for post

5.1.3 Scenario without the helper

This is what you would need to write to create the above module without using the mapStoreMutations helper

5.2 mapStoreCollections

Here the goal is to create mutations (create, update, delete), actions (upsert, delete) and getters (index, getById) related to array fields.

5.2.1 parameters

5.2.1.1 Collection info object

5.2.2 Demos

5.2.2.1 Basic Usage

Expected Output

Image for post
Image for post

5.2.3 Scenario without the helper

This is what you would need to write in order to create the above module without the help of the mapStoreMutations and mapStoreCollections helpers

5.3 mapState

I don’t know if you noticed, but our store now has a pattern, where the state fields and mutations names have the same name and that has a reason.

We need both to have the same name, in order to map them to a computed property, to be exact, the state will be mapped to a get, and the mutation to a set.

5.3.1 Parameters

The parameters will be very much like the Vuex mapState’s parameters.

5.3.2 Demos

5.3.2.1 Basic Usage

Expected Output

console

Image for post
Image for post

mounted page

Image for post
Image for post

getting record/doc by your id

Image for post
Image for post

item removed

Image for post
Image for post

6 Factories

the primary goal here is to wrap components or generate the whole store and/or pages.

6.1 component

the factory.component objective is to wrap another component and allow the dev to modify them at the render time, or even set up your properties, slots, etc.

6.1.1 Parameters

6.1.1.1 Options

6.1.2 Demos

6.1.2.1 Basic Usage

We’ll inject the reverse property in the QInput and when that property is set as true the label will be inverted. Besides that, we'll set the dark and outlined property to true. The QMarkupTable will also have the dark property changed to true

Expected Output

Image for post
Image for post

6.1.2.2 More Reusable

Ok, we had only 2 components and we already had a lot of boilerplate. We can improve that:

Now, we’re rebranding QInput, QSelect, QField, QMarkupTable, QList and QItem

Expected Output

Image for post
Image for post

6.2 Store

factory.store combines store.mapStoreMutations and store.mapStoreCollections.

6.2.1 Parameters

6.2.1.1 options

6.2.2 Demos

6.2.2.1 Basic Usage

Expected Output

Image for post
Image for post

6.3 Page

factory.page will expect the same options as factory.store and will map the state, mutations, actions and getters generated by factory.store to the page.

6.3.1 Parameters

6.3.1.1 options

6.3.2 Demos

6.3.2.1 Basic Usage

Expected Output

Image for post
Image for post

6.4 Page and Store

Let’s combine factory.page with factory.store and see what happens.

6.4.1 Demos

6.4.1.1 Basic Usage

Pay particular attention to the initialize action, it receives the route as an argument and is called as soon as the store is registered (perfect place to load data intro the state).

Expected Output

console — without initialize action

Image for post
Image for post

console — with initialize action

Image for post
Image for post

rendered page

Image for post
Image for post

Interested in Quasar? Here are some more tips and information:

More info: https://quasar.dev
GitHub: https://github.com/quasarframework/quasar
Newsletter: https://quasar.dev/newsletter
Getting Started: https://quasar.dev/start
Chat Server: https://chat.quasar.dev/
Forum: https://forum.quasar.dev/
Twitter: https://twitter.com/quasarframework
Donate: https://donate.quasar.dev

Quasar Framework

Build high-performance cross-device VueJS user interfaces…

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store