Insightful stories that revolve around technology, culture, and design

All blogs

Topics
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Implementing Iterators and Generators in JavaScript
Category Items

Implementing Iterators and Generators in JavaScript

JavaScript provides several ways of iterating over a collection, from simple 'for loops' to map() and filter(). Iterators and generators in JavaScript simplify code and save you from a lot of debugging and complexities.
5 min read

JavaScript provides several ways of iterating over a collection, from simple for loops to map() and filter(). Iterators and generators bring the concept of iteration directly into the core language and provide a mechanism for customizing the behaviour of ‘for...of loops’. Iterators and generators usually come as a secondary thought when writing code, but if you can take a few minutes to think about how to use them to simplify your code, they'll save you from a lot of debugging and complexities.

Iterators

When we have an array, we typically use the ‘for loop’ to iterate over its element.

Iterators and generators in JavaScript
  • The ‘for loop’ uses the variable 'i' to track the index of the ranks array
  • The value of 'i' increments each time the loop executes as long as the value of 'i' is less than the number of elements in the ranks array. But its complexity grows when you nest a loop inside another loop. 

ES6 introduced a new loop construct called ‘for...of’ to eliminate the standard loop’s complexity

Iterators and generators in JavaScript

The ‘for...of the loop’ can create a loop over any iterable object, not just an array.

Iterable values in JavaScript

The following values are iterable –

  • Arrays
  • Strings
  • Maps
  • Sets

Plain objects are not iterable and hence the 'for...of' uses the Symbol.iterator.

Symbol.iterator

The Symbol.iterator is a special-purpose symbol made especially for accessing an object's internal iterator. So, you could use it to retrieve a function that iterates over an array object, like so –

Iterators and generators in JavaScript
  • An iterator is an object that can access one item at a time from a collection while keeping track of its current position
  • It just requires that you have a method called next() to move to the next item to be a valid iterator
  • The result of next() is always an object with two properties –
  1. Value: The value in the iteration sequence
  2. Done:  true | false

Generators 

Generator functions once called, returns the Generator object, which holds the entire Generator iterable and can be iterated using next() method. Every next() call on the generator executes every line of code until it encounters the next yield and suspends its execution temporarily.

Generators are a special type of function in JavaScript that can pause and resume state. A Generator function returns an iterator, which can be used to stop the function in the middle, do something, and then resume it whenever. 

  • This generator object needs to be assigned to a variable to keep track of the subsequent next() methods called on itself.
  • If the generator is not assigned to a variable then it will always yield only till the first yield expression on every next().
  • A generator function is a function marked with the * and has at least one yield-statement in it.
  • Syntactically they are identified with a *, either function* X or function *X, — both mean the same thing

Fun Fact – async/await can be based on generators

Generator functions/yield and Async functions/await can both be used to write asynchronous code that 'waits', which means code that looks as if it was synchronous, even though it is asynchronous. ... An async function can be decomposed into a generator and promise implementation which is good to know stuff.

Generator functions are written using the function* syntax –

Iterators and generators in JavaScript
  • function*’ is a new 'keyword' for generator functions
  • yield is an operator with which a generator can pause itself

Additionally, generators can also receive input and send output via yield. In short, a generator appears to be a function but it behaves like an iterator.

A generator is a function that returns an object on which you can call next(). Every invocation of next() will return an object of shape —


{ 
    value: value,
    done: true  if the function code has finished, otherwise  false
}
  • The value property will contain the value
  • The done property is either true or false
  • When the done becomes true, the generator stops and won’t generate any more values


Here are some other common definitions of generators 

  • Generators are a special class of functions that simplify the task of writing iterators
  • A generator is a function that produces a sequence of results instead of a single value, i.e you generate ​a series of values
  • The value property will contain the value. The done property is either true or false. When the done becomes true, the generator stops and won’t generate any more values. The yield is a magical keyword that can do more things other than simply return a value and next() can do more things aside from retrieving the value.
  • A passing argument to next() - The argument passed to next() will be received by yield –
Iterators and generators in JavaScript

Output

Iterators and generators in JavaScript

Passing a function to yield

Apart from returning values, the yield can also call a function –

Iterators and generators in JavaScript

Output

Iterators and generators in JavaScript

Delegating to another generator or iterable using yield* expression

Iterators and generators in JavaScript

Output

Iterators and generators in JavaScript

Let’s see an example of fetching a single value from an API

As a Title –

Iterators and generators in JavaScript

Output

Iterators and generators in JavaScript
  • In this example; to fetch data from API, we have to install node-fetch using the command –
    '
    npm install node-fetch'
  • We then pass a generator to a function as a parameter. Let's call the function getTitle()
  • Now, in the function, we have to go through some steps to execute the generator
  • Initially, we will call the generator method. It returns an iterator(object)  which is caught in a variable 'iterator'
  • Now execute the iterator using 'next()' method
  • When the next method is called, the generator starts executing from this point. At line 4 the 'URL' is fetched
  • Fetch returns an object which is captured into variable 'iteration'
  • The object has 2 fields, viz. 'value' and 'done'
  • Here value is a promise and done is a boolean set to false
  • Iteration has a promise. Here we used our first yield
  • In our case, the getTitle() function has to resolve the promise. Since the yield doesn’t know how to resolve the promise.  So for resolving that promise we caught iteration.value into a variable 'promise'
  • Now we resolve the promise say into variable 'x'
  • We send the resolved 'x' to the iterator's next method. This x is a response which we collect into a variable 'response'. (line 5)
  • Now we have to extract the post from the response 
  • The response object now again has a promise which is to be resolved by our function. So we extract the object into variable 'anotherIterator' and the value of that object viz. promise into 'anotherPromise'
  • Now we resolve that promise in 'y' and pass it to the generator through the next() method
  • Here we used the second yield. So now we have resolved the response.json() and caught it into variable 'post'. (line 6)
  • Finally, we get our title through the object 'post'.Now we are going to extract our title from 'post.title'. Check the console for the title

Advantages of Generators

Lazy Evaluation 

This is an evaluation model that delays the evaluation of an expression until its value is needed. That is, if the value is not needed, it will not exist. It is calculated on demand.

Memory Efficient

A direct outcome of Lazy Evaluation is that generators are memory efficient.

The only values generated are those that are needed. With normal functions, all the values must be pre-generated and kept around case they need to be used later.

Conclusion

We have learned the following things about iterators and generators –

  • Iterator functions are a great and efficient way to do a lot of things in JavaScript. There are many other possible ways of using a generator function
  • Keeping iteration logic with the object it belongs to, is a good practice and which is the focus of ES6 features
  • The ability of a function to exchange data with the calling code during the execution is unique. And, surely, they are great for making iterable objects
  • As can be evidenced by the examples, generators are a really powerful tool that lets you have cleaner code - especially when it comes to any kind of asynchronous behaviour
Implementing Scroll Based Animations using React and GSAP
Category Items

Implementing Scroll Based Animations using React and GSAP

Complex animations should be implemented without compromising the fluidity and user experience of your website. In this blog, let's look at how to implement scroll based animations using React and GSAP.
5 min read

As computers are getting more powerful it is getting easier to achieve complex animations without compromising the fluidity and user experience. There are various JavaScript animation libraries available and most of them are pretty good. We at QED42 tried some of them and for the most part, we used GSAP which we think is kind of becoming an industry standard. GSAP is highly configurable and is just the right tool if you want to have scroll-based animations.

Smooth background change on scroll –

One thing that is eye-catching and easy to achieve, is smoothly changing background colour while scrolling. To implement this, we will change the wrapper component’s background colour as its child components move in and out of the viewport.

Source:qed42-js.netlify.app

Step 1: Create a context that will wrap our components and provide the necessary functionality

Scroll Based Animations using React and GSAP

Step 2:We will then import child components (named First, Second and Third), GSAP, and AnimationContext in our main app component. We are monitoring “currentBg” in the “useEffect” hook and whenever its value changes, the GSAP function gets executed. GSAP will change the background in 1 second which gives the fade-in effect.

Scroll Based Animations using React and GSAP

Step 3: To implement scroll-based triggers for the second and third components we will use GSAP.

The second component returns the following JSX, having a reference to wrapper element and text.

Scroll Based Animations using React and GSAP
Scroll Based Animations using React and GSAP

Next, we will create a GSAP timeline and use a scroll trigger to target an element, and set the start and endpoint for animation.

Scroll Based Animations using React and GSAP

ScrollTrigger has onEnter and onLeaveBack function which gets triggered when the trigger element passes through the scroll markers. That is where we change our background using context.

Note: The same effect can be achieved using gsap.to(), gsap.from() and other methods instead of gsap.timeline().

Scroll Based Animations using React and GSAP

The code for the above demo can be found at the following Github link.

What we learned from our hands-on experience is that animations should enforce, enhance the user behaviour and experience. The animations should not hinder action items in a way that it takes more time for users to interact with them. Therefore the background animation we saw above is very subtle and doesn’t cause any such hindrance.

Data portal mapping the future of climate migration
Category Items

Data portal mapping the future of climate migration

Delve into our collaborative effort with IOM, presenting a data-driven solution for climate resilience. Our visualizations, showcased at COP28, empower decision-makers to navigate climate-related displacement risks and foster positive change globally.
5 min read

As our planet changes, a complex challenge that has emerged is climate change-induced human migration. Millions are being forced to leave their homes, seeking safety and stability. Recognizing this critical issue, the United Nations (UN) leads coordinated efforts to support vulnerable communities.

The International Organization for Migration (IOM), the UN migration agency, promotes orderly and humane migration that benefits all. We had a great opportunity to join forces with IOM, contributing our expertise to a data-driven solution that sheds light and raises awareness on this complex issue.

IOM's commitment

International Organization for Migration
International Organization for Migration

Recognizing the urgency of climate change and its profound impact on human mobility, IOM has taken a leading role in addressing this global challenge. At the recent COP28 (28th United Nations Climate Change Conference) summit in Dubai, IOM aimed to foster international collaboration and drive ambitious action towards a low-emission and climate-resilient future.

As part of its strategic approach, IOM’s Global Data Institute (GDI) wanted a data-driven solution that leverages analytics to forecast where and when populations worldwide will be exposed to mobility-related climate hazards, such as floods, storms, and droughts so that decisions can be made based on evidence. This initiative helps the world understand climate-related displacement risk better and explore ideas to address it properly.

We designed and developed an interactive data visualization solution that IOM could use to present its research and approach at the COP28 summit.

The power of data and insights

We used the power of data and its ability to reveal hidden patterns and insights. Our solution processes large datasets and employs advanced analytics techniques to visually represent the complex dynamics of mobility-related climate hazards. It analyzes future trends and identifies emerging patterns based on state-of-the-art climatic, demographic, and economic datasets.

Take a look at GDI’s Climate Mobility Impacts dashboard on the Global Migration Data Portal. Users can explore and analyze how different climate hazards are expected to affect humans in the future.

Climate Mobility Dashboard
Climate Mobility Dashboard on the Global Migration Data Portal

This data-driven visualization approach provides a vital foundation to allocate resources and make informed policy decisions. International organizations can now interactively explore where and when climate hazard exposure, high population densities, and economic vulnerability will coincide in the future. It enables them to provide effective and targeted support for vulnerable populations.

This shift towards evidence-based decision-making ensures that aid and resources reach those who need it most, maximizing their impact and fostering a more resilient future for all.

Collaborative effort and action

This was a high-priority project for us with tight deadlines to meet. We had to design a portal that reads climate change data and presents it in interactive 2D and 3D maps, graphs, and bar charts.

This project demanded strong collaboration and dedication from a diverse team of experts. Our team of designers and JavaScript developers closely worked with the IOM team to research extensively, design, and develop a solution that meets current goals and is scalable for future goals.

team collaboration
Team collaboration

Agile methodologies were at the core of our approach, and we were able to adapt to emerging challenges and navigate complexities with remarkable efficiency. Our team’s commitment to agility proved invaluable, enabling us to successfully deliver the project on time and within budget.

Summing up

We will delve deeper into the design and development of our data visualization portal, offering insights into its features and unique capabilities in our case study. We believe that by sharing our knowledge and expertise, we can inspire further collaboration and advancement with data as a catalyst for positive change.

We are glad that we could help IOM present its data and approach visually to empower communities to navigate the complexities of climate change-induced migration. We look forward to working on more solutions that will positively impact lives worldwide. Talk to our experts to know more about how we can customize digital solutions that fit your needs.

Creating a custom CKEditor 5 plugin for Svelte
Category Items

Creating a custom CKEditor 5 plugin for Svelte

Uncover the secrets of crafting a Svelte plugin for CKEditor5 in our newest blog. Elevate your content creation with efficient Svelte component embedding. Explore the code and directory structure for insights and tips on building powerful CKEditor5 plugins.
5 min read

Svelte is an open-source JavaScript framework that helps to create interactive web pages. The Svelte plugin enables users to embed its components seamlessly into their content.

In this blog, we will consider how to create a custom plugin to integrate Svelte components into CKEditor 5, a powerful and extensible rich text editor that allows developers to tailor it to their specific needs.

To begin with, check out the directory structure that houses the essential components of the Svelte plugin.

Directory structure

Essential components of the Svelte plugin

1. package.json

Download the necessary CKEditor5 node modules for compiling custom plugins.


{

"name": "drupal-ckeditor5",

"version": "1.0.0",

"description": "Drupal CKEditor 5 integration",

"author": "",

"license": "GPL-2.0-or-later",

"scripts": {

"watch": "webpack --mode development --watch",

"build": "webpack"

},

"devDependencies": {

"@ckeditor/ckeditor5-dev-utils": "^30.0.0",

"ckeditor5": "~34.1.0",

"raw-loader": "^4.0.2",

"terser-webpack-plugin": "^5.2.0",

"webpack": "^5.51.1",

"webpack-cli": "^4.4.0"

},

"dependencies": {

"node": "^21.2.0"

}

}

2. webpack.config.js

The Webpack.config.js file is a script designed to automate the build process for CKEditor 5 plugins located in the js/ckeditor5_plugins directory. It employs the webpack module bundler to produce plugin files that are ready for production.

