Here are some recommended settings for a good result doing your first steps creating a PWA using QCObjects:
Using QCObjects in the front-end will let you tweak a set of options that are useful depending on your needs. The following settings can be set in any JS file at any time of execution. But some of them are gonna work only if you set them up before the building process of the components stack. To do that, just place a script tag at the end of the body of your main HTML file, either placing the code straight away into the script content or putting it in a separate file called init.js (we strongly recommend you to do the second option, as you can have a better approach if you use a service worker).
Below are the front end recommended settings for your progressive web app (PWAs):
The relative Import Path:
Here is a very important setting for your progressive web app. So many times I have heard developers ask... where do I put my related custom coded packages? QCObjects by default will try to find my front-end packages under the same folder I have placed my index.html, but... What happens if I have to code a high scalable app and have to place the common custom packages into a separate folder, because of I gonna use this folder as a symlink into a separate volume that is outside my app container? Well, here is the answer:
CONFIG.set('relativeImportPath', 'js/packages/');
Setting the relativeImportPath value, you can tell QCObjects to find your front-end packages in the folder you have specified. And then, you can symlink this folder to another external volume or whatever you mind to do, I don't know, probably just to organise better your stuff.
Same thing applies to the templates of components. A lot of developers are asking what to do if I have to code the corporate component templates once! Just once! And NOT copying from one app to another app every time I deploy a new app?
Well, just set this:
CONFIG.set('componentsBasePath', 'templates/components/');
And then you can make a symlink to templates/components or whatever you have set up in this value, pointing to an external volume of your container. That external volume will be put into every single new container app you done, and voila! You have common component templates for every app! And they are absolutely behavioural independent.
As additional information I can recommend you to study configMaps with Kubernetes, that is a good solution to apply in conjunction of separating folders for common uses in external volumes. Read some suff here and let me know if after you finish your head is still rounded 🤪.
The delay for ready:
Another good practice is to set the delay that will happen before the Ready process is started. As QCObjects has a very advanced way to handle the Ready events, I mean, when you use the Ready() function you're not just using a wrapper of the original window.ready event (as it was used to be in an older framework that I will not tell you the name but it starts with "J" and "Q" 😛).
By example, if you use QCObjects over a PhoneGap app, the Ready() function of QCObjets will also handle the "deviceready" event simultaneously, and it will be executed ONLY after the time of delay for ready has past. But, what on earth is this useful for? Good question... I don't really know 😝 but I can imagine that some day you'll gonna have some particular issue with some third party script blocking your entire script flow and you gonna have the need of apply some delay to the start processes.
Default value is cero (0), but in the QCObjects New App template (used with the CLI tool to create your new PWAs), is set to One (1). What is better? You tell me 🤷♂️🤷♀️
CONFIG.set('delayForReady', 1); // delay to wait before executing the first ready event, it includes imports
Cool, I can set to "preserveComponentBodyTag off! Ok, what is this for? Ok this seems to be not doing something very significant for the behaviour of our app. No, my friend, you're completely misunderstanding the purpose of life 🧑🎓. I'll tell you something about behaviour...
If a component doesn't have a body, how the hell it will work? Well, in QCObjects it will work 🧑🏫, but different.
In tech hands words, setting this:
CONFIG.set('preserveComponentBodyTag', false);
Will cause your <component> tag have a default body with "nothing", and when I say nothing, I mean nothing. So the component stack builder process will fill up the body with the template content without the need of an enclosing tag. Understood? So, forget about this kind of stuff:
- Parse Error: Adjacent JSX elements must be wrapped in an enclosing tag
This will not happen here!
But if you need to enclose your component because you feel confortable with that, you can still use an autogenerated <componentBody> tag is placed for you by the component stack building process when you set this value with true 🧑🍳.
Using a config.json file as a config service
Oh! Ok, this is gonna blow your mind a little bit. You can use all of these settings loaded from an external file, that you can put either in an external volume (as I explained before ) or if you are deploying your progressive web app using the QCObjects HTTP2 Built-In Server (I know the name is quite large) you can also set a config.json in the backend side and use the config encryption built-in micro-service to encrypt all front-end settings, so you can protect all the sensitive data you have to use in the front-end side.
Take it easy, be quiet! I'll do a special tutorial just to do that step.
CONFIG.set('useConfigService', false); // If this is true, settings will be loaded from config.json
Setting the routing way for the dynamic component routings handler.
Cool, what is this? Ok, I'll explain you in a moment, I'll just do some stuff first... just kidding ! In the front-end side, you have three ways to handle routings (mmm... not really, you have thousands since you can use regular expressions). By the way, the browser has three ways to understand how to point your routings (better?):
1) Pointing by using hashes or hashtags. I'm talking about #this #thing, yes, the #hashtag or old fashioned #anchor that you have used thousands of years ago in the links !
In QCObjects, if you make a routing component that is having some set like this:
<component name="loading-routing">
<routing path="#page1" name="mypage1"></routing>
<routing path="#page2" name="mypage2"></routing>
<routing path="#page3" name="mypage3"></routing>
</component>
And in your CONFIG values you have:
CONFIG.set('routingWay','hash');
2) If you point your page index.html to an anchor link #page1 (like index.html#page1 or index.html#page1?foo=bar or index.html?foo=bar#page1, I mean, you use an anchor right? you know what I'm talking about), the component stack builder will try to find a templates that matches the name attribute in the routing (by example: "mypage1" that could be a mypage1.tpl.html file in your templates/components folder )
Ok, but I'm not using anchor dude! I'd like to use only the raw path, because I've learned that I can handle my single page app even if I use raw paths with QCObjects HTTP2 Built-In Server, so... what if I set all my routings like this:
<component name="loading-routing">
<routing path="^/page1$" name="mypage1"></routing>
<routing path="^/page2$" name="mypage2"></routing>
<routing path="^/page3$" name="mypage3"></routing>
</component>
OK, OK, OK! Your code isn't broken bro! You have to calm down! Because QCObjects is trying to find an #anchor with this path, that obviously will not work.
To handle in the right way this kind of thing, you can set the routingWay! Wow! I've just explained it in a bunch of lines! (you got it, advanced programming is not easy as they've sold you bro! ). But coming back, you can set up the routingWay value to "path"
CONFIG.set('routingWay','path');
The above will let to QCObjects to match paths like this:
https://example.com/page1https://example.com/page2https://example.com/page3
Take in consideration that QCObjects will do it whenever is possible, because some servers are not capable to do that. If you're going to use this set of links, I highly recommend you to deploy your PWA over QCObjects HTTP2 Built-In Server that is supporting that behaviour as native.
3) You can also do links like this:
https://example.com/index.html?page1https://example.com/index.html?page2https://example.com/index.html?page3
I personally don't recommend you to do that, because it is agains almost any standard, but If you are not in a chance to choice because you're working in on a legacy app or something... well, you can set the routingWay value to "search"
CONFIG.set('routingWay','path');
Use the SDK
Yes, please, use it! It's very useful! And it's gonna be more day by day !
CONFIG.set('useSDK',true); // it is recommended to use the SDK that is dynamically loaded, but you can chose not to load it
Use the local SDK
By default, the SDK is loaded from the QCObjects Official CDN url. If your app is private and have not access to the internet (I can't imagine why because it's a web app), you can set up to use the SDK from the relative path in your project.
CONFIG.set('useLocalSDK',false); // on the frontend side you can chose whether to load the SDK from sdk.qcobjects.dev or from your local website. Default is false
Setting the templates file extension:
To set the file extension to locate the template files, you can do it by using CONFIG or on the Class definition of the custom component. I recommend you to standardise your code bro, use the CONFIG and the same file extension for every single component.
Then, if component.name = 'main' template name will be always main.tpl.html and your code will not become an "spaghetti".
CONFIG.set('tplextension','tpl.html');
So:
<component name="main" ></component>
Will try to find a main.tpl.html inside your templates/components folder.
What is the asynchronousImportsLoad setting?
When I was coding QCObjects, I was asking to myself the same question, what is asynchronous load of imports? Well, In QCObjects that means that all the internal "script" elements that QCObjects will create to load the imports will have the async attribute set with a value of true. And each browser will interpret that as they want!
By convention, it is recommended to load all the script elements in your page in async mode, but some times you wont do that. And the most of browsers don't really care. My conclusion, by default is cero (0) but I recommend you to always set this true bro, seriously. You're not passing the Audit tests of Chrome if you don't do that.
CONFIG.set('asynchronousImportsLoad', true);
Setting the service worker URI
Good, we are almost done, now we need a service worker that applies a cache or something innovative for our new app. Cool, but I have to register the service worker just in time, not before, not after, everything is loaded. How on earth is it supposed to be done? Don't worry bro, QCObjects is making this monkey job for you. You just need to specify where is the service worker located.
CONFIG.set('serviceWorkerURI','/sw.js'); //QCObjects will register an launch this service worker automatically to work offline
I hope the explanation of this tutorial wasn't very large (that's a lie, of course I know it's large) but I hope you've enjoyed it as much as I enjoy the huge amount of time I saved every time I build a new progressive web app using QCObjects.
Cheers!
Previously published at https://devblog.qcobjects.org/recommended-front-end-settings-for-your-pwa-using-qcobjects-ck8zbjdc301kjmys10xxpz7td