Our Global Presence

Canada
57 Sherway St,
Stoney Creek, ON
L8J 0J3

India
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049

USA
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
The fifth major webpack release was released recently. Almost two years since the last major release (4), this release brings a lot of changes to the most used module bundler in the JavaScript ecosystem. If like me, you started your front-end career prior to the rise of webpack, you remember the pain and frustration of working with tools like gulp and grunt.
Let’s take a look at the breaking changes and the improvements that come with the new release of this incredibly popular library.
This new version concentrates on five key areas.
Slow builds are one of the most common complaints from developers about webpack. The module bundler now offers an opt-in filesystem cache. This should improve our productivity as developers by speeding up our development builds.
Improvements have been made to tree shaking (also known as dead code elimination). While previous versions of webpack were able to remove unused code, version 5 takes it even further. webpack is now able to remove code inside of modules, leading to even smaller bundle sizes. To read more about all of the optimization features of webpack 5, check out the official documentation.
After bundle size, the thing that can improve your app loading time the most is caching. With caching, returning visitors to your application experience an almost instantaneous loading experience. With webpack 5, changes made to your code that don’t change the minimized version (eg, comments or variable names), do not result in cache invalidation. This means that your users will be able to experience the performance improvements of caching for longer.
Some of the changes introduced in this version will not have any visible impact on your application’s performance today. Instead, they are meant to allow for new features and improvements in later versions of webpack 5.
These future features include using http(s) imports as module externals. This will help with the development of micro frontends. To read more about these new and exciting features, check out the official documentation here.
Another breaking change is bumping the minimum Node.JS version from 6 to 10.13.0. Dropping support for older Node.JS versions will allow the team to simplify their code, and remove workaround to support these older versions.
webpack 5 also brings a new experiments configuration option with support for WebAssembly, Async Web Assembly, Top Level Await, and outputting your bundle as a module (previously only possible with rollup).
This new feature, in short, allows multiple webpack builds to work together. It allows your application to dynamically load code from another application (aka, a different webpack build). The most popular application of module federation is to enable micro-frontend architecture.
Going over module federation in detail is beyond the scope of this article. If you are interested in learning more, be sure to read the official webpack post here.
Here’s a rundown of the breaking changes othat made it into this version and corresponding migration advice.
All items that were marked as deprecated in version 4 have been removed. If your webpack 4 build prints deprecation warnings, be sure to address those before upgrading.
The plugins IgnorePlugin and BannerPlugin accept different arguments. Read more here.
In previous versions of webpack, polyfills for native NodeJS libraries like crypto were included. These have been removed. Instead, you should use frontend focused libraries, or install the polyfills yourself.
This is a personal question, and it really depends on how you use webpack in your project. Most developers who use webpack, use a lot of plugins. You need to make sure that the plugins you use, support this new version.
If you are using NextJS, you can upgrade to webpack 5 by setting the version as a yarn resolution in your package.json. But again, if you have a custom webpack config, you will need to ensure that your config works with webpack 5.
The big advantage (and disadvantage for some) of create-react-app, is that there is no official way to customize your webpack config. For those of you using CRA, you will need to wait until react-scripts is upgraded to support webpack 5. According to a contributor, this should happen in Create-React-App version 4.1 (source).
For more information about migrating from version 4 to 5, be sure to check out the official migration guide.
This new release of webpack makes me even more excited for the future of frontend development. It’s so refreshing to see new features and improvements to a tool that We use every day. We should see it’s improvements driving innovation in the community for the next few years.
Most frontend developers don’t end up touching webpack very much, and just assume that it “just works”. We’ve said it before, and we’ll say it again: We think this is a mistake. Understanding how your build tools work makes you a stronger developer and is invaluable in debugging errors.
While the webpack team will continue to support version 4, by fixing bugs and adding features, for the foreseeable future, they suggest that you upgrade to version 5. With almost any library (except perhaps React), there comes a time when you need to make breaking changes and architectural improvements that rely on those breaking changes.
In short – while dealing with breaking changes is annoying, We don’t think it’s too much of an ask to make some changes to your application’s configuration every two years in exchange for a better and faster build system.
For more information and to develop web application using Webpack 5, Hire Front-End Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using Webpack 5, please visit our technology page.
Content Source:
Browsers don’t understand JSX out of the box, so most React users rely on a compiler like Babel or TypeScript to transform JSX code into regular JavaScript. Many preconfigured toolkits like Create React App or Next.js also include a JSX transform under the hood.
Together with the React 17 release, we’ve wanted to make a few improvements to the JSX transform, but we didn’t want to break existing setups. This is why we worked with Babel to offer a new, rewritten version of the JSX transform for people who would like to upgrade.
Upgrading to the new transform is completely optional, but it has a few benefits:
This upgrade will not change the JSX syntax and is not required. The old JSX transform will keep working as usual, and there are no plans to remove the support for it.
React 17 RC already includes support for the new transform, so go give it a try! To make it easier to adopt, after React 17 is released, we also plan to backport its support to React 16.x, React 15.x, and React 0.14.x. You can find the upgrade instructions for different tools below.
Now let’s take a closer look at the differences between the old and the new transform.
When you use JSX, the compiler transforms it into React function calls that the browser can understand. The old JSX transform turned JSX into React.createElement(…) calls.
For example, let’s say your source code looks like this:
import React from 'react'; function App() { return <h1>Hello World</h1>; }
Under the hood, the old JSX transform turns it into regular JavaScript:
import React from 'react'; function App() { return React.createElement('h1', null, 'Hello world'); }
Note Your source code doesn't need to change in any way. We're describing how the JSX transform turns your JSX source code into the JavaScript code a browser can understand.
However, this is not perfect:
To solve these issues, React 17 introduces two new entry points to the React package that are intended to only be used by compilers like Babel and TypeScript. Instead of transforming JSX to React.createElement, the new JSX transform automatically imports special functions from those new entry points in the React package and calls them.
Let’s say that your source code looks like this:
function App() { return <h1>Hello World</h1>; }
This is what the new JSX transform compiles it to:
// Inserted by a compiler (don't import it yourself!) import {jsx as _jsx} from 'react/jsx-runtime'; function App() { return _jsx('h1', { children: 'Hello world' }); }
Note how our original code did not need to import React to use JSX anymore! (But we would still need to import React in order to use Hooks or other exports that React provides.)
This change is fully compatible with all of the existing JSX code, so you won’t have to change your components. If you’re curious, you can check out the technical RFC for more details about how the new transform works.
Note The functions inside react/jsx-runtime and react/jsx-dev-runtime must only be used by the compiler transform. If you need to manually create elements in your code, you should keep using React.createElement. It will continue to work and is not going away.
If you aren’t ready to upgrade to the new JSX transform or if you are using JSX for another library, don’t worry. The old transform will not be removed and will continue to be supported.
If you want to upgrade, you will need two things:
Since the new JSX transform doesn’t require React to be in scope, we’ve also prepared an automated script that will remove the unnecessary imports from your codebase.
Create React App support has been added and will be available in the upcoming v4.0 release which is currently in beta testing.
Next.js v9.5.3+ uses the new transform for compatible React versions.
Gatsby v2.24.5+ uses the new transform for compatible React versions.
Note If you get this Gatsby error after upgrading to React 17.0.0-rc.2, run npm update to fix it.
Support for the new JSX transform is available in Babel v7.9.0 and above.
First, you’ll need to update to the latest Babel and plugin transform.
If you are using @babel/plugin-transform-react-jsx:
# for npm users npm update @babel/core @babel/plugin-transform-react-jsx
# for yarn users yarn upgrade @babel/core @babel/plugin-transform-react-jsx
If you are using @babel/preset-react:
# for npm users npm update @babel/core @babel/preset-react
# for yarn users yarn upgrade @babel/core @babel/preset-react
Currently, the old transform (“runtime”: “classic”) is the default option. To enable the new transform, you can pass {“runtime”: “automatic”} as an option to @babel/plugin-transform-react-jsx or @babel/preset-react:
// If you are using @babel/preset-react { "presets": [ ["@babel/preset-react", { "runtime": "automatic" }] ] }
// If you're using @babel/plugin-transform-react-jsx { "plugins": [ ["@babel/plugin-transform-react-jsx", { "runtime": "automatic" }] ] }
Starting from Babel 8, “automatic” will be the default runtime for both plugins. For more information, check out the Babel documentation for @babel/plugin-transform-react-jsx and @babel/preset-react.
Note If you use JSX with a library other than React, you can use the importSource option to import from that library instead - as long as it provides the necessary entry points. Alternatively, you can keep using the classic transform which will continue to be supported.
If you are using eslint-plugin-react, the react/jsx-uses-react and react/react-in-jsx-scope rules are no longer necessary and can be turned off or removed.
{ // ... "rules": { // ... "react/jsx-uses-react": "off", "react/react-in-jsx-scope": "off" } }
TypeScript supports the JSX transform in v4.1 beta.
Flow supports the new JSX transform in v0.126.0 and up.
Because the new JSX transform will automatically import the necessary react/jsx-runtime functions, React will no longer need to be in scope when you use JSX. This might lead to unused React imports in your code. It doesn’t hurt to keep them, but if you’d like to remove them, we recommend running a “codemod” script to remove them automatically:
cd your_project npx react-codemod update-react-imports
Note If you're getting errors when running the codemod, try specifying a different JavaScript dialect when npx react-codemod update-react-imports asks you to choose one. In particular, at this moment the "JavaScript with Flow" setting supports newer syntax than the "JavaScript" setting even if you don't use Flow. File an issue if you run into problems. Keep in mind that the codemod output will not always match your project's coding style, so you might want to run Prettier after the codemod finishes for consistent formatting.
Running this codemod will:
For example,
import React from 'react'; function App() { return <h1>Hello World</h1>; }
will be replaced with
function App() { return <h1>Hello World</h1>; }
If you use some other import from React – for example, a Hook – then the codemod will convert it to a named import.
For example,
import React from 'react'; function App() { const [text, setText] = React.useState('Hello World'); return <h1>{text}</h1>; }
will be replaced with
import { useState } from 'react'; function App() { const [text, setText] = useState('Hello World'); return <h1>{text}</h1>; }
In addition to cleaning up unused imports, this will also help you prepare for a future major version of React (not React 17) which will support ES Modules and not have a default export.
For more information and to develop web application using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.
Content Source:
TypeScript 4.0 is a major milestone in the TypeScript programming language and has currently leapfrogged 3.9 to become the latest stable version. In this post, we’ll look at the new features TypeScript 4.0 offers.
To get started using 4.0, you can install it through NuGet or via NPM:
npm i typescript
You can test the code using the TypeScript playground or a text editor that supports TypeScript. I recommend using Visual Studio Code, you can get set up instructions here.
In a nutshell, we can say TypeScript is strongly typed JavaScript. This means that it requires developers to accurately specify the format of their data types, consequently, it allows the compiler to catch type errors at compile time and therefore, give a better developer experience.
This process of accurately specifying the format of data types is known as type declaration or type definitions — it is also called typings or simple types.
With this feature, TypeScript gives types to higher-order functions such as curry, concat, and apply. These are functions that take a variable number of parameters.
Consider a small contrived example of the concat function below:
function simpleConcat(arr1, arr2) { return [...arr1, ...arr2]; } console.log(simpleConcat([1,2,3], [5,6])) // [1, 2, 3, 5, 6]
There is currently no easy way to type this in TypeScript. The only typing strategy available currently is to write overloads.
Function or method overloading refers to a feature in TypeScript that allows us to create multiple functions having the same name but a different number of parameters or types.
Consider this:
function concat1<T>(arr1: [T], arr2: []): [T] { return [...arr1, ...arr2] } function concat2<T1, T2>(arr1: [T1, T2], arr2: []): [T1, T2] { return [...arr1, ...arr2] }; function concat6<T1, T2, T3, T4, T5, T6>(arr1: [T1, T2, T3, T4, T5, T6], arr2: []): [T1, T2, T3, T4, T5, T6] { return [...arr1, ...arr2] } function concat7<T1, T2, T3, T4, T5, T6, A1, A2, A3, A4>(arr1: [T1, T2, T3, T4, T5, T6], arr2: [A1, A2, A3, A4]): [T1, T2, T3, T4, T5, T6, A1, A2, A3, A4] { return [...arr1, ...arr2] } console.log("concated 1", concat1([1], [])) console.log("concated 2", concat2([1,2], [])) console.log("concated 6", concat6([1,2,3,4,5,6], [])) console.log("concated 10", concat10([1,2,3,4,5,6], [10, 11, 12, 13]))
From the example above we can see that the number of overloads increases as the number of items in the array increases which is suboptimal. In concat6 we had to write 6 overloads even when the second array is empty and this quickly grew 10 overloads in concat10 when the second array had just 4 items.
Also, we can only get correct types for as many overloads as we write.
TypeScript 4.0 comes with significant inference improvements. It allows spread elements in tuple types to be generic and to occur anywhere in the tuple.
In older versions, REST element must be last in a tuple type. And TypeScript would throw an error if this were not the case:
// Tuple speard items are generic function concatNumbers<T extends Number[]>(arr: readonly [Number, ...T]) { // return something } // spread occuring anywhere in the tuble valid in 4.0 beta. type Name = [string, string]; type ID = [number, number]; type DevTuples = [...Name, ...Numbers]
Given these two additions, we can write a better function signature for our concat function:
type Arr = readonly any[]; function typedConcat<T extends Arr, U extends Arr>(arr1: T, arr2: U): [...T, ...U] { return [...arr1, ...arr2]; } console.log("concated", typedConcat([1,2,3,4,5], [66,77,88,99]))
This is a pithy addition to TypeScript aimed at improving code readability.
Consider the code below:
type Period = [Date, Date]; // Example 1 older version type Period = [StartDate: Date, EndDate: Date]; // Example 2 4.0 beta function getAge(): [birthDay: Date, today: Date] { // ... }
Previously, TypeScript developers use comments to describe tuples because the types themselves (date, number, string) don’t adequately describe what the elements represent.
From our small contrived example above, “example 2” is way more readable because of the labels added to the tuples.
When labelling tuples all the items in the tuples must be labelled.
Consider the code below:
type Period = [startDate: Date, Date]; // incorrect type Period = [StartDate: Date, EndDate: Date]; // correct
In TypeScript 4.0, we can now use control flow analysis to determine the types of properties in classes when noImplicitAny is enabled. Let’s elaborate on this with some code samples.
Consider the code below:
// Compile with --noImplicitAny class CalArea { Square; // string | number constructor(area: boolean, length: number, breadth: number) { if (!area) { this.Square = "No area available"; } else { this.Square = length * breadth; } } }
Previously, the code above would not compile if noImplicitAny is enabled. This is because property types are only inferred from direct initializations, so their types must either be defined explicitly or using an initial initializer.
However, TypeScript 4.0 can use control flow analysis of this.Square assignments in constructors to determine the types of Square.
Currently, in JavaScript, a lot of binary operators can be combined with the assignment operator to form a compound assignment operator. These operators perform the operation of the binary operator on both operands and assigned the value to the left operand:
// compound operators foo += bar // foo = foo + bar foo -= bar // foo = foo - bar foo *= bar // foo = foo * bar foo /= bar // foo = foo/bar foo %= bar // foo = foo % bar
The list goes on but with three exceptions:
|| // logical or operator && // logical and operator ?? // nullish coalescing operator
TypeScript 4.0 beta would allow us to combine these three with the assignment operator thus forming three new compound operators:
x ||= y // x || (x = y) x &&= y // x && (x = y) x ??= y // x ?? (x = y )
Previously, when we use the try … catch statement in TypeScript, the catch clause is always typed as any, consequently, our error-handling code lacks any type-safety which should prevent invalid operations. I will elaborate with some code samples below:
try { // ... }catch(error) { error.message error.toUpperCase() error.toFixed() // ... }
From the code above we can see that we are allowed to do anything we want — which is really what we don’t want.
TypeScript 4.0 aims to resolve this by allowing us to set the type of the catch variable as unknown. This is safer because it’s meant to remind us to do a manual type checking in our code:
try { // ... }catch(error: unknown) { if(typeof error === "String") { error.toUpperCase() } if(typeof error === "number") { error.toFixed() } // ... }
TypeScript already supports jsxFactory compiler option, this feature, however, adds a new compiler option known as jsxFragmentFactory which enables users to customize the React.js fragment factory in the tsconfig.json:
{ "compilerOptions": { "target": "esnext", "module": "commonjs", "jsx": "react", // React jsx compiler option "jsxFactory": "createElement", // transforms jsx using createElement "jsxFragmentFactory": "Fragment" // transforms jsx using Fragment } }
The above tsconfig.json configuration transforms JSX in a way that is compatible with React thus a JSX snippet such as <article/> would be transformed with createElement instead of React.createElement. Also, it tells TypeScript to use Fragment instead of React.Fragment for JSX transformation.
TypeScript 4.0 also features great performance improvements in –build mode scenarios and also allows us to use the –noEmit flag while still leveraging –incremental compiles. This was possible in older versions.
In addition, there are several editor improvements such as @deprecated JSDoc annotations recognition, smarter auto-imports, partial editing mode at startup (which aimed to speed up startup time).
For more information and to develop web application using TypeScript, Hire TypeScript Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using TypeScript, please visit our technology page.
Content Source:
Apollo Client 3 offers a few new features, including package rearrange changes and more caching features. Let’s proceed to take a look at how to use the latest features from Apollo Client 3.
The InMemoryCache API has expanded features. They include the eviction of objects and fields, garbage collection, types and fields configuration, and pagination helpers.
Let’s explore these changes by installing the @apollo/client package with its dependencies by running:
npm i @apollo/client graphql react
We can add the InMemoryCache into our Apollo Client by writing:
import { ApolloClient, InMemoryCache, gql } from "@apollo/client"; const cache = new InMemoryCache(); const client = new ApolloClient({ uri: "https://graphqlzero.almansi.me/api", cache }); client .query({ query: gql` { user(id: 1) { id name } } ` }) .then(console.log);
The client is created with the cache option, which we set to the InMemoryCache; the cached items will be in memory. Once we’ve done that, we can use the new InMemoryCache features that come with Apollo Client 3.
We can evict the cached items by calling:
cache.evict();
We can optionally pass in the cached object’s ID by writing:
cache.evict({ id: 'user' })
We can also add a field property of the object like so:
cache.evict({ id: 'user', fieldName: 'name' })
The cache.gc method lets us do garbage collection on cached items. The object is determined to be reachable by tracing from the root to all the child references. Normalized objects that aren’t visited are removed.
To clear the unreachable cached items, we just call:
cache.gc();
Garbage collection can also be configured to retain some items. To retain the object with the ID ‘user’, for instance, we can write;
cache.retain({ id: 'user' })
We can configure how to deal with dangling references. When an object is evicted from the cache, it might have objects that have other cached objects. Apollo Client preserves these references because they may still be used later.
We can change how these references are dealt with by using a custom read function. To do so, we would write:
import { ApolloClient, InMemoryCache, gql } from "@apollo/client"; const cache = new InMemoryCache({ typePolicies: { Query: { fields: { ruler(existingRuler, { canRead, toReference }) { return canRead(existingRuler) ? existingRuler : toReference({ __typename: "user", name: "Apollo" }); } } }, user: { keyFields: ["name"], fields: { offspring(existingOffspring, { canRead }) { return existingOffspring ? existingOffspring.filter(canRead) : []; } } } } }); const client = new ApolloClient({ uri: "https://graphqlzero.almansi.me/api", cache }); client .query({ query: gql` { user(id: 1) { id name } } ` }) .then(console.log);
We set the ruler of the cache to our own ruler function. We determine what references can be read.
If there’s an existing cache ruler, then we use it; otherwise, we get the item with toReference. The offspring method returns the objects where canRead returns true. This way, we know we can read those items.
We can create our own local field within the InMemoryCache object.
For instance, we can write:
import { ApolloClient, InMemoryCache, gql } from "@apollo/client"; const cache = new InMemoryCache({ typePolicies: { User: { fields: { age: { read(_, { variables }) { return Math.random() * 100; } } } } } });
We created a local field with name age. This way, we can include the field in our query like the loading state and the networkStatus. variables have the fields from the query. It also has the caching data.
It’s just a getter that returns a random number:
import { ApolloClient, InMemoryCache, gql } from "@apollo/client"; const cache = new InMemoryCache({ typePolicies: { User: { fields: { age: { read(_, { variables }) { return Math.random() * 100; } } } } } }); const client = new ApolloClient({ uri: "https://graphqlzero.almansi.me/api", cache }); client .query({ query: gql` { user(id: 1) { id name age @client } } ` }) .then(console.log);
We get the age field with age @client. The @client keyword distinguishes local fields from fields that are retrieved from the API.
Reactive variables is the new feature from Apollo Client 3.0 onwards. To create one, we use the makeVar method from the @apollo/client package. For instance, to create a children reactive variable, we can write:
import { makeVar } from "@apollo/client"; const children = makeVar(["jane", "mary"]);
It returns a function that has the value of the reactive variable. To call it and get the value, we can write:
console.log(children());
The console log should read:
["jane", "mary"]
Reactive variables are useful for storing local state outside of the Apollo Client cache. This is different from local states and cached items, which are retrieved from the cache. Modifying a reactive variable automatically triggers an update of all active queries that depend on the variable.
We can also store local state with reactive variables. To do that, we can write:
import { ApolloClient, InMemoryCache, gql, makeVar } from "@apollo/client"; const age = makeVar(Math.random() * 100); const cache = new InMemoryCache({ typePolicies: { User: { fields: { age: { read(_, { variables }) { return age(); } } } } } }); const client = new ApolloClient({ uri: "https://graphqlzero.almansi.me/api", cache }); client .query({ query: gql` { user(id: 1) { id name age @client } } ` }) .then(console.log);
Above, we created the age reactive variable, and we read it into the local state by returning it in the read method. Then we can query age like we do with other local states. Now, whenever our query changes, we’ll see a new value of age returned as well.
To update the reactive variable, we just pass in a new value, like so:
import { makeVar } from "@apollo/client"; const age = makeVar(Math.random() * 100); console.log(age()); age(Math.random() * 100); console.log(age());
We pass in a new value to the function returned by makeVar to update the value. Now both console logs should show different values.
We can define our own cache field policy so that we can read them in a way that’s different from what’s in the API.
For instance, we can write:
import { ApolloClient, InMemoryCache, gql } from "@apollo/client"; const cache = new InMemoryCache({ typePolicies: { User: { fields: { name: { read(name) { return name.toUpperCase(); } } } } } }); const client = new ApolloClient({ uri: "https://graphqlzero.almansi.me/api", cache }); client .query({ query: gql` { user(id: 1) { id name } } ` }) .then(console.log);
We created a type policy for the User type. fields has the fields we want to modify when reading, and we want the value of name to be upper-case.
So we make the name’s read method return the upper-case name. Now the console.log call in the then method should have the data field with user.name inside it being upper-case.
We can use this for many other applications, like setting default field values, transforming lists, changing field values, pagination, and much more.
Apollo Client 3 comes with many changes to caching, including the ability to clear cache data. We can also add local fields and change the ways normal fields are retrieved with cache policy.
For more information and to develop web application using Front-End JS, Hire Front-End Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using Front-End JS, please visit our technology page.
Content Source:
It has been two and a half years since React v16 was first released. The dev team promises that update v17 is incredibly important for the future of React but claims that no new features are being added. So what exactly does that mean? And how can React claim to be releasing a major new version without adding new features?
Past React updates have always caused deprecations of older versions. This could make it incredibly difficult for teams to upgrade their React versions, especially when working with large or neglected codebases. So, the React team has decided that v17 will lay the groundwork for a new method of adopting updates. When React v18 is released, developers will be able to choose to only upgrade parts of their app and keep other parts running on v17. React advises against this if you’re application is actively maintained or in large-scale production, but it can help teams who don’t actively maintain their application or who don’t need to migrate certain components to the newer version. In the future, new React versions won’t leave these apps behind or demand massive migrations.
To enable this ability, the React team has spent some time reworking the event system. These updates are what caused React v17 to be a major release since it could potentially break many applications.
Contrary to what you might think, React doesn’t attach events to individual elements. Instead, React binds one handler per event type to the document
node. This approach increases performance in applications with large element trees and also enables features like replaying events.
In the background, React can capture an event and determine which component to call before propagating the event up the component tree. However, in native Javascript, the event has already propagated to the document
level. While this may not sound like an issue, this system breaks when running multiple instances of React. If a React app nested inside of another one has stopped the propagation of the event, the parent React app will still capture the event. This was a major headache for developers looking to nest different versions of React. You may not think that this happens in production, but the Atom code editor encountered this issue four years ago!
React will now attach event handlers to the root node of the React app. This change will allow the safe nesting of React trees within each other. Granted, all React instances will have to be running on version 17 or higher for this to work. This update also means that React apps are easier to embed inside of other frameworks like jQuery. React will now stop events from propagating to jQuery as one would expect.
It is fairly common to return a cleanup function within a useEffect
method to stop any code running within the function. In the past, this cleanup function would run synchronously before the next frame was drawn. In reality, most apps don’t require screen updates to be delayed will running cleanup methods. So they will now run asynchronously after React has rendered the next frame. This should result in faster switch times between components. You can still use the useLayoutEffect
method to run a cleanup method that blocks the render loop.
Event pooling is incredibly confusing and doesn’t provide any optimizations on modern browsers. Instead, it can result in some strange bugs when working with multiple components that receive the same event. One event handler might set the event to be null, and thus the other components using the event would run into a null variable error. In short, newer React version will allow event fields to be accessed whenever you need them.
React v17 may not be the feature-packed update React developers were hoping for. It is instead more of a piece-of-mind update. So while we may not be getting cool new components or hooks, these additions will pay off down the road in later updates. You can try React v17 now by running npm install react@17.0.0-rc.0 react-dom@17.0.0-rc.0
in your React project.
For more information and to develop web application using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.
Content Source:
React Router is by far the most popular library in the React ecosystem. According to npm, it is downloaded about 3.6 million times a week. This number is almost half of React’s 7.6 million weekly downloads. This means that almost every second project that uses React uses React Router.
That’s huge. Almost half of the React projects out there rely on React Router for routing. Chances are, if you have worked with React, you have worked with React Router.
Now with version six in beta and a new release coming soon, we thought it would be interesting to take a dive into what’s new and what has changed in React Router version 6.
For a library that is so important to the React community, it has gone through a number of iterations and breaking changes. From its first release in 2014, and with every major release, the maintainers of React Router have introduced new features and breaking changes. Some in the React community have complained about the difficulty of upgrading from one version to the next, and have questioned the library’s constant churn.
Many have complained about the difficult upgrades that came with every new major release of the library.
If your application is working correctly, and you don’t need access to the new features promised in version 6, you can stick with your older version. Don’t feel the need to refactor your old applications to use React Router 6. If it ain’t broke, don’t fix it.
npm install react-router@next react-router-dom@next
So without further ado, let’s take a look at what’s new and what has changed in the latest version of React Router
Routes is introduced as a new element in React Router version 6. This new element allows us to easily define nested routes and relative routes, and make it easy to compose complex routes and layouts. In the previous version of the library, we defined Routes inside of a Switch.
The <Routes > is the new <Switch> element now. It is very much similar to <Switch> with some new features.
// old - v5 import { BrowserRouter, Switch, Route } from 'react-router-dom'; const App = () => { return ( <BrowserRouter> <Switch> <Route exact path="/" component={Home} /> <Route path="/users" component={Users} /> </Switch> </BrowserRouter> ); } // new - v6 import { BrowserRouter, Routes, Route } from 'react-router-dom'; const App = () => { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home />} /> <Route path="users" element={<Users />} /> </Routes> </BrowserRouter> ); }
Did that component prop got changed to element?
That brings us to our second highlight.
If you notice in the above example, in the new version we are passing a react element instead of a component. This is so much better, now we can pass props directly to the element.
// old - v5 <Route exact path="/" component={Home} /> <Route path="/users" render={routeProps => ( <Users isCustomLayout={true} /> )} /> // new - v6 <Route path="/" element={<Home />} /> <Route path="users" element={<Users isCustomLayout={true} />} />
Now, all Route and Link children of a Route are relative to their parent. This makes it a lot easier to build applications with many nested routes and makes it easier to reason about your application’s routing logic.
No more exact and strict props
Yes, you read it right. In v6 all the routes match exactly by default.
// old - v5 <Route exact path="/" component={Home} /> // new - v6 <Route path="/" element={<Home />} />
Relative paths and links
In v6, both paths and links are relative to their parent route. This means we can omit the “/” if we want the relative path.
// old - v5 <Route exact path="/" component={Home} /> <Route path="/users" component={Users} /> // new - v6 <Route path="/" element={<Home />} /> <Route path="users" element={<Users />} />
If you have used previous versions of React Router, you will immediately notice that we don’t need to use the exact prop anymore. You will also notice that the Link we defined is relative. Instead of passing /customers/:id, we can just use /:id.
What about nested routes then? They just got better.
Just like your regular react elements we just need to wrap the child route with a parent one.
// old - v5 <Route exact path="/" component={Home} /> <Route path="/users" component={Users} /> // .... users.js import { useRouteMatch } from 'react-router-dom'; const Users = () => { const { path } = useRouteMatch(); return ( <div> // you can do something here <Switch> <Route path={`${path}/:id`} component={UserInfo} /> <Route path={`${path}/profile`} component={UserProfile} /> </Switch> </div> ); } // new - v6 <Route path="/" element={<Home />} /> <Route path="users" element={<Users />}> <Route path=":id" element={<UserInfo />} /> <Route path="profile" element={<UserProfile />} /> </Route> // .... import { Outlet } from 'react-router-dom'; const Users = () => { return ( <div> // you can do something here // Outlet: This element is used as a placholder for the child route. // Which means it will be either <UserInfo /> or <UserProfile /> <Outlet /> </div> ); }
Now we can define our routes using the new useRouter hook. This allows you to build your routes using JavaScript objects. Let’s take a look at our previous application, now defined using useRouter.
import { BrowserRouter, Link, Outlet, useRoutes } from 'react-router-dom'; function App() { let element = useRoutes([ { path: '/', element: <Home /> }, { path: 'customers', element: <Customers />, children: [ { path: '/', element: <CustomersIndex /> }, { path: ':id', element: <CustomerProfile /> }, ] } ]); return element; } function Users() { return ( <div> <nav> <Link to="/1">Customer 1</Link> </nav> <Outlet /> </div> ); }
You might ask yourself, why does it matter? Why would I want to compose my routes using JavaScript objects instead of JSX? One great use case would be to programmatically build routes, let’s say, based on the directory structure of your application. You could loop through all of the files in your pages directory, and build routes from that.
The team behind React Router claims that the new version is a lot smaller than the previous versions. They estimate that it’s about 70% smaller. Smaller bundles mean that your application loads faster, and content to your users faster.
With all these awesome changes, there is also icing on the cake. They have reduced the bundle size by more than 50%.
Pic courtesy: medium.com
The old useHistory hook has been removed and replaced with a suspense-ready navigate API. Now you can use useNavigate to programmatically navigate around your application. They also expose a Navigate component that you can use to redirect your users.
No more history, it’s time to navigate. The useHistory hook is now replaced with the suspense-ready useNavigate hook.
// old - v5 import { useHistory } from 'react-router-dom'; const CustomButton = props => { const history = useHistory(); const handleClick = () => { history.push('/users'); } return <button onClick={handleClick}>{props.label}</button>; } // new - v6 import { useNavigate } from 'react-router-dom'; const CustomButton = props => { const navigate = useNavigate(); const handleClick = () => { navigate('/users'); } return <button onClick={handleClick}>{props.label}</button>; }
So that’s it! If you believe that your applications can benefit from smaller bundle sizes, and from suspense ready navigation, we strongly suggest that you upgrade to the latest version.
For more information and to develop web application using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.
Content Source:
Version 10.0.0 is here! This is a major release that spans the entire platform, including the framework, Angular Material, and the CLI. This release is smaller than typical; it has only been few months since we released version 9.0 of Angular.
We try to release two major versions each year to keep Angular synchronized with the rest of the JavaScript ecosystem and to have a predictable schedule. We plan to release version 11 this fall.
New Date Range Picker
Angular Material now includes a new date range picker.
Image of the new date range picker. Pic courtesy: blog.angular.io
To use the new date range picker, you can use the mat-date-range-input
and mat-date-range-picker
components.
Warnings about CommonJS imports
When you use a dependency that is packaged with CommonJS, it can result in larger slower applications.
Starting with version 10, we now warn you when your build pulls in one of these bundles. If you’ve started seeing these warnings for your dependencies, let your dependency know that you’d prefer an ECMAScript module (ESM) bundle.
CommonJS or AMD dependencies can cause optimization bailouts. Pic courtesy: blog.angular.io
Optional Stricter Settings
Version 10 offers a more strict project setup when you create a new workspace with ng new
.
ng new --strict
Enabling this flag initializes your new project with a few new settings that improve maintainability, help you catch bugs ahead of time, and allow the CLI to perform advanced optimizations on your app. Specifically, the strict
flag does the following:
any
Keeping Up to Date with the Ecosystem
As usual, we have made a few updates to the dependencies of Angular to stay synchronized with the JavaScript ecosystem.
We’ve also updated our project layout. Starting with version 10 you will see a new tsconfig.base.json
. This additional tsconfig.json
file better supports the way that IDEs and build tooling resolve type and package configurations.
New Default Browser Configuration
We’ve updated the browser configuration for new projects to exclude older and less used browsers.
v9 Defaults
Pic courtesy: blog.angular.io
v10 Defaults
Pic courtesy: blog.angular.io
This has the side effect of disabling ES5 builds by default for new projects. To enable ES5 builds and differential loading for browsers that require it (such as IE or UC Browser), simply add the browsers you need to support in the .browserslistrc
file.
Angular Team Fixit
We’ve dramatically increased our investment in working with the community. In the last three weeks our open issue count has decreased by over 700 issues across framework, tooling, and components. We’ve touched over 2,000 issues, and we plan to make large investments over the next few months, working with the community to do even more.
Deprecations and Removals
We’ve made several new deprecations and removals from Angular.
The Angular Package Format no longer includes ESM5 or FESM5 bundles, saving you 119MB of download and install time when running yarn
or npm install
for Angular packages and libraries. These formats are no longer needed as any downleveling to support ES5 is done at the end of the build process.
Based on heavy consultation with the community, we are deprecating support for older browsers including IE 9, 10, and Internet Explorer Mobile.
You can read more about our deprecations and removals.
Visit update.angular.io for detailed information and guidance. To have the best update experience, we recommend always upgrading one major release at a time.
To update:
ng update @angular/cli @angular/core
For more information and to develop web application using Angular, Hire Angular Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop web application using Angular, please visit our technology page.
Content Source:
In this article, you’re going to see how to set up Jenkins from scratch and create and run an Angular pipeline — all in about five minutes. Don’t worry if you’re not familiar with Angular. The same principles hold for Vue, React, Python, Java, and other languages. So get comfy because we’re about to start.
The structure of the article will be as follows:
If you’re already familiar with Jenkins, feel free to skip this part.
In this section, we’ll go over the installation steps for macOS and Linux as shown on the Jenkins website. You can also find information on getting started on a Windows machine.
First, let’s create a network for Jenkins:
docker network create jenkins
Add two volumes to share Docker client TLS certificates and persist Jenkins data. This way, no data is lost when you shut down your PC or server, for example. Keep in mind that if you do remove these volumes, data will be lost permanently.
docker volume create jenkins-docker-certs docker volume create jenkins-data
The following four commands bring the Docker container up:
docker image pull docker:dind docker container run --name jenkins-docker \ --restart unless-stopped \ --detach \ --privileged --network jenkins \ --network-alias docker \ --env DOCKER_TLS_CERTDIR=/certs \ --volume jenkins-docker-certs:/certs/client \ --volume jenkins-data:/var/jenkins_home \ --publish 2376:2376\ docker:dind docker image pull jenkinsci/blueocean docker container run --name jenkins-blueocean \ --restart unless-stopped \ --detach \ --network jenkins \ --env DOCKER_HOST=tcp://docker:2376 \ --env DOCKER_CERT_PATH=/certs/client \ --env DOCKER_TLS_VERIFY=1 \ --volume jenkins-data:/var/jenkins_home \ --volume jenkins-docker-certs:/certs/client:ro \ --publish 8080:8080 \ --publish 50000:50000 \ jenkinsci/blueocean
Jenkins is now running on http://localhost:8080, but you have to do one more tricky step: You have to unlock Jenkins. The initial password can be found inside a folder of the Jenkins CI blue ocean Docker container. I’ll show you how to retrieve this. When you try this yourself, make sure you specify the right docker UUID.
docker container ps 4ec29afb280f jenkinsci/blueocean 1ce11b131265 docker:dind docker container exec 4ec29afb280f cat /var/jenkins_home/secrets/initialAdminPassword bd95aa5131a142b690795fa9427287a8
In the next step, you can configure the plug-ins you want to install. I’ll leave that up to you. I installed the Cobertura (for Java) and Locale plug-ins and got rid of Subversion. After they are installed, you have to create an admin user.
In the last step, you have to set a Jenkins URL (e.g. http://localhost:8080), but I did not bother to change it. In the end, Jenkins restarts and is completely installed. That took us literally only a couple of minutes.
The Jenkins user interface. Pic courtesy: medium.com
Let’s face it, there are tons of possible ways to define a great pipeline. This will only be a simple example. It would be great to hear if you have suggestions for an improved pipeline. Don’t hesitate to leave a comment at the end of the article!
First of all, it’s important to specify a base Docker image to run our commands. At the time of writing, using the latest node Docker image felt like a good choice.
Next, we specify the stages to go over. In this configuration, the most recognizable development stages are specified:
Feel free to add additional steps. At this point, you have so much freedom. Deploy automatically or publish a Docker image that can be rolled out to a limited amount of users. That choice is yours. To conclude this section, let me share the pipeline with you. Put this inside a Jenkinsfile (no extension) in the root folder of your project:
pipeline { agent { docker { image 'node:latest' } } stages { stage('Install') { steps { sh 'npm install' } } stage('Test') { parallel { stage('Static code analysis') { steps { sh 'npm run-script lint' } } stage('Unit tests') { steps { sh 'npm run-script test' } } } } stage('Build') { steps { sh 'npm run-script build' } } } }
Open Jenkins on http://localhost:8080 and create a new item. No need to do a lot here, actually. Let’s create a “Multibranch Pipeline.”
Create a Pipeline menu. Pic courtesy: medium.com
A new menu opens. Here, you can add a description among many other things, but we’ll only cover the most important parts in this article. You should look for the section called “branch sources” and select Git. The next thing to do is pass in a project repository (e.g. https://github.com/user/project-name.git) and your credentials. That is sufficient.
Let’s add one more thing to make it an automatic pipeline. Let’s poll the GitHub repository for changes. Enable “Scan Multibranch Pipeline Triggers” and pass a reasonable interval. This will trigger a build (e.g. every minute) only when there are source code changes. That way, builds get triggered automatically. If one minute is too intensive, you can always lower the interval to check for changes later on.
Now go to http://localhost:8080/blue/organizations/jenkins/pipelines and run your first job if it’s not already running. Let me show you how this looks:
The pipeline was successful! Pic courtesy: medium.com
For more information and to develop web application using Angular, Hire Angular Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop web application using Angular, please visit our technology page.
Content Source:
Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone while being compatible with the newest features of React.
While working with react you might have noticed that are different ways to manage the global state management in React. Let’s take look at the options that we have:
Redux is a predictable state container for JavaScript apps.
It is used by a lot of web apps these days, it allows us to have a global state, register components to it and they will re-render by themselves every time a value they registered to will change.
Context API is another approach that devs take for better management of state within the application.
Context is designed to share data that can be considered “global” for a tree of React components, such as the current authenticated user, theme, or preferred language.
Now that we are already using to above two famous ways of adding global state to our application here comes something new i.e Recoil.
Recoil lets you create a data-flow graph that flows from atoms (shared state) through selectors (pure functions) and down into your React components.
React
local component state. If the same atom is used from multiple components, all those components share their state.Let’s try to understand this with a Demo example.
Consider we want to store user data upon login into our application and share between two components,
Let first define an atom which stores the logged-in user Data
pic courtesy: blog.bitsrc.io
In the above example, we have stored the object which has a name in it. It is stored inside our loggedInUserData
atom.
Now consider we need to show this name in our useRecoilState
.
pic courtesy: blog.bitsrc.io
And our component looks something like this, which display the data from the same atom which is used in the header component again with help of useRecoilState
pic courtesy: blog.bitsrc.io
The syntax might look quite similar to useState which we are already used to in react
hooks.
As in the above example since the same state is shared between the
This is one of the important hooks in the Recoil API. This hook will just subscribe to the component to the given Recoil state, it is used to return the value of the given Recoil state.
For more information and to develop web application using React JS, Hire React Developer from us as we give you a high-quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft”. To develop custom web apps using React JS, please visit our technology page.
Content Source:
Express is a web application framework for Node. It provides various features that make web-application development fast and easy, a task that otherwise takes more time when using only Node.
There are many ways you can create and manage routes using Express, the most simple and direct being through the use of the delete, get, post, and put methods. Each one of them is mapped to the equivalent request HTTP verb.
const express = require("express"); const app = express(); const port = 3000; app.get("/", (req, res) => res.send("GET")); app.post("/", (req, res) => res.send("POST")); app.get("/home", (req, res) => res.send("GET HOME")); app.post("/home", (req, res) => res.send("POST HOME")); app.get("/about", (req, res) => res.send("GET HOME")); app.post("/about", (req, res) => res.send("POST HOME")); app.listen(port, () => console.log(`App listening at http://localhost:${port}`) );
In the example above, we have three routes (/, /home, /about), each one with two different HTTP verbs (get, post) and its own logic that’s sending a unique text to the client
As you can see from this tiny example, this kind of approach can get very messy when the number of routes increase.
There’s a way we can make this code better by using the route method and method chaining to equal paths:
const express = require("express"); const app = express(); const port = 3000; app.route("/") .get((req, res) => res.send("GET")) .post((req, res) => res.send("POST")); app.route("/home") .get((req, res) => res.send("GET HOME")) .post((req, res) => res.send("POST HOME")); app.route("/about") .get((req, res) => res.send("GET HOME")) .post((req, res) => res.send("POST HOME")); app.listen(port, () => console.log(`App listening at http://localhost:${port}`) );
This way we can make the code a little bit shorter, but it’s still messy since we have multiple route paths in the same file.
Our next step is to create a separate file for each path and make use of the Express Router object. The Router object is an isolated instance of middleware and routes. You can think of it as a mini-application, capable only of performing middleware and routing functions.
// /routes/root.js const express = require("express"); const router = express.Router(); router .route("/") .get((req, res) => res.send("GET")) .post((req, res) => res.send("POST")); module.exports = router; // /routes/home.js const express = require("express"); const router = express.Router(); router .route("/") .get((req, res) => res.send("GET HOME")) .post((req, res) => res.send("POST HOME")); module.exports = router; // /routes/about.js const express = require("express"); const router = express.Router(); router .route("/") .get((req, res) => res.send("GET ABOUT")) .post((req, res) => res.send("POST ABOUT")); module.exports = router; // index.js const express = require("express"); const app = express(); const port = 3000; app.use("/", require("./routes/root")); app.use("/home", require("./routes/home")); app.use("/about", require("./routes/about")); app.listen(port, () => console.log(`App listening at http://localhost:${port}`) );
This way, we have cleaner code in the main file, index.js, and each route is defined in its own file. In addition to the Route object, we make use of the Express method use to map the path to its configuration file.
It’s much better than what we had in the earlier examples, but we can still see some problems here — like the code repetition in each route file and, mainly, the fact that every time we add new route files to the app, we need to change the main file to map the path to the file. When we have a great number of routes, we have the same problem: The main file code gets bigger and messy.
To solve the second issue, we can make a separate file to map each path to its route file and do a simple require in the main file.
// /routes/index.js module.exports = (app) => { app.use("/", require("./root")); app.use("/home", require("./home")); app.use("/about", require("./about")); }; // index.js const express = require("express"); const app = express(); const port = 3000; require("./routes")(app); app.listen(port, () => console.log(`App listening at http://localhost:${port}`) );
The routes folder index file receives the app instance from the main file and makes the path mapping. The main file makes use of the Immediately Invoked Function Expression to require and execute the routes index file passing the app created. Now we have a cleaner main file, but we still have the problem that it’s required to manually map each path to its file.
Node can help us make this better if we can make it loop through the routes folder’s files and make the mapping. To achieve this, we’ll make use of Node’s fs.readdirSync. This method is used to synchronously read the contents of a given directory. The method returns an array with all the file names or objects in the directory.
And you may ask, what about the path? If we don’t have an automated way to discover the path of each route file, we’ll still have to edit the list for each route added. We can see two kinds of solutions for this issue: to use convention over configuration or to add a export with the path in the route file.
To use convention over configuration, we’ll use the filename as the route path. To make it safer and to remove potential problematic characters, we’ll use Lodash to convert the filename to snakeCase, where strings are separated by an underscore.
Another change we’ll make is to use the Router object only in the routes config file, making the route code simpler and avoiding code repetition.
Besides this, we’ll make use the path.join Node method to make our code cross-platform, since Windows and Linux-based systems use different path names:
// /routes/root.js module.exports = (router) => { router .get("/", (req, res) => res.send("GET")) .post("/", (req, res) => res.send("POST")); return router; }; // /routes/home.js module.exports = (router) => { router .get("/", (req, res) => res.send("GET HOME")) .post("/", (req, res) => res.send("POST HOME")); return router; }; // /routes/about.js module.exports = (router) => { router .get("/", (req, res) => res.send("GET ABOUT")) .post("/", (req, res) => res.send("POST ABOUT")); return router; }; // routes/index.js const snakeCase = require("lodash/snakeCase"); const express = require("express"); module.exports = (app) => { require("fs") .readdirSync(__dirname) .forEach((file) => { if (file === "index.js") return; const path = "/" + (file !== "root.js" ? snakeCase(file.replace(".js", "")) : ""); // root.js file will map to / const router = express.Router(); const route = require(require("path").join(__dirname, file));(router); app.use(path, route); }); }; // index.js const express = require("express"); const app = express(); const port = 3000; require("./routes")(app); app.listen(port, () => console.log(`App listening at http://localhost:${port}`) );
The other option, as we said earlier, is to export the desired path name in the route file and use this information in the route config file.
To achieve this, we’ll have to export an object with the path and config keys in our route file. In this kind of configuration, we strongly suggest you use the filename path method as a fallback to avoid errors in case you forget to add the path export. This way, we have an extra bonus: a solution that’ll work on both situations.
In our final example, we’ll change the home route path to my_home and leave the about route file as it was.
// /routes/root.js module.exports = { path: "/", config: (router) => { router .get("/", (req, res) => res.send("GET")) .post("/", (req, res) => res.send("POST")); return router; }, }; // /routes/home.js module.exports = { path: "/my_home", config: (router) => { router .get("/", (req, res) => res.send("GET HOME")) .post("/", (req, res) => res.send("POST HOME")); return router; }, }; // /routes/about.js - here we dont export path to use the filename as a path module.exports = (router) => { router .get("/", (req, res) => res.send("GET ABOUT")) .post("/", (req, res) => res.send("POST ABOUT")); return router; }; // routes/index.js const snakeCase = require("lodash/snakeCase"); const express = require("express"); module.exports = (app) => { require("fs") .readdirSync(__dirname) .forEach((file) => { if (file === "index.js") return; const router = express.Router(); const routeModule = require(require("path").join(__dirname, file)); const path = routeModule.path || "/" + (file !== "root.js" ? snakeCase(file.replace(".js", "")) : ""); const route = routeModule.config ? routeModule.config(router) : routeModule(router); app.use(path, route); }); };
And that’s it. Here we have our smarter Express router config. By using this kind of configuration — and solutions like PM2 or Nodemon to watch your app folder and restart automatically on file changes – all you have to do to add a new route is to add a file in the routes folder.
Of course, there’s plenty of space for improvements, like error checking, but this kind of feature I’ll leave to you so you can get used to the code provided and practice your coding skills while trying to achieve whichever feature you think isn’t implemented in my example. To make things easier in your journey, I’ve provided the final code in CodeSandbox. Feel free to fork and work on it.
For more information and to develop web application using Node JS, Hire Node Developer from us, as we give you high quality product by utilizing all the latest tools and advanced technology. E-mail us any clock at – hello@hkinfosoft.com or Skype us: “hkinfosoft“. To develop any custom web apps using using Node JS, please visit our technology page.
Content Source:
57 Sherway St,
Stoney Creek, ON
L8J 0J3
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
57 Sherway St,
Stoney Creek, ON
L8J 0J3
606, Suvas Scala,
S P Ring Road, Nikol,
Ahmedabad 380049
1131 Baycrest Drive,
Wesley Chapel,
FL 33544
© 2025 — HK Infosoft. All Rights Reserved.
© 2025 — HK Infosoft. All Rights Reserved.
T&C | Privacy Policy | Sitemap