This configuration script is structured to bundle CKEditor 5 plugins individually, leveraging the capabilities of the getDirectories function. This function dynamically retrieves all subdirectories within the specified path (./js/ckeditor5_plugins). For each identified directory, a distinct Webpack configuration is generated and seamlessly integrated into the module.exports array.


const path = require("path");

const fs = require("fs");

const webpack = require("webpack");

const { styles, builds } = require("@ckeditor/ckeditor5-dev-utils");

const TerserPlugin = require("terser-webpack-plugin");

function getDirectories(srcpath) {

return fs

.readdirSync(srcpath)

.filter((item) => fs.statSync(path.join(srcpath, item)).isDirectory());

}

module.exports = [];

// Loop through every subdirectory in src, each a different plugin, and build

// each one in ./build.

getDirectories("./js/ckeditor5_plugins").forEach((dir) => {

const bc = {

mode: "production",

optimization: {

minimize: true,

minimizer: [

new TerserPlugin({

terserOptions: {

format: {

comments: false,

},

},

test: /\.js(\?.*)?$/i,

extractComments: false,

}),

],

moduleIds: "named",

},

entry: {

path: path.resolve(

__dirname,

"js/ckeditor5_plugins",

dir,

"src/index.js",

),

},

output: {

path: path.resolve(__dirname, "./js/build"),

filename: `${dir}.js`,

library: ["CKEditor5", dir],

libraryTarget: "umd",

libraryExport: "default",

},

plugins: [

// It is possible to require the ckeditor5-dll.manifest.json used in

// core/node_modules rather than having to install CKEditor 5 here.

// However, that requires knowing the location of that file relative to

// where your module code is located.

new webpack.DllReferencePlugin({

manifest: require("ckeditor5/build/ckeditor5-dll.manifest.json"), // eslint-disable-line global-require, import/no-unresolved

scope: "ckeditor5/src",

name: "CKEditor5.dll",

}),

],

module: {

rules: [{ test: /\.svg$/, use: "raw-loader" }],

},

};

module.exports.push(bc);

});

3. index.js

This file exports an object as the default export of the ‘index.js’ file. The object possesses a property named Svelte, and its value is the imported Svelte plugin. This is how CKEditor 5 will identify and uncover the Svelte plugin during the execution of the build process. The exported object functions as a map of available plugins that CKEditor 5 can utilize.


/**
* @file The build process always expects an index.js file. Anything exported
* here will be recognized by CKEditor 5 as an available plugin. Multiple
* plugins can be exported in this one file.
*
* I.e. this file's purpose is to make plugin(s) discoverable.
*/

import Svelte from './svelte';

export default {
 Svelte,
};

4. svelte.js

The Svelte class serves as the glue that integrates the editing and UI components of the plugin. It extends CKEditor's Plugin class and specifies its dependencies.


/**
* @file This is what CKEditor refers to as a master (glue) plugin. Its role is
* just to load the "editing" and "UI" components of this Plugin. Those
* components could be included in this file, but
*
* I.e, this file's purpose is to integrate all the separate parts of the plugin
* before it's made discoverable via index.js.
*/

// The contents of SvelteUI and Svelte editing could be included in this
// file, but it is recommended to separate these concerns in different files.
import SvelteEditing from './svelteediting';
import SvelteUI from './svelteui';
import { Plugin } from 'ckeditor5/src/core';

export default class Svelte extends Plugin {
 // Note that SvelteEditing and SvelteUI also extend `Plugin`, but these
 // are not seen as individual plugins by CKEditor 5. CKEditor 5 will only
 // discover the plugins explicitly exported in index.js.
 static get requires() {
   return [SvelteEditing, SvelteUI];
 }
}

The static get requires() method in this context specifies that the Svelte master plugin requires both SvelteEditing and SvelteUI. Although these components extend the Plugin class, CKEditor 5 will not consider them as individual plugins unless explicitly exported in index.js. This emphasizes the importance of explicit export to ensure that CKEditor 5 recognizes these components as plugins.

5. SvelteEditing - Handling the model

The SvelteEditing class defines the data model for the Svelte element and the converters for handling its conversion to and from DOM markup.


import { Plugin } from 'ckeditor5/src/core';
import { toWidget, toWidgetEditable } from 'ckeditor5/src/widget';
import { Widget } from 'ckeditor5/src/widget';
import InsertSvelteCommand from './insertsveltecommand';

/**
* CKEditor 5 plugins do not work directly with the DOM. They are defined as
* plugin-specific data models that are then converted to markup that
* is inserted in the DOM.
*
* This file has the logic for defining the Svelte model, and for how it is
* converted to standard DOM markup.
*/
export default class SvelteEditing extends Plugin {
 static get requires() {
   return [Widget];
 }

 init() {
   this._defineSchema();
   this._defineConverters();
   this.editor.commands.add(
     'insertSvelte',
     new InsertSvelteCommand(this.editor),
   );
 }
 _defineSchema() {
   // Schemas are registered via the central `editor` object.
   const schema = this.editor.model.schema;

  
   schema.register('Svelte', {
     // Behaves like a self-contained object (e.g. an image).
     isObject: true,
     // Allow in places where other blocks are allowed (e.g. directly in the root).
     allowWhere: '$block',
     allowContentOf: '$block',
     allowAttributes: ['src'],
   });
 }

 /**
  * Converters determine how CKEditor 5 models are converted into markup and
  * vice-versa.
  */
 _defineConverters() {
   // Converters are registered via the central editor object.
   const { conversion } = this.editor;

   // Upcast Converters: determine how existing HTML is interpreted by the
   // editor. These trigger when an editor instance loads.
   //

   conversion.for('upcast').elementToElement({
     model: 'Svelte',
     view: {
       name: 'iframe',
       classes: '-svelte-embed',
     },
   });
   conversion.for('dataDowncast').elementToElement({
     model: 'Svelte',
     view: (modelElement, { writer: viewWriter }) => {
       const src = modelElement.getAttribute('src') || modelElement.getAttribute('htmlAttributes')['attributes']['src'] || 'https://www.google.com';
       const iframe = viewWriter.createEditableElement('iframe', {
         class: '-svelte-embed',
         src: src,
       });
  
       return iframe;
     },
   });
   conversion.for('editingDowncast').elementToElement({
     model: 'Svelte',
     view: (modelElement, { writer: viewWriter }) => {
       const div = viewWriter.createEditableElement('iframe', {
         class: '-svelte-embed',
         src: modelElement.getAttribute('src') || modelElement.getAttribute('htmlAttributes')['attributes']['src'] || 'https://www.google.com',
       });
       return toWidgetEditable(div, viewWriter);
     },
   });
 }
}

init() {
 this._defineSchema();
 this._defineConverters();
 this.editor.commands.add(
 'insertSvelte',
 new InsertSvelteCommand(this.editor),
 );
 }

The init method initializes the plugin, calling two helper methods: _defineSchema and _defineConverters, to set up the schema and converters for the Svelte model. Additionally, it adds the 'insertSvelte' command to the editor, associating it with the InsertSvelteCommand class.


_defineSchema() {
 // Schemas are registered via the central `editor` object.
 const schema = this.editor.model.schema;

 schema.register('Svelte', {
 // Behaves like a self-contained object (e.g. an image).
 isObject: true,
 // Allow in places where other blocks are allowed (e.g. directly in the root).
 allowWhere: '$block',
 allowContentOf: '$block',
 allowAttributes: ['src'], 
 });
 }

The _defineSchema method sets up the schema for the Svelte model, registering the model type and specifying that it behaves like a self-contained object (isObject: true). It also defines where the model is allowed (allowWhere), where its content is allowed (allowContentOf), and the allowed attributes (allowAttributes), in this case, the 'src' attribute.


/**
 * Converters determine how CKEditor 5 models are converted into markup and
 * vice-versa.
 */
 _defineConverters() {
 // Converters are registered via the central editor object.
 const { conversion } = this.editor;

The _defineConverters method sets up the converters for the Svelte model, using the CKEditor conversion object to register converters for upcasting and downcasting.


// Upcast Converters: determine how existing HTML is interpreted by the
 // editor. These trigger when an editor instance loads.
 //
 conversion.for('upcast').elementToElement({
 model: 'Svelte',
 view: {
 name: 'iframe',
 classes: '-svelte-embed',
 },
 });

This section registers an upcast converter, determining how existing HTML is interpreted by the editor when it loads. It specifies that when encountering an HTML iframe element with the class '-svelte-embed,' it should be upcasted to a Svelte model element.


conversion.for('dataDowncast').elementToElement({
 model: 'Svelte',
 view: (modelElement, { writer: viewWriter }) => {
 const src = modelElement.getAttribute('src') || modelElement.getAttribute('htmlAttributes')['attributes']['src'] || 'https://www.google.com';
 const iframe = viewWriter.createEditableElement('iframe', {
 class: '-svelte-embed',
 src: src,
 });
 
 return iframe;
 },
 });

This section registers a downcast converter for data, defining how the Svelte model should be converted to DOM markup. If the model has a 'src' attribute, it uses that value; otherwise, it defaults to 'https://www.google.com'. It creates an iframe element with the specified class and source, which is then returned.


conversion.for('editingDowncast').elementToElement({
 model: 'Svelte',
 view: (modelElement, { writer: viewWriter }) => {
 const div = viewWriter.createEditableElement('iframe', {
 class: '-svelte-embed',
 src: modelElement.getAttribute('src') || modelElement.getAttribute('htmlAttributes')['attributes']['src'] || 'https://www.google.com',
 });
 return toWidgetEditable(div, viewWriter);
 },
 });
 }
}

This section registers an editing downcast converter, defining how the Svelte model should be converted to editable DOM markup. It creates an iframe element similar to the data downcast converter and then uses toWidgetEditable to wrap it as a widget in the editable view.

6. SvelteUI - User interface integration

The SvelteUI class registers the toolbar button for Svelte embeds, complete with an icon and dropdown functionality. It listens for user interactions and triggers the insertion of Svelte components into the editor.


/**
* @file registers the Svelte toolbar button and binds functionality to it.
*/

import { Plugin } from 'ckeditor5/src/core';
import { Collection } from 'ckeditor5/src/utils';
import icon from '../../../../icons/svelte.svg';
import { createDropdown, addListToDropdown , Model } from 'ckeditor5/src/ui';

export default class SvelteUI extends Plugin {
 init() {
   const editor = this.editor;

   editor.ui.componentFactory.add('Svelte', (locale) => {
     const dropdownView = createDropdown(locale);
     dropdownView.buttonView.set({
         icon,
     });

     const items = new Collection();
     const directories = editor.config.get('svelte_embed');

     for (const key in directories) {
       items.add({
         type: 'button',
         model: new Model({
             id: key,
             icon,
             src: directories[key],
             withText: true,
             label: key,
         }),
       });
     }

     addListToDropdown(dropdownView, items);

     // Inside SvelteUI class
     this.listenTo(dropdownView, 'execute', (eventInfo) => {
       let { src, label } = eventInfo.source;
       src += label + '/dist/index.html';
       editor.execute('insertSvelte', src);
     });
     return dropdownView;
 });
 }
}

editor.ui.componentFactory.add('Svelte', (locale) => {
 const dropdownView = createDropdown(locale);
 dropdownView.buttonView.set({
 icon,
 });

This section adds the Svelte component to the CKEditor UI, creating a dropdown view using the createDropdown function. It sets its button view with an icon and associates it with the specified locale.


const items = new Collection();
 const directories = editor.config.get('svelte_embed');

 for (const key in directories) {
 items.add({
 type: 'button',
 model: new Model({
 id: key,
 icon,
 src: directories[key],
 withText: true,
 label: key,
 }),
 });
 }

Here, a collection of items is created, representing the Svelte components to be displayed in the dropdown. It iterates through the directories obtained from the editor's configuration and adds each Svelte component as a button to the collection.


addListToDropdown(dropdownView, items);

This line adds the list of Svelte components to the previously created dropdown view using the addListToDropdown function.


// Inside SvelteUI class
 this.listenTo(dropdownView, 'execute', (eventInfo) => {
 let { src, label } = eventInfo.source;
 src += label + '/dist/index.html';
 editor.execute('insertSvelte', src);
 });

This section sets up an event listener using 'this.listenTo' to listen for the 'execute' event on the dropdown view. When an item is selected, it extracts the src and label from the selected item, modifies the src path, and then executes the 'insertSvelte' command on the editor with the modified src.


return dropdownView;
 });
 }

Finally, the init method returns the configured dropdown view, completing the initialization of the SvelteUI plugin.

7. insertsveltecommand

The heart of our plugin lies in the InsertSvelteCommand class. This command executes when the toolbar button for embedding Svelte components is pressed, utilizing CKEditor's model to insert the desired content into the editor.


/**
* @file defines InsertSveltecommand, which is executed when the Svelte
* toolbar button is pressed.
*/

import { Command } from 'ckeditor5/src/core';

export default class InsertSveltecommand extends Command {
 execute(src) {
   const { model } = this.editor;

   model.change((writer) => {
     model.insertContent(createSvelte(writer, src));
   });
 }
}

function createSvelte(writer, src) {
 const SVelte = writer.createElement('Svelte', {src: src});
 return SVelte;
}

export default class InsertSveltecommand extends Command {

This line declares the InsertSvelteCommand class, extending the CKEditor 5 Command class. This class encapsulates the logic executed when the toolbar button is pressed.


execute(src) {
    const { model } = this.editor;

    model.change((writer) => {
      model.insertContent(createSvelte(writer, src));
    });
  }

The execute method is part of the Command class and contains the logic to be executed when the command is invoked. It takes a src parameter, representing the source content to be inserted.

