Chat System: How to design a library (Part Three)
Overview
We need to create a Library that any customer can easily integrate to their website. The Library should provide a UI widget in the corner and have an API platform to intercommunicate, if a customer wants to override the default behavior.
Library Design
Common Rules for any JS Library
Here is a list of rules that each library should follow:
- Avoid overriding, changing, and modifying the global environment and the default CSS. Avoid adding a method to global objects and changing the behavior of the DOM, as well.
- Avoid using a 3rd party libraries that can make changes in the environment, or conflict with another library version or other incompatible libraries.
- To prevent conflicts avoid exposing objects, with common names, to the global environment.
- Use unique names for all CSS class names and id selectors to prevent conflict.
- Library must be able to load in ES6 module, Common JS, Require JS, and Windows.
- When using JS, the library should load using either script tag, defer/async attributes or asynchronously.
- Make the library as small as possible.
- For further use, it is good to embed the library version inside the actual library.
This is how it will be.
Let’s see how we did in following the rules
Firebase will be the only 3rd party library that we will use, considering it should be already in use. Firebase will not override any object in global environment and only exposes one global object – “firebase”. There may be conflicts if a customer’s website already uses firebase for personal reasons.
- Will handle each case if website will load firebase library in its own way
We won’t use any polyfills, shims, and CSS normalizers. We will have a defined CSS and have a few fields exposed to the global environment.
- Use a unique prefix for all CSS selectors (id, class, and attribute)
- Use a unique prefix as well for all fields in the global environment
Our library should only work in the browser environment and use a browser feature that works with all browser versions. If not able to, use polyfills that will not expose itself to the global environment. Script in final stage should be in ES5.
Library is able to load using ES6 modules, script element, and Require JS
- Use UMD
Library should be minimized
- Use Uglify JS
Be able to debug library
- A production (minimized) version with the ability to debug the library
- Library version will be embedded within the library
Let’s see how integration will work for our library:
<!-- Step 1. Option 1 - to add by script tag --><!-- also you can remove 'async' and/or 'defer' attribute if want --> <script type="text/javascript" async defer src="//chat.com/chat.widget.min.js"></script> <!-- Step 1. Option 2 - to add by js in runtime --> <script> (function () { var lc = document.createElement('script'); lc.type = 'text/javascript'; lc.async = true; // can remove if need lc.defer = true; // can remove if need lc.src = '//chat.com/chat.widget.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(lc, s); })(); </script> <!-- Step 1. Option 3 - to add into website bundle by website developers --> <script type="text/javascript" async defer src="//website.bundle.min.js"></script> <!-- Step 2. For options 1 and 2 - use async init structure to start works with library --> <script> // (un)comment for debugging (enable)disable window.CFC_DEBUG = true; (function (f) { var g = window; if (g.cfc) f(); else (g.cfcAsyncInit ? g.cfcAsyncInit : g.cfcAsyncInit = []).push(f); })(function () { // widget is ready to init onWidgetReady(windows.cfc); </script> <!-- Step 2. For options 3 - use es6 modules for example to load chat library --> <script> import cfc from 'chat.widget'; // (un)comment for debugging (enable)disable cfc.CFC_DEBUG(true); // widget is ready to init onWidgetReady(cfc); </script> <!-- Step 3. Work with library --> <script> function onWidgetReady(cfc) { cfc.init({ autoLoadLibraries:true // optional (default:true) // in case if website owner has own way to load firebase library }); // login user to widget cfc.user .login({ brandId: 44, userId: 67146891 }) .then(function () { // widget if logged-in there }); } </script>
Let’s see how the library should be in high-level design:
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory() : typeof define === 'function' && define.amd ? define(factory) : (global['cfc'] = factory()); }(this, (function () { 'use strict'; var isDebugVar = false; function isDebug() { return (typeof CFC_DEBUG !== "undefined" && CFC_DEBUG) || isDebugVar; } function log() { if (isDebug()) { var args = Array.prototype.slice.call(arguments); args.unshift(window.console); Function.prototype.bind.apply(window.console.log, args)(); } } // ... var ChatManager = function () { // .... }(); var JsNS = 'cfc'; if (window[JsNS] === undefined) { // expose chat instance (singleton by design) var manager = ChatManager.inst?ChatManager.inst:(ChatManager.inst = new ChatManager()); var widget = { user: { login: manager.login.bind(manager), // ... others fields }, init: manager.init.bind(manager), manager: function() { return isDebug()?manager:null; }; CFC_DEBUG: function(v) { isDebugVar = v; } // ... others fields VERSION: "0.0.1" }; // run all async functions setTimeout(function() { var asyncInit = window[JsNS + 'AsyncInit']; if (asyncInit && asyncInit.length > 0) { for (var i = 0; i < asyncInit.length; i++) { try { asyncInit[i](); } catch (e) { error(e); } } asyncInit.length = 0; } }); return widget; } else { log('seems window.' + JsNS + ' already exposed'); } })));
Conclusion
As part of ui/ux modernization services, we offer suitable options to fit diverse requirements. When all the rules from library design are followed, the result is a JS library that is not only fast and light, but can also be integrated in many different ways.
Pros
- Compatible with all browsers
- Has minimal dependencies
- Doesn’t override the native environment
- Minimal size
- Many ways to integrate
- Ability to debug production build
Cons
- Very few fields are exposed to global
- Dependent on a Firebase library
References
Top articles
- Which OS Versions Should My App Support for Optimal Performance?
- 5 Key Technology Issues in Healthcare Industry
- Complete Guide to Microsoft Dataverse
- Key Success Factors for Technology Modernization
- Cloud Agnostic Applications: Why Do You Need It?
- Is Flutter ready for Enterprise mobile apps?
- 7 ERP Implementation Challenges and How To Overcome Them
- Understanding Technical Debt: Definition, Impact & Tips for Businesses
Related Articles