Utility Belt App Extension
Speeding up the development of SSR and offline-first apps
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
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
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
mounted page
getting record/doc by your id
item removed
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
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
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
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
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
console — with initialize action
rendered page
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