  • const { model } = this.editor;: Destructures the model property from the editor object. The editor object represents the CKEditor instance.
  • model.change((writer) => { ... });: Initiates a model change, ensuring that the changes are handled as a single transaction. The writer parameter provides methods for modifying the model.
  • model.insertContent(createSvelte(writer, src));: Inserts content into the model, calling the createSvelte function to generate the content to be inserted.

function createSvelte(writer, src) {
 const SVelte = writer.createElement('Svelte', {src: src});
 return SVelte;
}

The createSvelte function generates a CKEditor 5 model element representing the Svelte component. It uses the writer.createElement method to create an element with the specified name ('Svelte') and attributes (in this case, the src attribute). The created element is then returned.

The final look

After enabling the module in Drupal, you should see the screen below:

In this requirement, we are passing the folders inside a specific directory from Drupal to the CKEditor5 plugin. When you access any content-type page with full HTML, you will start seeing this:

On clicking the "View Source" option, the type casting of CKEditor5 will display the iframe tag with the src attribute set to the folder's index.html.

Conclusion

Creating a custom CKEditor 5 plugin to embed Svelte components adds a new dimension to content creation. The Svelte plugin seamlessly integrates into the editor, providing users with a streamlined experience for incorporating dynamic Svelte content.

If you want to know how to integrate CKEditor 5 in Drupal 9, you can find all the important steps here.

Happy editing with Svelte !

A comprehensive guide to deploying apps to TestFlight for seamless testing
Category Items

A comprehensive guide to deploying apps to TestFlight for seamless testing

Deploy iOS apps effortlessly using TestFlight. Learn its benefits, prerequisites, and a step-by-step guide for seamless deployment. Troubleshoot common issues for smooth testing.
5 min read

Introduction:

In the fast-paced world of app development, ensuring a smooth and bug-free user experience is paramount. One crucial step in achieving this is thorough testing, and TestFlight stands out as a reliable platform for iOS app testing. This blog will walk you through everything you need to know

about deploying apps to TestFlight, covering requirements, and benefits, and providing a step-by-step guide for a hassle-free deployment process.

Understanding TestFlight:

What is TestFlight?

TestFlight is Apple's official beta testing service that allows developers to distribute pre-release versions of their iOS apps to a selected group of testers for thorough testing before the app goes live on the App Store.

Benefits of Using TestFlight:

1. Early Feedback:

Enables developers to gather valuable feedback from a diverse group of testers before releasing the app to the general public.

2. Real-world Testing:

Provides the opportunity to test the app in real-world scenarios, uncovering potential issues that might not be apparent in a controlled environment.

3. Security and Privacy:

Ensures that the beta testing process is secure and respects the privacy of both developers and testers.

4. App Store Preview:

Allows developers to create a polished App Store page with screenshots, descriptions, and other information before the official release.

Requirements for Deploying Apps to TestFlight:

1. Apple Developer Account:

Ensure you have an active Apple Developer account. This is a prerequisite for accessing TestFlight.

2. Xcode:

Install the latest version of Xcode, Apple's integrated development environment (IDE).

3. Appropriate Certificates and Profiles:

Generate and configure necessary certificates and provisioning profiles in the Apple Developer Center to sign your app.

4. Testers' Apple IDs:

Collect Apple IDs from individuals who will be testing your app.

Step-by-Step Guide to Uploading Apps to TestFlight:

Step 1: Prepare Your App in Xcode

1. Launch Xcode:

Open Xcode and load your project.

2. Configure Build Settings:

In the "Project Navigator," select your project, go to "Build Settings," and set the build configuration to 'Release.' This optimizes your app for distribution.

3. Versioning:

Navigate to the 'General' tab and adjust the version number and build number. This step is crucial for tracking different versions of your app.

Step 2: Archive Your App

1. Generate Build:

From the top menu, select your target device as "Any iOS Device" to generate a build suitable for distribution.

2. Archive the Build:

Go to "Product" > "Archive" to Start the process of Archiving.

Archive is the process of preparing our app for uploading to the test flight, in-short it creates the compressed version of our app for the appropriate upload

Step 3: Distribute the App

1. Select the version of the app to Distribute

After the archive process is completed you will be redirected to the All Archives page, here select the archive you want to deploy to the Test flight,

After selecting the archive hit the Distribute button to start the process.

2. Configure the Options:

After hitting the Distribute App option you will be prompted with the option of how you want to deploy the app. You can select the option according to your needs and the purpose of the app, We will go with the Test flight option for this blog.

3. Start Uploading the Build

After selecting all the configuration options we can start the distribution by Pressing the Distribute button.

Step 4: Tester Onboarding

1. Access the Login Page:

Open your preferred web browser and navigate to App Store Connect.

2. Enter Apple Developer Credentials:

Log in using your Apple Developer account credentials. Ensure you have the necessary permissions for managing users and builds.

3. Access TestFlight Section:

Once logged in, you'll be on the App Store Connect dashboard. Navigate to the "My Apps" section and select your app. In the left sidebar, find and click on "TestFlight."

4. Select Internal or External Testing:

In the TestFlight section, choose either "Internal Testing" for your development team or "External Testing" for a wider audience.

5. Add Testers Using Apple IDs:

Click on the "+" (plus) icon to add testers. Enter the Apple IDs of the individuals you want to invite as testers. For internal testing, use the Apple IDs associated with your development team. For external testing, use the Apple IDs of external users.

6. Configure Tester Information:

Provide additional information about each tester, such as their first name, last name, and email address. This ensures that testers receive invitations with accurate information.

7. Define Tester Roles and Notifications:

Specify the tester's role (App Manager, Developer, Marketer, or Tester) and select the desired notification options. This step allows you to tailor the testing experience based on individual roles.

8. Send Invitations:

Once all details are filled, click "Invite" to send invitations to the added testers. Testers will receive an email invitation to join the testing group.

Step 5: Adding the Build for Testing

After the uploading is successful, the latest version will show up in the IOS Builds section

It will contain some Options for compliance for the app which which will ask for basic app details like if your app includes any kind of Authentication, if yes then which kind of it is?

As a final step, once you check all the compliance, the app will automatically be available to testers for testing purposes in the test flight App.

Testers will receive an E-mail notifying them that, a new build is available to test.

Step 6: Submit for Review(Optional For Testing)

1. Complete App Information:

Fill in all mandatory information on App Store Connect. Include details such as app description, keywords, and screenshots.

2. Submit for Beta App Review:

Submit your app for beta App Review. This ensures your app complies with Apple's guidelines.

Troubleshooting Deployment: Navigating Common Issues with TestFlight

Even with meticulous preparation, the world of app deployment can be unpredictable. Understanding and resolving common issues is an essential skill for any developer. Here, we delve into potential challenges that may arise during the TestFlight deployment process and provide detailed solutions.

1. Code Signing Issues:

Symptoms:

Error messages related to provisioning profiles or code signing during the build process.

Solution:

1. Revisit Apple Developer Center: Ensure that your certificates and provisioning profiles are correctly set up. Sometimes, a simple refresh or recreation of these in the Apple Developer Center can resolve issues.

2. Xcode Preferences: Check Xcode preferences to make sure the correct developer account is selected, and the associated provisioning profiles are up to date.

2. Build Rejections in App Store Connect:

Symptoms:

Your build is rejected during the beta App Review.

Solution:

1. Review Apple's Guidelines: Thoroughly review the App Store Review Guidelines to identify any violations.

2. Update Metadata: Make sure all app metadata, including descriptions, screenshots, and keywords, complies with App Store guidelines.

3. TestFlight Invitation Issues:

Symptoms:

Testers cannot access the app or face issues with TestFlight invitations.

Solution:

1. Verify Tester Email: Double-check that the email addresses of your testers are accurate, and they have accepted the TestFlight invitation.

2. Expired Builds: If testers are trying to access an older build, ensure that the build is still valid and hasn't expired.

4. Problems with Beta App Review:

Symptoms:

Delays or rejections during the beta App Review process.

Solution:

1. Communication with Apple: If you face delays or rejections, reach out to Apple through the Resolution Center in App Store Connect for clarification.

2. Adhere to Guidelines: Ensure your app follows all guidelines. Apple provides specific feedback during the review process, which can guide you in addressing issues.

5. Issues with TestFlight Distribution:

Symptoms:

Testers cannot download or install the app from TestFlight.

Solution:

1. Check Tester's Device: Ensure that the tester's device meets the minimum requirements for the app.

2. TestFlight App Version: Confirm that the TestFlight app on the tester's device is up to date.

6. Network or Connectivity Problems:

Symptoms:

Slow uploads, timeouts, or other network-related issues.

Solution:

1. Stable Internet Connection: Use a stable and high-speed internet connection to avoid interruptions during the upload process.

2. Retry: If issues persist, try uploading your build during non-peak hours or using a different network.

7. Issues with External Testers:

Symptoms:

External testers encountering difficulties joining or accessing the beta.

Solution:

1. Double-check Email Invitations: Ensure that the email invitations sent to external testers are accurate, and that they follow the provided instructions.

2. Resend Invitations: If testers are having trouble, consider revoking and reissuing invitations.

8. New Terms Agreement:

Symptoms:

A prompt for new terms or agreements in App Store Connect.

Solution:

1. Review and Accept: If prompted to agree to new terms or agreements in App Store Connect, carefully review the terms and conditions. Accept them to continue using the platform.

2. Clear Cache and Cookies: In some cases, clearing your browser's cache and cookies may resolve issues related to accepting new terms.

Conclusion:

Deploying apps to TestFlight is a crucial step in ensuring a successful app launch. By following this comprehensive guide, you'll be well-equipped to navigate the TestFlight deployment process, harness its benefits, and gather valuable feedback to refine your app before it reaches the wider audience on the App Store. Happy testing!

Here are some links to official Apple documentation for reference on How to deploy the apps to the test flight:

How to use the GraphQL useMutation hook of Apollo in ReactJS
Category Items

How to use the GraphQL useMutation hook of Apollo in ReactJS

GraphQL is a powerful query language that allows more flexibility and efficiency in data-driven applications compared to REST.In simple words, while querying with a RESTful API, we demand extra data that is not required at that moment. Here’s where GraphQL comes in handy for requesting only the required data from the server.
5 min read

GraphQL is a powerful query language that allows more flexibility and efficiency in data-driven applications compared to REST.

In simple words, while querying with a RESTful API, we demand extra data that is not required at that moment. Here’s where GraphQL comes in handy for requesting only the required data from the server.

Apollo is like the glue layer allowing us to use GraphQL in the front end (ReactJS in our example). We can make queries from React to our Graph of data in the server and retrieve data to present on the browser.

GraphQL


Prerequisites

  • Basic knowledge of Apollo Client library, GraphQL, and Schemas
  • Setup of GraphQL in NodeJS using express , express-graphql, and graphql
  • Setup of Apollo client and GraphQL in ReactJS using @apollo/client and graphql
  • MongoDB (mongodb and mongoose) or any other database  


Mutations and GraphiQL

Mutations allow us to mutate/change our data by performing CRUD operations. According to the official website of GraphQL, a mutation is defined as:

  • A GraphQL operation that creates, modifies, or destroys data.


We need to explicitly define mutations in the GraphQL server just like we define our RootQuery.

For example, a mutation schema definition to add an author and a book to our database would look something like this in NodeJS:


const Mutation = new GraphQLObjectType({
  name: "Mutation",
  fields: {
    addAuthor: {
      type: AuthorType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        age: { type: new GraphQLNonNull(GraphQLInt) },
      },
      resolve(parent, args) {
        const author = new Author({
          name: args.name,
          age: args.age,
        });
        return author.save();
      },
    },
    addBook: {
      type: BookType,
      args: {
        name: { type: new GraphQLNonNull(GraphQLString) },
        genre: { type: new GraphQLNonNull(GraphQLString) },
        authorId: { type: new GraphQLNonNull(GraphQLID) },
      },
      resolve(parent, args) {
      },
    },
  },
});

export const MyAppSchema = new GraphQLSchema({
  query: RootQuery,
  mutation: Mutation,
});


Here, the fields object contains all the mutation operations which we would like to perform. addAuthor is one such operation. AuthorType is the schema defined for the author with fields, such as ID, name, age, and books. args is the data we want to save in the database and ensure the correct datatypes.

Author is a mongoDB model, which is created using Mongoose. The resolve method is used to fetch/access, send, and mutate data in the database. The save() method is a Mongoose method that adds new author to the database. The same is the case of the addBook operation.

A mutation operation to add a book and an author sent from GraphiQL would look something like this:


mutation {
  addBook(name: "Old Path White Clouds", genre: "Biography", authorId: "646f026c0a60750fa3592095") {
    name
    genre
    authorId
  }
	addAuthor(name: "Thich Nhat Hanh", age:100){
    name
    age
  }
}


The query execution can be verified from the browser network tab with the name “graphql” (an example given at the end of this article).

GraphiQL is like a dummy frontend app that allows us to test our GraphQL server. The setup can be done from the main file or app file on our server. It is suggested specify whether we are using the production or development mode.


// setting up the graphql server
app.use(
  "/graphql",
  graphqlHTTP({
    schema: MyAppSchema, // defines schema of the graph and the object types
    graphiql: process.env.NODE_ENV === "development",
  })
);

The useMutation hook

Let’s discuss about the functionality of the useMutation() hook! It is used on the client end to send our mutation to the server.

Assuming that we have done the setup (explained later), we need to follow the steps below:

Step 0: Setting up Apollo Client in React application is done by installing @apollo/client, and creating a client object. It is a GraphQL client library using which we can make queries to the server like HTTP or Axios.


import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
import AddBook from "./components/AddBook";

// setup apollo client
const client = new ApolloClient({
  uri: "http://localhost:5000/graphql",
  cache: new InMemoryCache(),
});

function App() {
  return (
    <ApolloProvider client={client}>
      <div className="App">
        <AddBook />
      </div>
    </ApolloProvider>
  );
}

export default App;

The uri is the server endpoint to which requests are made. ApolloProvider wraps our React app and helps inject whatever data is received from the server to our frontend.


Step 1: Import gql template literal from @apollo/client library.


Step 2: Define the mutation as ADD_BOOK using gql in a separate file to ensure modularity in the project. For example, in the queries/index.js file, a mutation takes in data in the form of variables with a $ sign.


import { gql } from "@apollo/client";

export const ADD_BOOK = gql`
  mutation ($name: String!, $genre: String!, $authorId: ID!) {
    addBook(name: $name, genre: $genre, authorId: $authorId) {
      name
      id
      genre
      authorId
    }
  }
`;



Step 3: Import the useMutation()hook in the component mutation and request the above mutation to the server. This request is executed on an event of a button click to add a book. Here is where the useMutation() hook comes into picture.


import { useMutation } from "@apollo/client";
import { ADD_BOOK, GET_BOOKS } from "../queries";

const AddBook = () => {

  const [bookName, setBookName] = useState("");
  const [genre, setGenre] = useState("");
  const [authorId, setauthorId] = useState("");

  const [addBook] = useMutation(ADD_BOOK, {
    ignoreResults: false,
  });

  const submitForm = (e) => {
    e.preventDefault(); 
    addBook({
      variables: {
        name: bookName,
        authorId: authorId,
        genre: genre,
      },
      refetchQueries: [GET_BOOKS],
    });
  };

  return (
    <div>
      <form id="add-book" onSubmit={(e) => submitForm(e)}>
        {/* other form content */}
        <button>+</button>
      </form>
    </div>
  );
};

export default AddBook;

This hook takes the mutation ADD_BOOK that we just created as the first parameter and some options in an object, such as variables, and ignoreResults as the second parameter.

It also returns two elements, where the first is a mutate function (addBook), and the second is an object with details on the mutation - loading, error, and data.

It is important to make a call to this mutate function to perform the mutate operation because only calling the hook does not execute the mutation automatically (unlike GraphQL queries).

  • Variables can either be passed while calling the mutate function or while calling the useMutation hook.
  • The ignoreResults property, if set true, the mutation's data property is not updated with the mutation's result.
  • The refetchQueries property allows us the refetch certain queries once the mutation is complete.


Loading and error states are used to update the UI based on the mutation progress. They help display loading spinners or error messages while waiting for the mutation to complete or handling any encountered errors.

Finally, this is what our app and the mutation operation look like.

App & Mutation Operation using GraphQL useMutation

This is how our MongoDB database would look in the compass tool.

MongoDB in Compass


Difference between useQuery and useMutation

There are two differences between the hooks:

  • useQuery is a read-only operation used to fetch data, while useMutation is a write-only operation used to edit data and perform CRUD operations.
  • The useQuery hook runs automatically on component render, whereas the useMutation hook returns a mutate function which is needed to be triggered.


Below is an example of a query to fetch all authors and their details in GraphiQL (after we add them using the mutation specified above).

Fetch all authors in GraphiQL


Resources


Summary

The Apollo client introduces a remarkable tool: useMutation. This modern approach surpasses conventional methods. Additional libraries like apollo boost might not be required because @apollo/client comprehensive on its own. For hands on experience, Apollo offers tutorial challenges to practice with the useMutation hook before incorporating it into the project.

Notably, the graphql-http package has taken the place of express-graphql - something that can be explored. In a nutshell, the Apollo useMutation hook streamlines the process of handling GraphQL mutations, making the construction of resilient and engaging React applications simpler.

A Beginner's Guide to React Native
Category Items

A Beginner's Guide to React Native

Unlock the potential of React Native, a JavaScript-based framework for seamless Android and iOS app development. Master core components, CSS emulation, FlexBox layout, and custom fonts integration. Dive into the future of multi-platform app creation!
5 min read

React Native, a popular javascript-based framework built by Facebook in 2015, uses a Single Codebase applicable for developing apps on Android and iOS. The usage of this framework has increased developer productivity and minimized the learning requirements of other languages such as Objective C, Swift, Java Kotlin, etc. which are needed for Android/iOS app development.

Instead of using HTML and DOM as building blocks for the UI, React Native uses the native core components such as Button, View, Switch, etc. which you’ll find on iOS and Android. The philosophy is to learn once and write anywhere. Today, apps such as Instagram, Facebook, UberEats, Pinterest, Skype, and much more use React Native. You can also integrate this framework with your existing mobile applications!

Note: Written in JavaScript. Runs on React. Rendered with Native Code

Prerequisites

  1. JavaScript Fundamentals
  2. ReactJS
  3. CSS basics
  4. ECMAScript 6 (ES6)

Topics Covered

  1. How does React Native Work
  2. Setup
  3. Assumptions
  4. Adding CSS in React Native
  5. Understanding the React Native Core Components
  6. FlexBox in React Native
  7. Adding Custom Fonts to React Native
  8. Conclusion & Future Work

How does React Native Work: Views

In Mobile development, a View is the basic building block of UI: a small rectangular element on the screen that can be used to display text, images, or respond to user input. Even the smallest visual elements of an app, like a line of text or a button, are kinds of views.

A beginner's guide to React Native
Mobile App Development: It's all about Views!

According to the React Native site's introduction, you invoke the views with JavaScript using React components. React Native creates the corresponding Android and iOS views at runtime for those components. Because React Native components are backed by the same views as Android and iOS, React Native apps look, feel, and perform like any other app.

Setup

  1. Install expo-CLI globally using sudo npm install -g expo-cli
  2. Initialize project expo init my-first-react-native-project. This will create a basic project setup with all the initial files like package.json, etc.
  3. Go to the project directory in your favorite editor cd my-first-react-native-project/
  4. Run the expo-cli server using yarn start OR expo start
  5. In case it shows this error on the web browser - “Expo Developer Tools is disconnected from Expo CLI”, (EMFILE: too many open files) then install watchman: brew install watchman
  6. Download the expo client app on your mobile.
  7. Scan the QR code provided in the web browser, and you can view the Javascript running.

💡 As a result of the automatic fast reload feature of React Native, there is no need to restart manually after the completion of all these steps.

The app.js file contains the main component, which can be edited as per the project requirements.

Assumptions

  1. The code is written with respect to the React Functional components.
  2. All core components have to be initially imported from react-native in your code –

import { StyleSheet, Text, View, ScrollView, FlatList, Alert, TouchableWithoutFeedback, Keyboard } from 'react-native';

Adding CSS in React Native

  • React Native does not use CSS. It only emulates the idea of CSS. Therefore, we implement CSS using the style prop in the component, which refers to the CSS properties stored in an object.
  • A StyleSheet is an abstraction similar to CSS StyleSheets. This makes the code easier to understand and in case of any error in the style properties, it is shown at compile time rather than run time.

const styles = StyleSheet.create({
  container: {
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  boldText: {
    fontWeight: 'bold',
  },
});


  • The idea of inheritance of CSS properties does not work in the case of React Native. One needs to specify styles for each element. With one exception - Text widgets within Text widgets.

<Text>Name is <Text style={styles.boldText}>{name}</Text> !</Text>


Understanding the React Native Core Components

Core components are a set of essential, ready-to-use native components for quick and easy mobile application development

  • <View> is used to wrap other elements.
  • <Text> is used to display any textual content
  • You cannot write anything without the React Native core components. Not even HTML tags such as <p> can be used. This will result in an error.
  • In react native, <Button/> is a self closing tag. And you can send data as prop to this element. For example, <Button title='update state'/>. This will have some styles by default, but you cannot add styles property to a button in react native, hence it should be wrapped around a <View> tag to add styles to it.

<View style={styles.header}>
<Text style={styles.boldText}>Name is {name} </Text>
   <Text>Age is {age} </Text>
</View>
  • <TextInput> is used to take inputs from a user. It has the following props available -  
  1. placeholder prop
  2. multiline for text with multiple lines for form input
  3. onChange and onChangeText event listeners. onChange is useful when we need access to underlying native-event containing target, eventCount and text. While onChangeText only provides access to underlying text that changed
  4. keyboardType prop is useful to set the type of inputs that a user can provide. For instance a phone number will only contain numbers. Email address should follow a regex, etc.

            1. numeric

            2. email_address


<TextInput
   style={styles.input}
   placeholder='e.g. Vertika'
   onChangeText={(val) => setName(val)
   multiline>
</TextInput>
<TextInput 
   style={styles.input}
   placeholder='e.g. 20'
   onChangeText={(val) => setAge(val)}
   keyboardType={'numeric'}>
</TextInput>
  • Lists of data can be rendered using the JS method map(). Same as it is done in other JS frameworks. Similarly, you need to have a key for each list item. When the list or any content exceeds the page dimensions, you need to add <ScrollView>, wrapping up the content that should get scrolled. This is suitable for shorter lists.

const colors = [
  { name: 'red', key: 1 },
  { name: 'blue', key: 2 },
  { name: 'orange', key: 3 },
  { name: 'purple', key: 4 }
]

// In the return method

<ScrollView>
   {colors.map(color =>
      <Text key={color.key} style={colorStyles(color.name)}>{color.name}</Text>
   )}
</ScrollView>

// A separate method using CSS styles Dynamically
const colorStyles = (color) => {
  return {
    marginTop: 20,
    padding: 30,
    backgroundColor: color,
    color: "white"
  }
}
  • <FlatList/> is quite similar to ScrollView, except that it performs much better in terms of memory and processing time. Since it renders items lazily, when they are about to appear, and removes items that scroll way off-screen, therefore, it is better for longer lists. It automatically looks for the key property in each item in a list. Few mostly used properties of FlatList are as follows-        
  • data: pass the list/array that has to be rendered.                
  • renderItem: renders the items of the list mentioned in the data prop.
  • keyExtractor: used in case the name of the key is something other than a key.
  • numColumns: tells the number of columns in which the data should be rendered.

<FlatList
   numColumns={2}
   keyExtractor={item => item.id}
   data={colors}
   renderItem={({ item }) => ( // has to be named as "item"
     <Text style={colorStyles(item.name)}>{item.name}</Text>
   )}
/>
  • <TouchableOpacity> is used when you want an element to go opaque, or fade out a little bit when touched. You can also use the onPress() property for adding other functionalities.

<TouchableOpacity onPress={() => pressHandler(item.id)}>

   <Text style={colorStyles(item.name)}>{item.name}</Text>

</TouchableOpacity>
  • <Alert> is used to launch an alert dialog with the specified title and message. It can also have multiple buttons as option, providing different functionalities using the onPress() handler.

Alert.alert('OOPS!', 'Todo must be atleast 3 characters long.', [
  { text: 'Gotcha!', onPress: () => console.log('alert closed.') }
])
  • <TouchableWithoutFeedback> wraps a single component based on the requirement. When pressed, the functionality provided in the onPress() handler shall execute.

<TouchableWithoutFeedback
      onPress={() => Keyboard.dismiss()} 
<WrappedComponent/>
</TouchableWithoutFeedback>
  • The Keyboard module used in the above example listens to native events and handles them using methods such as dismiss().

FlexBox in React Native

  • A flex-box takes up the whole space available on the mobile screen. It can be set in styles using -

const styles = StyleSheet.create({
  container: { // outermost component
    flex: 1,
flexDirection:'row',
    justifyContent:'space-around',
alignItems:'stretch',
  }
})
  • The default behavior of flex is 'column'. You can set it as flexDirection:'row' for horizontal alignment of data.
  • Setting flexDirection without flex:1 takes only the required space and not the whole screen.
  • The justifyContent property enables us to set the item positions in a flexbox to the center, left (default), right, spread (space-around and space-between), etc.
  • The alignItems property sets the alignment of the flexbox items w.r.t to their position.
  • The space for the items is divided based on each element's flex properties, like flex:2 for one element, flex:3 for another, etc.

Adding Custom Fonts to React Native

To add custom fonts to your react-native project, the expo-font library can be used. With the help of this, fonts can be loaded from the web and then be used in React Native components. One can download the required fonts, copy them into the assets folder, and include them in the App.js or other JS file using the loadAsync() method.


import * as Font from 'expo-font';
const getFonts = () => { return Font.loadAsync({
  'nunito-regular': require('./assets/fonts/Nunito-Regular.ttf'),
  'nunito-bold': require('./assets/fonts/Nunito-Bold.ttf')
})}

Apps.js
loadAsync() is a highly efficient built-in method, that loads font from a static resource. Any string can be used as the font-family name. Secondly, you need to add these fonts to the styles of your components.


<Text style={{fontFamily: 'nunito-bold'}, fontSize: 20}>This is home screen</Text>

MyComponent.js
It is a good UI approach (for better optimization) to display components to the screen only when the assets such as custom fonts, icons, and logo images are completely loaded. Therefore, state management (the useState hook) is applicable here, along with another expo library called expo-app-loading which tells the expo-splash-screen to keep the screen visible while the AppLoading component is mounted. You can read more about it here.

Install the library using - expo install expo-app-loading


import AppLoading from 'expo-app-loading';
export default function App() {
  const [fontLoaded, setFontLoaded] = useState(false);
  if (fontLoaded) {
    return <MyComponent />
  }
  else {
    return (
      <AppLoading
        startAsync={getFonts}
        onFinish={() => setFontLoaded(true)}
        onError={(err) => console.log(err)}
      />);
  }

}

Apps.js

The AppLoading component makes a call to the getFonts() method, and when the fonts are finished loading, we call the setFontLoaded() method and set fontLoaded to true causing re-rendering. Thus, <MyComponent/> gets rendered.

Conclusion & Future Work

With React Native, programmers can create multi-platform applications with one technology - React, making the product cost-efficient. The Core components that we just discussed and many more, map directly to the platform’s native UI building blocks. This was just an introductory blog, and there is much more to learn in React Native, such as Navigation, Error handling, Images, Forms, etc. that shall be covered soon by us. Stay tuned for more updates! 
React Native, a popular javascript-based framework built by Facebook in 2015, uses a Single Codebase applicable for developing apps on Android and iOS. The usage of this framework has increased developer productivity and minimized the learning requirements of other languages such as Objective C, Swift, Java Kotlin, etc. which are needed for Android/iOS app development.

Styling your Next.js application
Category Items

Styling your Next.js application

Next.js is opinionated about how to organize your JavaScript code, but it's not opinionated about whether your styling should belong in JavaScript or not. In this blogpost learn how different styling methods can be used to style your Next.js application along with the pro's and con's of using these methods.
5 min read

Next.js is opinionated about how to organize your JavaScript code, but it's not opinionated about whether your styling should belong in JavaScript or not. As CSS-in-JS is becoming more and more popular due to some of its great advantages over css, there are people who outrightly hate the idea of CSS-in-JS. The **Differing Perspectives on CSS-in-JS** give a sneak peek into the over-opinionated world of what you should use.This blogpost though won't go into explaining this love and hate debate about css-in-js. The goal of this blogpost is to explain how we can use different styling methods to style our Next.js application and also mention the Pro's and Con's of using these methods.

Vanilla CSS/ Global CSS

Of course, you don't need to install anything to start to write your CSS styles. Just place your .css files inside the _app.js file, and you're ready to use it.

Styling your Next.js Application

Drawbacks of Vanilla CSS/ Global CSS

Anybody who has worked with using vanilla css knows how daunting and tedious working with Vanilla CSS can become. Some of the drawbacks are using Vanilla CSS are:

  1. Styling can be inconsistent due to Global Namespace as you can easily unintentionally target too many elements.
  2. Since styles are not scoped to the component, you'll have to be very cautious about deleting your code safely. 

CSS modules

Next.js has built in support for CSS modules. You can make use the [name].module.css file naming convention.Just rename your .css files with the .module.css suffix, and you're ready to import them inside of your JSX files!

Styling your Next.js Application

Since CSS Modules are locally scope they give you the ability to control your element styles in a more granular way as you don't need to worry about style collisions. Next.js takes care of optimising your CSS by minifying and code-splitting your css files. This is an ideal way of writing your CSS:

  1. You css in not dependent on JavaScript
  2. Zero-barrier to entry as you'll be writing Vanilla CSS
  3. Class-names are scoped

Drawbacks of CSS modules

  1. Nesting is not supported by default. You'll have to use PostCSS for that
  2. If you are sharing components across applications, using CSS modules may not best approach to go with
  3. Describing global styles, you have to use a syntax that does not belong to the CSS specification

Sass

Sass is one of the most popular preprocessors out there. It allows you to write more reusable, maintainable CSS. All need to do to get started is to run yarn add sass, rename your <file>.module.css files to <file>.module.scss, and you're ready to use SASS (or SCSS) syntaxes in your CSS Modules! You can configure your SASS options by editing the default next.config.js file as shown in the image.

Styling your Next.js Application

Sass makes it easy for you to automate repetitive task and create reusable code snippet with some of it's widely used features like:

  • Mixins: Create reusable code snippets
  • Variables: Allows you to to store information that you want to reuse throughout your stylesheet
  • Modules: Allows you to split your css files into more maintainable css files

Drawbacks of Sass

  1. Entry barrier: You need learn new features present in this preprocessor before using it
  2. Browser support: Some of the features aren't supported across browsers
  3. Although you can make use BEM methodology to name your classes. Naming can still be hard and you might need to look up a dictionary to name your classes

CSS-in-JS

CSS in JS is probably the most popular way of theming react applications right now. Almost every other day a new library pops-up. Some of the most popular libraries are: Styled components, EMOTION and Radium. There's also zero-runtime solutions like Vanilla-extract ,where CSS is extracted to CSS files at build-time.

CSS-in-JS lets you author CSS in JavaScript syntax. Let's look into 2 approaches of styling your application with CSS-in-JS:

Styled components

To use styled components we need to install babel-plugin-styled-components and styled-components. Next edit your _document.js file. Your should look somewhat identical to code shown in the below image.

Styling your Next.js Application

Next update your .babelrc file to include the next/babel preset and include the styled-components plugin, with server-side-rendering (ssr) enabled.

Styling your Next.js Application

We are done with all the configuration. Usage fairly simple. You just create a variable with the help of tagged-template-literals and then use it.

Styling your Next.js Application

Some of the advantages of using Styled components are:

  1. CSS rules are automatically vendor prefixed
  2. As with all the CSS-in-JS libraries you don't need worry about colocation
  3. Specificity is solved by auto-generated class names

You can learn more about it's official documentation.

Styled JSX

As easy as writing vanilla CSS, Next-js also has an inbuilt support for styled jsx. It allows you to write CSS using Javascript directly inside your components.

Styling your Next.js Application

Alternatively you can also make use of libraries like Chakra, ThemeUI or Tailwind to implement a component library and design system.

Conclusion

Each method has it's own pros and cons. After evaluating these pros and cons you will have to settle for one approach in the end. I think you are the best of judge of what styling methodology you should be using for your application. I for one have been making use of styled components and global stylesheets to theme my Next.js application.

Data Fetching and Next.js
Category Items

Data Fetching and Next.js

Next.js has evolved enormously over the past couple of years. From last year only it has introduced different data fetching techniques like Static Site Generation (SSG) and Incremental Static Regeneration(ISR) making it a default solution to build large scale web applications for most people.
5 min read

Next.js has evolved enormously over the past couple of years. From last year only it has introduced different data fetching techniques like Static Site Generation (SSG) and Incremental Static Regeneration(ISR) making it a default solution to build large scale web applications for most people.

In older days websites that were built were all really just a folder with HTML files that could be requested by a browser. After sometime as the web evolved, web severs came into use and how content was being served changed from static html files to generating the html at every user request. Then Javascript was invented and how content on a website would look and behave completely changed.

With the evolution of JavaScript and as the joke goes "JavaScript has become the main cause for making websites!" the approach of building web applications has changed. Rather than everything coupled together websites are built to be flexible, decoupled from the content and split up depending on what kind of data you need to serve to user.

In its journey of evolution, endless number of JS frameworks have been created which have played a key part in the success of Javascript. Next.js is also one of its creations. Build on top react, it's main goal is to help developers create production-ready applications with minimal need for configuration and boilerplate code.

To create production ready applications with ease Next.js offers several different data fetching strategies. This post will cover the basic understanding of different data rendering methods and how you can choose the right solution on a per-page basis to build a hybrid web app in Next.js.

SSG- Static site generation

In essence, SSG simply means that the HTML is generated at build-time and is reused in each request. So whenever someone visits the statically generated page, there is no need to fetch some tidbit from a database or wait for some library to render a template and the the user doesn't need to wait for the Javascript to download and execute before being able to see the initial content.

In Next.js you will use the next build command that will build the production application in your .next folder, you can deploy your application on hosting platform like netlify and vercel. Below image demonstrates the build process.

Data Fetching with nextjs

How to do it?

To build a static page Next.js provides us getStaticProps method:


export async function getStaticProps(context) {
  const data = await jsonapiClient(process.env.DRUPAL_API_URL, 'products');
  const resultNormalized = jsonapiNormalize(data);
  return {
    props: {
      resultNormalized,
    },
  }
}

ISR - Incremental static regeneration

Incremental static regeneration can help alleviate longer build times which becomes quite a headache when you consider rebuilding a very large scale e-commerce site. Traditionally in static site generation if we wanted to make any change, no matter how big or small, we would need to trigger a build that would entirely rebuild our site. This is where ISR comes into picture. This feature of Next.js aims at providing benefits of SSR with SSG by automatically re-rendering of statically exported pages without a full rebuild.

To understand how this works in practise, let's look into the implementation:

In getStaticProps which is used to build a page with static data you'll be able to return a revalidate property that tells Next.js that this page needs to be incrementally generated after given amount of time. The page defines what timeout is reasonable, this could be as low as 1 second.


export async function getStaticProps() {
  const data = await jsonapiClient(process.env.DRUPAL_API_URL, 'products');
  return {
    props: {
      data,
    },
revalidate: 30 //seconds
  }
}

Below image illustrates what happens when user requests a page using ISR fetching technique:

Data Fetching with nextjs
  • When user requests a page statically generated page is served.
  • After 30 seconds the first user to request the page will be served with a stale page.
  • Next.js generates a new version of the page in the background and updates the static file for future requests.
  • When a next request comes in the updated static file is served.

Note: ISR differs from server-rendering with Cache-Control headers. ISR is based on cache-control stale-while-revalidate http header. You can read more about it here.

SSR - Server side rendering

This is a pretty old technique. All of your processing is done on the server, every single time a request comes in. Every time a user makes a request the page is served on demand-talking to DB, API'S. This ensures that your user always sees the latest updated data.

Data Fetching with nextjs

How does Next.js do it?


export async function getStaticProps() {
  const data = await jsonapiClient(process.env.DRUPAL_API_URL, 'products');
  return {
    props: {
      data,
    },
revalidate: 30 //seconds
  }
}

CSR - Client Side rendering

CSR is the most common way of rendering these days. This is also how NextJS by default, renders the page, assuming you do not have a getServerSideProps method exported from your page. The following process unfolds when user requests a resource page :

  1. The browser requests the HTML file
  2. The browser requests the JS file.
  3. Performs Client-side rendering (CSR)

CSR is the easiest and fastest way for developers to build SPA(single page applications).

Data Fetching with nextjs

How to choose?

Generally you will be using combination of all the rendering techniques to build a real-world application. There is no one way high way solution. Each way of rendering data has it's own pros and cons. E.g: SSG might be Great for SEO and incredibly fast to serve but for larger applications you might want to consider using ISR as slow rebuild for large applications doesn't make it the best solution to serve static data. Similarly to address the cons of SSR you need might want to go with SSG. It just depends on the use case.

If you want to pick one of our experts brain to understand what suites best for your application ,you can contact us here!

Frontend build tool with PostCSS and Gulp
Category Items

Frontend build tool with PostCSS and Gulp

Frontend build tools can save a lot of valuable time and make a frontend developers life much easier. This blog talks about the frontend build tool we've created coupling PostCSS and Gulp which helps with frontend tasks such as compiling, linting & image optimization.
5 min read

Frontend build tools can save a lot of valuable time and make a frontend developers life much easier. They can do almost anything: download libraries, run tests, bundle packages, automatize tasks, and so much more. Lately, PostCSS and Gulp v4 are the talks of the town when it comes to the frontend side of web development. To ride this wave, we've built a frontend build tool coupling PostCSS and Gulp. This frontend build too essentially helps with frontend tasks such as compiling, linting & image optimization. Let's dive into how we built this frontend build tool! 

What is PostCSS?

PostCSS is a tool that gives access to a bunch of CSS related plugins to help improve the workflow and writing CSS. This enables a developer to start with a blank slate and select the additional plugins as required. If you are familiar with JavaScript tooling, then you can think of PostCSS as Babel for CSS.

What is Gulp?

Gulp is a JavaScript toolkit that helps in implementing multiple front end tasks during web development. Gulp is one of the most popular build tools that help with several tasks when it comes to web development.

Pre-requisites for using the tool

Ensure that you are using the latest LTS release of Node.js. Start by installing and running Node.js. 

To install the required packages, use


npm install

Now that the pre-requisites are in order, let’s take a look at some of the features of this tool categorized by the front-end tasks.

Features and functionalities of our frontend build tool

  • The tool uses PostCSS for managing variables and provides the needed browser support
  • With the extension .css, we can use SCSS/PostCSS syntax or it's features
  • The tool provides partial file support like SASS and nested CSS support like SASS
  • We included the RTL feature which converts LTR CSS to RTL for directional CSS
  • The tool provides the BEM classes feature too
  • You can define your Placeholder and @extend it, for example, src/css/utils/_placeholders.css. Here's how to use a placeholder - 
    src/css/components/navbar.css. For more details on how to use a placeholder visit - postcss-extend-rule. 
  • Our tool also facilitates PX to REM conversion. The default base for conversion is 1rem = 16px and the default output unit for <value>px is rem. For more information visit - postcss-pixels-to-rem
  • The tool provides media query breakpoints for mobile/iPad/desktop devices, for example - src/css/utils/_breakpoints.css. Here's how to use the media query breakpoints - src/css/components/header.css
  • The tool also comprises CleanCSS & Auto-prefixer

Script for CSS


gulp build:CSS

Script for JavaScript

Our frontend build tool uses ES6 for managing javascript with the 'Drupal.behaviors' code standard.


gulp build:CSS

Linting JS and CSS

Linting Javascript and CSS files along with fixing Linting errors & formatting.

Script to lint JS:


gulp lint:js

Script to fix JavaScript errors & format JS file:


gulp js-fix-prettier

Script to lint CSS:


gulp lint:css

Script to fix CSS linting errors:


gulp lint:css-fix

Image optimization

The images designated for the custom theme can be placed in the images/ folder. We have a gulp task to optimize images.


gulp images

Run multiple tasks

Run multiple tasks at one time. Like build/compile CSS, JS & optimise images.


npm run build

Continuous file watch:


npm run watch

OR


gulp watch:css

Conclusion 

Our frontend build tool makes frontend developers life easier by assisting in frontend tasks such as compiling, linting & image optimization. Check out our frontend build tool here - gulp-postcss.

Thank you for reading!

A quick guide to MongoDB Indexing
Category Items

A quick guide to MongoDB Indexing

Indexes support the efficient resolution of queries. Without indexes, MongoDB must scan every document of a collection to select those documents that match the query statement. Here's a quick guide to MongoDB indexing.
5 min read

Databases are the backbone of any modern application, be it mobile or web. The database helps store useful information so that it can be queried whenever needed. Let’s assume the database is like a book. It’s easy to read through and find certain things that you like if a book has fewer pages. But for a book with a large number of pages, it will take a substantial amount of time to revisit your favourite quotes, act, chapter, etc. To our rescue, we have pages like “Table of Contents”, “Index”  that help us traverse through pages easily. 

What is indexing?

Creating an index on a field creates another data structure that holds the field value and a pointer to the original record. In MongoDB whenever an index is created it is sorted in ascending or descending order. Given below is an example of how you will create an index on a User’s collection sorted by descending order of age.


> db.User.createIndex({age: -1})

Why should we use indexes?

Indexes help in the fast retrieval of documents(records). They can drastically reduce query time for large data sets. Without indexes MongoDB performs a collection scan i.e. MongoDB will scan every document and it can be expensive if your application doesn’t need every data or a good chunk.

Example: Fetching a single user’s details from user collection using an id or email that is not indexed. Mongo will scan every document every time whenever that particular query is executed.

Side Note

  • Command to get all indexes on a particular collection

> db.Contacts.getIndexes()
  • To run a diagnostic on a particular query

> db.contacts.explain ('executionStats').find()

Types of indexes in MongoDB

  • Single field index: MongoDB allows the creation of an index on a single field and for sort operations. For single-field indexes sort order defined doesn’t matter because MongoDB can traverse the index in both directions.

db.contacts.createIndex({email: 1})
  • Compound Index: MongoDB supports indexes on multiple fields for instance {email: 1, age: -1}. The order of fields in a compound key has significance. Let’s execute it and see what it actually means. On execution of the following query:

> db.User.explain ('executionStats').find().sort({name: 1, age: -1})

Under queryPlanner > winningPlan > inputStage > stage the value is “IXSCAN” which means an indexed scan was the winning plan and not the whole collection was searched.  Let’s now execute the same query but now with fields reversed.


> db.User.explain ('executionStats').find().sort({age: -1, name:1})

And the result was as following:

MongoDB Indexes

Here in the “winning plan”, we can see the whole collection was scanned.

Note: For a query to use a compound index for a sort, the specified sort direction for all keys in the cursor.sort() document must match the index key pattern or match the inverse of the index key pattern. This means for the above example both {email: -1, age: 1} and {email: 1, age -1} is supported but not {email: 1, age: 1} or {email: -1, age: -1}.
 

  • Partial Index: Partial indexes are somewhat like compound indexes and sparse indexes but with a little more power. For partial indexes, we mention conditions or expressions based on which documents are indexed. However, for the sparse index, if the indexed field is missing then that document is skipped from the indexing process i.e sparse indexes only check for the existence of a key.

Query to create Partial Index:


> db.User.createIndex ({name: 1, age: -1}, {partialFilterExpression: {score: {$gt: 33} }})
  • Query Coverage: For the index created above MongoDB will not use the index if the result is an incomplete set. For example: On executing query mentioned below.

> db.User.explain ('executionStats'). find({name: 'Mary', score: {$gt: 32} })

In the execution statistics mentioned below, the winning plan was “COLLSCAN” because we created a partial index for indexing documents having a “score” above 33, and our query is searching for a value above 32 therefore MongoDB rejects index scan and performs collection scan to avoid the incomplete result.

MongoDB Indexes
  • TTL(Time-to-live) index: In the case of collections where documents should be deleted after a period of time. TTL index is the best way to go about it. TTL index works on date fields. To create a TTL index 2 parameters are necessary, firstly a date field and secondly the amount of time after which indexed documents will be automatically removed. Query to create a TTL index.

db.User.createIndex( {"createdAt": 1}, {expireAfterSeconds: 3600} )
  • Text Indexes: Text indexes are used to index 

db.Books.createIndex ({name: 'text''})

To search a collection having a text-based index, the query looks something like this:

MongoDB Indexes

Word Exclusion: MongoDB also has the feature to exclude words from the search query. Simply add subtract before the word that is to be excluded.

For example: 


> db.Books.find({$text:  {$search: 'age -number'} }). pretty () 

Result: The document having the name property “Age is just a number” is excluded. 

MongoDB Indexes

Using indexes carefully

MongoDB Indexes

Now I get it. If we index all our fields it will make our application fast. Not true!!!

Indexes come at a cost, it takes substantial time when creating new documents when a collection have various indexes set on it. All the existing indexes will be re-calibrated every time a document is added. Also one should not use indexes if a query returns a major chunk of your collection because it adds an extra step of going through indexed fields and fetching corresponding documents.

Conclusion

Above mentioned indexes are some of the widely used indexing methods. Indexes can be introduced and used at any point of time in the development cycle. So, play with indexes create them, drop them and find out their execution status to choose what best works for your application.

Happy Coding!!!

Decoupling Drupal Commerce with Next.js
Category Items

Decoupling Drupal Commerce with Next.js

This blog post will demonstrate how we can leverage Drupal's JSON API to create a Decoupled application with Next.js as our rendering layer and Drupal Commerce as the content hub.
5 min read

Hoping you all are familiar with the term Headless/Decoupled Drupal, I won't be diving into the details. However, if you'd want to know more about what Headless Drupal is, you are just one click away from finding the secrets of the Headless world! Today we will demonstrate how Drupal's JSON API can be leveraged to create a Decoupled application with Next.js as our rendering layer and Drupal Commerce as the content hub.

As a starter here is what we will be covering in this blog post:

  1. Setting up your Drupal commerce site
  2. Setting up the Next.js site and fetching data from the Drupal site
  3. Working with the data (Create pages dynamically)

Note: We will follow this up and cover checkout functionality in another blog post.Here is a link to the starter package. This is still a work in progress but good to get you started 

Set up your Drupal Commerce site

Drupal Commerce provides you with a starter project. This will make your content work easier as it provides you with some preconfigured products. Alternatively, you can set up your site from scratch by following the Commerce documentation here.


composer create-project drupalcommerce/demo-project demo-commerce --stability dev --no-interaction

Once you are done installing the site, you need to do a few more things:

  • Enable JSON API, JSON:API Resources, JSON API Hypermedia, and Commerce API module. You can also add the Simple OAuth module for authentication
  • Add JSON resources cross bundle module and enable it or you can also create a custom resource for the listing of all products. (Note: The cross bundle module is not compatible with JSON API Extras.)
  • Allow read and write permissions for JSON API
  • Edit your services.yml file to allow cross-origin headers


Fetching data from the Drupal site

Here is a link to the starter package. This is still a work in progress but good to get you started. Go through the readme file to check how to set up your Next.js site.

This is how your homepage should look like:

Decoupling Drupal Commerce with Next.js

Let me walk you through the folder structure and the code:

Decoupling Drupal Commerce with Next.js
  1. Pages folder: As the name suggests this is where you are going to be adding your pages. Each page is associated with a route based on its file name. Next.js also supports dynamic page routing.
  2. Components folder: This is where we will abstract our functionality into different components.
  3. api.js file: This is where all the magic happens. This page contains all the code responsible for manipulating the API data.
  4. next.config.js: This file is not included in the browser build and is used by the server. You can read more about it here.
  5. .env file: This is where all your environment variables will be stored.

Creating pages

Here are some of the Next.js functions we will be using to fetch data at the build and run time.

  • getStaticProps (Static Generation): Fetches data at build time
  • getStaticPaths (Static Generation): Specifies dynamic routes to pre-render pages based on data
  • getServerSideProps (Server-side Rendering): Fetches data on each request
  • getInitialProps: Enables server-side rendering in a page and allows you to do initial data population, which means sending the page with the data already populated from the server. getInitialProps will disable Automatic Static Optimization For the initial page load, getInitialProps will run on the server only. getInitialProps will then run on the client when navigating to a different route via the next/link component or by using next/router. However, if getInitialProps is used in a custom _app.js, and the page being navigated to implements getServerSideProps, then getInitialProps will run on the server.

Creating Static Routes

As mentioned above each page in Next.js is associated with a route based on its file name. So the index.js file inside the pages folder will work as our homepage.

Decoupling Drupal Commerce with Next.js

In getStaticProps, we are using our JSON:API Client (you can find the relevant code in the api.js file) to fetch the relevant data and filter it as per our needs. getStaticProps function returns the data as props to our default component which is further manipulated to get the desired result.

Creating dynamic routes

Next.js also supports dynamic page routing. In Next.js you can add brackets to a page ([param]) to create a dynamic route. Inside the product folder in the pages folder, we have created a file [id].js which will be responsible for creating our product detail pages.

Decoupling Drupal Commerce with Next.js

Here, getStaticPaths fetches the products id's for us and passes them as params to getStaticProps and get static props to pass the product data as props to the default product component.

Note that we are using the product id here. Because with JSON:API in Drupal you can't filter by path alias due to technical limitations. JSON:API filters translate to entity queries on field values; because Drupal path aliases aren't fields you can't use the filter query param to look up articles by their alias.

So to overcome this limitation we can use modules like:

  • Decoupled Router: Which provides a new endpoint where a client can query a path for any possible JSON:API resources.
  • Fieldable Path: Which provides a new entity field (and thus queryable via the filter query param) that is designed to mimic the entity's path (with Pathauto support). We will cover this in another blog post.

Another thing to note here is that for better a developer experience in development mode, getStaticProps and getStaticPaths run on every request otherwise they only run at build time.

Conclusion

This is it! You have set up a Decoupled site with a simple listing page and detail pages. As this is still a work in progress. If you face any difficulties please add your queries in the comments section below and I will be happy to answer!

Building interactive maps with Leaflet and React
Category Items

Building interactive maps with Leaflet and React

In this article, we are going to develop a simple interactive map that shows the state and union territory wise Covid-19 cases in India using Leaflet JS and React.
5 min read

Having a map is a vital tool for engaging with audiences for many online businesses. Interactive maps allow direct interaction with your site visitors. It also responds and anticipates the needs of your users/customers. In this article, we are going to develop a simple interactive map that shows the state and union territory wise Covid-19 cases in India using Leaflet JS and React. 

Let’s get started.

What is Leaflet? 

Leaflet is an open-source JavaScript library for developing interactive maps. Weighing just about 39 KB of JS, it has all the mapping features most developers ever need. It’s a lightweight, open-source mapping library that utilizes OpenStreetMap. It has more than 30k stars on GitHub

Installing React-Leaflet 

We need to install react-leaflet in our React project. Please follow the steps provided in the following guide

Once the react-leaflet is added to our package-JSON file, we need to add a few more things to view our map correctly. 

Now we need to add some CSS to our file to start using the map straight away. You can do that either by including the CSS link tag in your head, or you can simply copy-paste the CSS from the file below directly into your project(index.html):


<link
     rel="stylesheet"
     href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"             
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
     crossorigin=""

We need to set the width and height of the .leaflet-container that the map renders itself into, otherwise it won’t be visible because the div will have a height of 0px:


.leaflet-container {
 width: 100%;
 height: 100vh;
}

Once this is done we are ready to get started. The below code displays the code required to render the Leaflet map in the React App. Here we have imported the MapContainer from react-leaflet (along with some other packages which we’ll use in later stages) and we’ll return it from our App component.

MapContainer component: It initializes the map. We set the center position of the map by adding latitude and longitude along with the default zoom level of the map.

TileLayer component: A tile layer is a set of web-accessible tiles that reside on a server. We have added the URL and attribution to our TileLayer component.


import {React, useState} from 'react'
import './App.css'
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import { Icon } from 'leaflet'
import covidData from './data.json'
import icon1 from './images/covid19.svg'

function App() {
  return (
     <MapContainer center = { [ 20.593683, 78.962883 ] }
         zoom = { 5 }
         scrollWheelZoom = { true }
     >
     <TileLayer
attribution='© <a href="https://stadiamaps.com/">Stadia Maps</a>, © <a href="https://openmaptiles.org/">OpenMapTiles</a> © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
       url = 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png'
     />
</MapContainer>
)
}

Adding Map Markers

To display the data in our map as markers, first, we need the data source. I have created the data source in a JSON file that contains all the state-wise(and union territories as well) covid details in India. We will load this data locally from a JSON file, but to get an idea how our data looks like, here’s an example:


{
   "Id": 1,
   "Location": "Maharashtra",
   "Total_Cases": "36,39,855",
   "New_Cases_Per_Day": "61,695",
   "Cases_Per_1_Million_People": "31,877",
   "Deaths": "59,153",
   "Latitude": 19.601194,
   "Longitude": 75.552979
 },
 {
   "Id": 2,
   "Location": "Kerala",
   "Total_Cases": "11,97,301",
   "New_Cases_Per_Day": "8,126",
   "Cases_Per_1_Million_People": "34,574",
   "Deaths": "4,856",
   "Latitude": 10.850516,
   "Longitude": 76.27108
 }

Once the data source is created, we can map through the data inside our MapContainer component, which returns a marker component for each of the state-wise data related to covid. A Marker component is used to display clickable/draggable icons on the map. It requires a position property to display the render location on the map. It takes an array of [ latitude, longitude ], the same as the center property in MapContainer.

In addition to this, we have initialized a useState hook with null. Inside the click eventHandler we will set the activeCovid when the user clicks on the marker. It will show the information to the user about the particular selected stated in a map popup. 


function App() {
  const [ activeCovid, setActiveCovid ] = useState( null );
  return (
     <MapContainer center = { [ 20.593683, 78.962883 ] } zoom = { 5 }
{ covidData.map(eachData => (
         <Marker
           key={eachData.Id}
           position= {[eachData.Latitude, eachData.Longitude]}
           eventHandlers={{
             click: () => {
               setActiveCovid(eachData)
             }
           }}
         />
       ))}
     </MapContainer>
)
}

Adding Map Popups

Since we are tracking which state or union territory the user has clicked on, if the data is available for that state or union territory then we can display the Popup. The Popup component will display a white rounded rectangle shape that can be closed, and much like a Marker component, we need to give a position so it will know where to render on the map. Inside the popup, we can pass our HTML to show the total cases, new cases (1-day *), cases per 1 million people for the selected state or union territory. 

There is an onClose property/event on the Popup component. When a user closes the popup it will help us track and update the setActiveCovid state hook accordingly.


<MapContainer center = { [ 20.593683, 78.962883 ] } zoom = { 5 } >
{ activeCovid && (
        <Popup
         position={ [ activeCovid.Latitude, activeCovid.Longitude ] }
         onClose={()=>{
            setActiveCovid(null)
          }}
        >
          <div>
           <h1>{ activeCovid.Location }</h1>
           <p>Total cases:  { activeCovid.Total_Cases }</p>
            <p>New cases (1 day*):  { activeCovid.New_Cases_Per_Day }</p\>
       <p>Cases per 1 million people:  { activeCovid.Cases_Per_1_Million_People }</p>
           <p>Deaths:  { activeCovid.Deaths }</p>
         </div>
       </Popup>
     )}

 </MapContainer>


Displaying the Custom Marker Icons

Now we can add our custom icons as well. It is very easy in the leaflet to add our custom icons. First, we need to import the icon from the leaflet itself. With that, we can create a new icon instance by providing the URL location of the image along with its size.


import { Icon } from 'leaflet'
const covidIcon = new Icon({
 iconUrl: icon1,
 iconSize: [25, 25]
})

The Marker component provides an optional property icon that can be set to the covidIcon variable that we created. Once the custom marker is added our website will look like this.

Final Website

Interactive maps with Leaflet and React

Conclusion

In this article, we have learned that React-Leaflet is a great open-source free mapping library alternative to Google Maps and MapBox. It is an extremely easy-to-use package and is extremely lightweight (39KB of JS). We have also demonstrated a small use case where we have displayed the state or union territory wise Covid-19 cases in India using Leaflet-react. Feel free to play around with this code to develop your own interactive maps. And share your experience with us in the comment section below! 

To know more about how to implement navigation with Leaflet Maps click here

Navigation with Leaflet Maps
Category Items

Navigation with Leaflet Maps

This blog will show how we can make use of the leaflet maps to show the route between a source and a destination. For achieving this we will be using the Leaflet Routing Machine module.
5 min read

Today, we are going to see how we can add routing to our leaflet maps. This blog will show how we can make use of the leaflet maps to show the route between a source and a destination. For achieving this we will be using the Leaflet Routing Machine module.

What is Leaflet?

Leaflet is an open-source JavaScript library for developing interactive maps. Weighing just about 39 KB of JS, it has all the mapping features most developers ever need. It’s a lightweight, open-source mapping library that utilizes OpenStreetMap. It has more than 30k stars on GitHub

What is Leaflet Routing Machine?

Leaflet Routing Machine is an easy, flexible, and extensible way to add routing to a Leaflet map. Using the default is just a few lines of code to add fully functional routing, but you can still customize almost every aspect of the user interface and interactions.

Key features of  Leaflet Routing Machine include:

  • Standard Leaflet control, with Leaflet, look and feel
  • Routing from start to destination, with the possibility of ‘via’ points
  • Add, edit and remove waypoints through both address input and using the map
  • Multiple language support
  • OSRM - Open Source Routing Engine is built-in 

Installation:

We need to install react-leaflet in our React project. Please follow the steps provided in the following guide. Once the react-leaflet is added to our package-JSON file, we need to add a few more things to view our map correctly. 

Now we need to add some CSS to our file to start using the map straight away. You can do that either by including the CSS link tag in your head, or you can simply copy-paste the CSS from the file below directly into your project(index.html):


<link
 rel="stylesheet"
href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"             
integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
     crossorigin=""
>

We need to set the width and height of the .leaflet-container that the map renders itself into, otherwise it won’t be visible because the div will have a height of 0px:


.leaflet-container {
 width: 100%;
 height: 100vh;
}

Apart from the react-leaflet, we need to install a leaflet-routing-machine package as well:


npm install --save leaflet-routing-machine

And afterwards, we need to import the below files in our routing component:

Import library's CSS file:


import "leaflet-routing-machine/dist/leaflet-routing-machine.css";

Import library's JS file:


import "leaflet-routing-machine";

So for our current use case, we will create a simple leaflet map and add routing to it. Users will be able to enter source city and destination city, based on which it will show the routes between the two locations. Just for our understanding, our website will look like below:

Navigation with Leaflet Maps

Now let’s get started

First, we’ll render the leaflet map in our React app. We can do this by importing 2 components from the react-leaflet:


import { MapContainer, TileLayer } from "react-leaflet";

Once the import is done now we’ll display the map with the help of the imported component.


<MapContainer center={position} zoom={6} style={{height: '100%', width: '100%', position: 'relative'}}>  
<TileLayer
 attribution='© <a href="https://stadiamaps.com/">Stadia Maps</>, © <a href="https://openmaptiles.org/">OpenMapTiles</a> © <a > contributors'
 url = 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png'
/>
</MapContainer>

This will render the leaflet map in our React app. So the basic functionality of the imported components are:

MapContainer component: The Map component requires that we set a center position, which is an array containing latitude and longitude, along with the default zoom level of the map.

TileLayer component: A tile layer is a set of web-accessible tiles that reside on a server. We have added the URL and attribution to our TileLayer component.

Once the Map is loaded in our React app now we add two Autocomplete dropdown menu’s in our React app and we will create a data source containing data of all the major cities around the world as below:

Data Source sample


[
    {
        "city": "Tokyo", 
        "city_ascii": "Tokyo", 
        "lat": "35.6897", 
        "lng": "139.6922", 
        "country": "Japan", 
        "iso2": "JP", 
        "iso3": "JPN", 
        "admin_name": "Tōkyō", 
        "capital": "primary", 
        "population": "37977000", 
        "id": "1392685764"
    }, 
    {
        "city": "Delhi", 
        "city_ascii": "Delhi", 
        "lat": "28.66", 
        "lng": "77.23", 
        "country": "India", 
        "iso2": "IN", 
        "iso3": "IND", 
        "admin_name": "Delhi", 
        "capital": "admin", 
        "population": "29617000", 
        "id": "1356872604"
    }
]

Dropdowns


<Autocomplete
id="source-city"
options={cities}
onChange={(event, value) => setSourceCity(value)}         
classes={classes}
getOptionLabel={(option) => `${option.city}, ${option.country}`}
style={{ width: 300, paddingBottom: '5%' }}
renderInput={(params) => <TextField {...params} color="secondary" label="Source" variant="outlined" InputLabelProps={{style: { color: 'white' },}}
/>
<Autocomplete
id="destination-city"
options={cities}
onChange={(event, value) => setDestinationCity(value)}         
classes={classes}
getOptionLabel={(option) => `${option.city}, ${option.country}`}
style={{ width: 300, paddingBottom: '5%' }}
renderInput={(params) => <TextField {...params} color="secondary" label="Source" variant="outlined" InputLabelProps={{style: { color: 'white' },}}
/>

In the above dropdowns, we are saving the value of our selected city using setSourceCity & setDestinationCity using theuseState on the onChange event in the dropdown. Once we get our selected city we will pass these values to the Routing Component as props.


<MapContainer center={position} zoom={6} style={{height: '100%', width: '100%', position: 'relative'}}>   
<TileLayer attribution='© <a href="https://stadiamaps.com/">Stadia Maps</a>, © <a href="https://openmaptiles.org/">OpenMapTiles</a> © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
url = 'https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png'
/>
<Routing sourceCity={sourceCity} destinationCity={destinationCity}/>       
</MapContainer>


Now in our Routing.js

Now in our Routing component, we will destructure the props to sourceCity and destinationCity.


const Routing = ({ sourceCity, destinationCity }) => {
// Some Code...
}

Now we will use the useMap hook which will provide the Leaflet Map instance in any descendant of the MapContainer.


const map = useMap();

Then we will instantiate a new routing control with the waypoints. We will initialize the waypoints with the latitude and longitude coming from the de-structured props sourceCity and destinationCity. Then we will add that to our map.


const routingControl = L.Routing.control({
         waypoints: [
           L.latLng( parseFloat(sourceCity.lat), parseFloat(sourceCity.lng) ),
           L.latLng( parseFloat(destinationCity.lat), parseFloat(destinationCity.lng) )
         ],
 }).addTo(map);

That’s it we have added the route to our map. It’s that simple. So our final website will look like below:

Final Website

Navigation with Leaflet Maps

Conclusion

In this blog, we have learned how to add routing to our leaflet maps using the leaflet-routing-machine module. Also, we have developed a small use case where we can select the source city and destination city from the dropdown and it will show the route between the two cities. You can access the complete code of this tutorial here. If you would like to know more about how to build interactive maps with Leaflet and React click here.

What's new with Next.js 11?
Category Items

What's new with Next.js 11?

Vercel, the company behind the React and JavaScript framework NEXT.JS, announced the release of Next.js 11 yesterday at its Next.js Conf. Let's dive into some of the important new features that Next.js has introduced in their latest Next.js 11 release.
5 min read

Next.js is a result of the combined work of 1600 community developers,  industry partners like Facebook and the core Next.js team. Its philosophy has always been to make DX (Developer Experience) as good as UX (User Experience). And this really shows with all the different features Next.js has introduced over the last few years making it the first hybrid framework to succeed at scale. Providing features to build both static and dynamic websites with blazing fast speed.

Whether you’re starting with a single static page or deploying a dynamic site with billions of pages, NEXT.JS is the hybrid framework that meets you where you are and grows with you.

–  Vercel CEO Guillermo Rauch

Vercel, the company behind the React and JavaScript framework Next.js, announced the release of Next.js 11 yesterday at its Next.js Conf

NEXT.JS 11

Source - Nextjs.org

Let's dive into some of the important new features that Next.js has introduced in their latest Next.js 11 release.

Next.js Live (Preview Release)

This is basically Figma for developers. This feature will let you code in the browser, with your team, in real-time. This is probably the most important feature and will simplify team collaboration to a large extent.

NEXT.JS 11

Source - sdtimes.com

How this works – You need to be a part of the team which has deployed the application to the Vercel platform. If you are a part of the team all you need to do to get started here is to simply change your URL from .app to .live and Hola! This feature does not support collaborative editing inside the editor yet, which means that it will only update the changes in the UI and not in the editor.

Conformance for Next.js

Conformance is a methodology used by Google internally from their experience over the years of building web, to codify best practices in a way that they are automated and enforceable. Google's web platform team has now begun open-sourcing their system for different frameworks.

In simpler words, it's basically a linter that does something more than just code analysis. You can simply type npx next lint after upgrading to Next.js 11 to get started.

You can read more about conformance here.

Next.js Image Enhancements

Images are essential to performance for any website and one of the most commonly used elements on the web. Since version 10.0.0, Next.js has a built-in Image Component and Automatic Image Optimisation. In Next.js 11, the image component has been upgraded to support:

  1. Automatic size detection for local Images
  2. Image blur-up placeholders for static and as well as dynamic images

Next.js Script Component 

Next.js 11 comes with a new component named next/script which will let you prioritise the loading of 3rd party scripts. In practice all you need to do is define the strategy property on the Next script tag and Next.js will take care of optimally loading it as per the strategy value. E.g:


<Script
  src="<https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.map>"
  strategy="beforeInteractive" // other values - (lazyOnload, afterInteractive)
/>

Automatic Font Optimisation

In Next.js the CSS of fonts are automatically inlined at build time hence eliminating the round trip of fetching font declarations which as per Next.js will improve the FCP and LCP by as much as five seconds. Next.js also uses a pre-connect tag by default, establishes a connection with the underlying font files even faster. It supports both Google fonts and Adobe kit.

Create React App Migration

This feature is currently experimental, considering the issues encountered while migrating a React application to Next.js. To convert your React app into Next.js you simply need to use the following command


npx @next/codemod cra-to-next

This will transform your React app into the Next.js app while taking the React app compatibility into consideration. 

Webpack 5

With Next.js 11, there is no need for any custom added configuration to make webpack 5 work for your Next.js app. Webpack 5 is now enabled by default, removing the manual overhead of adding the configuration in your next.config.js. Here is the upgrade documentation for webpack 5 you can follow. 

Conclusion

Next.js 11 includes significantly faster starts and changes, real-time feedback, instantaneous live collaboration and significant image optimisation enhancements. Learn more about Next.js 11 updates here. You can also check out the upgrade guide for upgrading your Next.js app from version 10 to 11.

How to Cache your Node.js application with Redis
Category Items

How to Cache your Node.js application with Redis

This article is a simple introduction to Redis and how to cache your Node.js application with Redis. Here, you will learn the utilization of Redis for caching through an example and how you can use it to improve your application speed and performance.
5 min read

This article is a simple introduction to Redis and how to cache your Node.js application with Redis. Here, you will learn the utilization of Redis for caching through an example and how you can use it to improve your application speed and performance. Before that, let us understand what caching & Redis is.

What is caching?

Caching is the process of storing copies of files in a cache or a temporary storage location so that they can be accessed more quickly. The goal of caching is speeding up data access operations better than a database or remote server could allow. It is ideal in the case of expensive (in time) operations. As a back-end developer, our task is to complete the clients’ requests as fast as possible. Sometimes, queries require several operations like retrieving data from a database, performing calculations, retrieving additional data from other services, etc., that drag our performance down.

With caching, we can process the data once, store it in a cache and then retrieve it later directly from the cache without doing all those expensive operations. We would then periodically update the cache so that users can see updated information.

What is Redis?

Redis is an open-source (BSD licensed), in-memory data structure store used as a database, cache, and message broker. You can think of it as a No-SQL database, which stores data as a key-value pair in the system memory. If needed, Redis supports disk-persistent data storage too.

Redis is best in situations that require data to be retrieved and delivered to the client in the least amount of time. Now that you have an understanding of what Caching and Redis are, let’s build a basic project that implements caching using Redis.

Install Redis:

If you are an OSX user, you can install Redis using the command below. For other platforms, please follow the guide on https://redis.io/download.


brew install redis

Create a new directory for the application by running the following command on the terminal:


mkdir redis-nade-cache
         cd redis-nade-cache

Initialize the directory to create a package.json file by running


npm init -y

After running the above command, you should have a package.json file in the redis-nade-cache directory. Now, we are going to request a json placeholder API https://jsonplaceholder.typicode.com.

Start by creating a simple Express server in index.js:


const app = express();
const port = 4000;
app.get('/data/:searchtext', (req, res) => {
   const searchtext = req.params.searchtext;
    const recipe = await axios.get(`https://jsonplaceholder.typicode.com/${searchtext}`);
    client.setex(searchtext, 1000, JSON.stringify(recipe.data));
     return res.status(200).send({
           error: false,
           message: `Data for ${searchtext} from the server`,
           data: recipe.data
         });
   }) 
app.listen(port, () => {
 console.log(`Server running on port ${port}`);
});


Now, start the server by running node index.js and open postman to request the photos endpoint.

First Request-Response:

How to Cache your Node.js application with Redis

Second Request-Response:

How to Cache your Node.js application with Redis

Take note of the time from the above images. The first request took 5.38 seconds while the second one took 4.89 seconds. We will improve this by implementing caching using Redis. Let’s implement Redis in the above example.

Install Express, Redis, and node-fetch npm modules with the below command:


npm install node-fetch express redis

Now that we have successfully set up Redis, the next step is to use it in our application to improve it by reducing the turnaround time of request and response. Now we will add the following changes to the index.js file.

First, we create a Redis client and link it with the local Redis instance using the default Redis port (6379)


const client = redis.createClient(6379);

Then, in the /recipe route handler, we will try to get the appropriate matching data to serve the request by checking for the key in our Redis store. If found, the result is served to the requesting client from our cache and there is no need to make the server request anymore.


client.get(searchtext, async (err, data) => {
     if (!data) {
        return res.status(200).send({
         error: false,
         message: `Data for ${searchtext} from the cache`,
         data: JSON.parse(data)
       })
     }

If the key is not found in our Redis store, a request is made to the server and once the response is available, we store the result using a unique key in the Redis store:


const recipe = await axios.get(`https://jsonplaceholder.typicode.com/${searchtext}`);
     client.setex(searchtext, 1020, JSON.stringify(recipe.data));

Hence, subsequent requests to the same endpoint with the same parameter will always be fetched from the cache, so long the cached data has not expired. The setex method of the Redis client is used to set the key to holding a string value in the store for a particular number of seconds which in this case is 1020 (17 minutes).

Final code of index.js


const express = require('express');
const axios = require('axios');
const redis = require('redis');
const app = express();
const port = 4000;
const client = redis.createClient(6379);
client.on("error", (error) => {
 console.error(error);
});
app.get('/data/:searchtext', (req, res) => {
 try {
   const searchtext = req.params.searchtext;
   client.get(searchtext, async (err, data) => {
     if (data) {
        return res.status(200).send({
         error: false,
         message: `Data for ${searchtext} from the cache`,
         data: JSON.parse(data)
       })
     } else { 
         const recipe = await axios.get(`https://jsonplaceholder.typicode.com/${searchtext}`);
         client.setex(searchtext, 1020, JSON.stringify(recipe.data));
         return res.status(200).send({
           error: false,
           message: `Data for ${searchtext} from the server`,
           data: recipe.data
         });
     }
   }) 
 } catch (error) {
     console.log(error)
 }
});
app.listen(port, () => {
 console.log(`Server running on port ${port}`);
});


Now, let’s test the application after implementing cache. Open postman and request the same endpoint as before.

How to Cache your Node.js application with Redis

If the key is not found in the cache, the request is sent to the server which takes 566 minutes to complete. Since the key didn’t exist in the cache before, it is now saved in the cache and subsequent requests with the same data will be fetched from the cache which makes it faster, and also reduces the load on the server. Below is the response time after the cache:

How to Cache your Node.js application with Redis

As we can see above, it took a blazing 48 milliseconds for the request to be completed because it was fetched from the cache.

Conclusion

Redis is a powerful in-memory data store that can be used in our applications. It’s very simple to save and get data without much overhead. Refer to https://www.npmjs.com/package/redis for more use cases and refer to https://redis.io/commands for more Redis commands.

React Suspense - A Quick Introduction
Category Items

React Suspense - A Quick Introduction

React 16.6 has added a Suspense component that allows you to 'wait' for some code to load and declaratively specify a loading state (like a spinner) while you’re waiting. Here's a quick introduction to what React Suspense is.
5 min read

React 16.6 has added a <Suspense> component that allows you to “wait” for some code to load and declaratively specify a loading state (like a spinner) while you’re waiting. React Suspense was pitched as an improvement to the developer experience when dealing with asynchronous data fetching within React apps. This is a huge deal because everyone who is building dynamic web applications knows that this is still one of the major pain points and one of the things that bring huge boilerplates with it.

Let’s see what suspense is and how it’s used. 

What is React Suspense?

Suspense is a component that wraps the custom components and enables them to communicate to React that they’re waiting for some data to load before the component is rendered.

It is important to note that Suspense is neither a data-fetching library like react-async nor is it a way to manage a state like Redux. It simply prevents your components from rendering to the DOM until some asynchronous operation (i.e., a network request) is completed. 


<Suspense fallback={<p>loading..</p>}>
    <StudentList />
</Suspense>

Here, the StudentList component is wrapped with a Suspense component that has a fallback prop. This means that if StudentList is waiting for some asynchronous operation, such as getting the lists of students from an API, React will render <p>loading..</p> to the DOM instead. The StudentList component is rendered only after the promises and API’s are resolved.

This can also be written as –


if(loading({
Return <p>loading…</p>
}
return <StudentList />

Let’s look at some scenarios related to the same –


What If StudentList was the one who triggered the operation? 

In that case, we would have to move the loading check from the parent component to the StudentList component. 


What if there are more components apart from StudentList, each triggering their async requests?

This would mean that each child component would have to manage their loading states independently, and that would make it tricky to organize the data loading operations in a way that doesn’t lead to a janky UX.

Take a look at the example below –


<Suspense fallback={<p>loading...></p>}>
    <StudentlList />
    <TeacherList />
    <BranchList />
</Suspense>


Here's an example that I have implemented on the CodeSandbox: 
https://codesandbox.io/s/suspense-example-rvi1e

How to use Suspense to display a loader?

React comes with the support of lazy components. Instead of handling the dynamic import Promise, React.lazy allows you to use the dynamic component like a statically imported one. React.lazy() is a new function in React that allows you to load react components lazily through code splitting without help from any additional libraries.

Lazy loading is the technique of rendering only needed or critical user interface items first, then quietly unrolling the non-critical items later. It is now fully integrated into the core React library itself. We formerly used react-loadable to achieve this but now we have react.lazy() in the React core.

Suspense is a component required by the lazy function basically used to wrap lazy components. Multiple lazy components can be wrapped with it. It takes a fallback property that accepts the react elements you want to render as the lazy component which is being loaded.


const StudentList = React.lazy(() => import(‘./components/StudentList’));
const TeacherList = React.lazy(() => import(‘./components/TeacherList’));
const BranchList = React.lazy(() => import(‘./components/BranchList’))’
<Suspense fallback = {<p>loading…</p>}>
    <StudentList />
    <TeacherList />
    <BranchList />
</Suspense>


React.lazy takes a function that will execute the dynamic import. It returns a component that will run this function during its first rendering.

The resulting promise status is used by Suspense:

  • to render the fallback during the chunk download (pending Promise)
  • to render the real StudentList component once downloaded (resolved Promise)

Conclusion

Suspense helps us to coordinate asynchronous resources with our loader component rendering. We have already used it in the above example.

We have seen how to get started using the lazy and suspense components provided by React to load components lazily. The above example is a basic one as compared to the numerous possibilities these new features bring.

This was a quick introduction to “React.Suspense” and how it is used with code splitting. Stay tuned for our upcoming blog on ‘What Suspense will become in the future.

A hint – It will be used for much more than just code splitting!


Here's a glimpse of the React team’s vision for what the future of React might look like, including some never before seen prototypes.


Developing Multilingual sites with Headless CMS - Strapi
Category Items

Developing Multilingual sites with Headless CMS - Strapi

Strapi is one of the most popular open-source Headless CMS right now. In this blog post, I will give you a walkthrough on how to create multilingual websites with the Headless CMS - Strapi.
5 min read

Over 4 billion people are using the internet today. It is used by different businesses (like e-commerce, social media, etc.) for attracting more customers. Every business is going online (especially during this pandemic) with the notion of gaining the upper hand on the competitors with different marketing strategies.

One of such marketing strategies is Multilingual websites to attract more customers, by catering to different demographics.

What is a Multilingual website?

As the name suggests, a multilingual website is a website that has content in more than one language. 

Benefits of Multilingual websites

  • English is not the only language:

English might be the most widely spoken language globally but there are other well-known popular languages like Mandarin, Spanish, etc. A website that displays its content in more than one language is reachable to more people comparatively.

The most common languages used on the internet as of January 2020, by the share of internet users are - 

Developing Multilingual sites with Headless CMS - Strapi


Source: Statista
 

  • Everyone loves their native language:

Human beings have a special regard for their native language even though they can speak and read English well enough and it is a normal thing. Similarly, if the website displays content in the region’s native language, it will connect with people easily. It also shows that your business truly cares about the non-English speaking customers and their language is just as important.

The most spoken languages worldwide in 2021:

Developing Multilingual sites with Headless CMS - Strapi


Source: Statista
 

  • More customers mean more sales:

As you develop your website in multiple languages, your target audience is getting bigger. There will be an increase in the number of customers and as a result, the sales will also increase. 

  • A different approach from competitors: 

There is a famous quote by Dr Seuss:

Why fit in when you were born to stand out?

No matter what your business is, it faces market saturation and huge competition these days. A multilingual website is a great way to stand out from your competitors.

  • Search engines: 

On Google, there are a lot of languages to choose from. If you have a multilingual website then search engines will show your website’s result in the user’s preferred language.

Now the question arises of how can we make our website multilingual. There are a lot of options available in the market but today we are going to discuss how we can achieve this with Strapi (Headless CMS).

What is a Headless CMS?

A Headless CMS is a back-end-only content management system where the content is built from the ground without its head, which is the front-end. It makes the content accessible via API for display on any device.

What is Strapi - Open Headless CMS?

Strapi is one of the most popular open-source Headless CMS right now. It has more than 35k stars on Github with growing popularity each day. Strapi enables content-rich experiences to be created, managed, and exposed to any digital product, channel, or device. It gives a very user-friendly experience that you can stack up with any technology. Please check out their Github repo below:

https://github.com/strapi/strapi

The current scope of Multilingual website with Strapi

There is no plugin available for making a website Multilingual. As per the below road map, the plugin is still in the testing stage and according to the recent update, it will either be launched at the end of Q1-2021 or might get postponed by a few weeks into Q2-2021.

Developing Multilingual sites with Headless CMS - Strapi

Roadmap link: 19-content-internationalization-ce-ee-v3

Building a multilingual website with Strapi

  • Building the back-end with Strapi:

Firstly we need to do the local setup for Strapi. Please follow the instructions mentioned in the guide: Installing from CLI 

URL: http://localhost:1337/admin/

  • Creating the collections in Strapi:

Step 1 - On the left panel of the dashboard, click content-types builder, it will give you an option to create new collections. Click on it and name the collection as ‘article’ and click continue.

Developing Multilingual sites with Headless CMS - Strapi

Step 2 - It will now ask you to add fields for the collections. Since we are building a multilingual website, we will specify each field name with the language code as a suffix in the field name just to differentiate between each language.

For eg: If we need to specify the field ‘title’ for the English language then the field name can be mentioned as  ‘title_en’. In the same way, we can mention the Hindi language as ‘title_hi’.

Likewise, we need to add the title and description along with the language code as the suffix for the field name. After adding all the fields, click Save. 

Here is the list of all field names created for this multilingual website:

Field Name

Field type

title_en

text

title_hi

text

title_fr

text

title_de

text

description_en

rich-text

description_hi

rich-text

description_fr

rich-text

description_de

rich-text

image

media

We are using 4 languages here English(en), Hindi(hi), French(fr) and German(de). Article collection will have the following fields:
 

Developing Multilingual sites with Headless CMS - Strapi


 Step 3 - Now, let’s add a few articles to the created collections. In the left side panel, under collection types, click on ‘Articles’ and then click on add New Articles.

Developing Multilingual sites with Headless CMS - Strapi

Now as per the defined language suffix, type the content in its specific language field as shown below:

Title_en: Munnar Travel Blog – Tourist Places

Title_hi: मुन्नार यात्रा ब्लॉग - पर्यटक स्थल

Title_fr: Munnar Travel Blog - Lieux touristiques

Title_de: Munnar Reiseblog - Touristenorte

The same needs to be done for Description fields as well. This will help in distinguishing different languages to display in the front-end by using their field name. We can easily differentiate with the help of the language code provided in the Suffix. 

The full approach for adding an article is below:

Developing Multilingual sites with Headless CMS - Strapi

Step 4 - After adding a few articles, we need to provide the ‘Article’ collection permission to send the API requests to fetch the data from Strapi. For That Click on settings > Roles > Public.

Developing Multilingual sites with Headless CMS - Strapi

Scroll down to the Permissions and check the find and findone boxes. Save it and we have successfully given permissions to our Article collections. 

Developing Multilingual sites with Headless CMS - Strapi
  • Building the front-end using React
  1. Fetching data from Strapi.

App.js:


useEffect(()=>{
   //Fetching Data from Strapi
   const getPosts = async () => {
     const response = await fetch('http://localhost:1337/articles')
     const data = await response.json();
     console.log('useFFect Data:', data)
     setPosts(data)
   }
  getPosts()
},[])

Here we are fetching all the data from the Strapi using the URL ‘http://localhost:1337/articles’ and then feeding the JSON data to our header component as props.
 

index.js(Header Component):

The data from App.js is used here as props to display the content in multiple languages.


const Header = (data) => {
....
} 

Now, we’ll handle the multiple languages by creating a Header for our blog.


<div className="main-header">
<div className="header-container">
 <div className="title">
     <h2> BlogPost </h2>
 </div>
 <div className="languages-wrapper">
  <FormControl component="fieldset">
<RadioGroup aria-label="language" name="language" value={value} onChange={handleChange} row>
      <FormControlLabel value="English" control={<Radio />} label="eng" />
      <FormControlLabel value="Hindi" control={<Radio />} label="hi" />
      <FormControlLabel value="French" control={<Radio />} label="fr"/>
      <FormControlLabel value="German" control={<Radio />} label="de"/>
   </RadioGroup>
  </FormControl>
 </div>
</div>
</div>

Developing Multilingual sites with Headless CMS - Strapi

Here, we have created 4 radio buttons for each language (English, Hindi, French, and German) and on selecting any one of the languages, our content will display in that particular language.


   const [value, setValue] = useState('English')
   const handleChange = (event) => {
     setValue(event.target.value);
     console.log('Values:', event.target.value)
   }

Here, the default selected language will be English and if the user selects any other language our function handleChange will get invoked and the useState hook will set the new value for that language code. With this, the page will start showing the content in that language.

Final Website

Developing Multilingual sites with Headless CMS - Strapi

Conclusion

In this tutorial, we have learned how to build multilingual sites with Strapi. We first started by developing our back-end with Strapi and added collections with articles, then we went on to build our front-end with React to display content fetched from Strapi. You can access the complete code of this tutorial on Github.

Github Links

Backend: multilingual-with-strapi-backend.git

Frontend: multilingua-with-strapi-frontend.git

Higher-Ed
Healthcare
Non-Profits
DXP
Podcast
BizTech
Open Source
Events
Quality Engineering
Design Process
JavaScript
AI & ML
Drupal
Culture