In modern web development, optimizing application performance is crucial for providing a seamless user experience. One effective technique to achieve this is called code splitting. Code splitting involves breaking down your JavaScript codebase into smaller, more manageable chunks that can be loaded on-demand rather than all at once. Let's explore more about Code splitting by deep dying in this article. Let's get started :)
What is code splitting?
Code splitting is a technique used to improve the performance of your application by splitting your code into smaller chunks that can be loaded separately.
Imagine you have a big React Application with multiple components. Instead of bundling all your code into a single large file, you can segment it into smaller bundles based on different routes or components.
This means that when users access your app, they only fetch the essential code for the initial view, with additional code loading dynamically as they navigate further.
This can significantly reduce the initial load time of your application because users don't have to download everything upfront.
Why is code splitting important?
By default, React bundles all JavaScript code into one file for simplicity during development. However, this approach can result in larger file sizes, causing slower load times, especially on slower networks or mobile devices.
Alternatively, code splitting breaks down the code into smaller chunks that load as needed. This optimizes performance by reducing initial load times, as users only download the necessary code for the specific parts of the application they are using.
Implementing code splitting offers several key benefits:
Faster Initial Load Times: By loading only essential code upfront, users experience faster initial page loads, which is crucial for retaining user engagement and reducing bounce rates.
Improved Performance: Smaller code bundles result in quicker parsing and execution times, enhancing the responsiveness of your application.
Efficient Resource Management: Code splitting enables more efficient resource allocation by loading code only when it's needed. This can lead to cost savings, especially in cloud-based hosting environments.
Implementing Code Splitting in React
There are several ways to implement code splitting in a React application. Let’s explore these methods:
React.lazy() with Suspense and Fallback
This method helps in the lazy loading of a component. It means that we can define components that can be imported dynamically into the application. This helps us reduce the bundle size because we are delaying the loading of the component that might be used later in the application. Syntax for lazy load.
const ContactUs = React.lazy(() => import('./contact'));
But there is a catch, what if our import takes time to load? Your application might break at that time. In this case
React.Suspense
comes into the picture.We need to always use the Lazy component within the
Suspense
component. It makes sure your app stays smooth while waiting for a lazily loaded component to load by allowing you to specify the loading indicator until our component is ready to render.import React, { Suspense, lazy } from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Home from "./home"; const About = lazy(() => import('./about')); const ContactUs = lazy(() => import('./contact')); const App = () => ( <Router> <Suspense fallback={<div>Loading...</div>}> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<ContactUs />} /> </Routes> </Suspense> </Router> ); export default App;
The
fallback
props take any React element that we want to show while the lazy component is loading.Named Export
Named exports allow you to export multiple values (functions, variables, objects, Components) from a module under specific names.
// About.js import React from 'react'; export const AboutProfile = () => { return <p>About Profile</p>; }; export const AboutActivity = () => { return <p>About Activity</p>; }; export const About = () => { return ( <div> <h2>About Component</h2> <AboutProfile /> <AboutActivity /> </div> ); };
React.lazy
currently only supports default exports. But if you want to import the above module in lazy which is the named exports. You can achieve it with the following syntax.const About = React.lazy(() => import('./About').then((module) => { return { default: module.About }; }) );
The above syntax allows the
About
component to be lazily loaded when it's needed in the application, improving initial load times by splitting the bundle and loading components on demand. This ensures that tree shaking keeps working and you don’t pull in unused components.Dynamic Import
Whenever we import a module or third-party library, we generally import it synchronously like in the example below :
import { multiply } from './mathUtils'; console.log(multiply(8,9));
When we are importing the file synchronously. It means that the initial bundle file will have this import. But we can import any files based on our requirements. Now, what does it mean? It means we should only import if the application demands them. Let's check this out with the below example.
import React from 'react'; const MultiplyComponent = () => { const multiplyValue = () => { import("./mathUtils").then((module) => { console.log(module.multiply(8, 9)); }); }; return ( <button onClick={multiplyValue}>Multiply Value</button> ); }; export default MultiplyComponent;
Here, we are dynamically importing a module that returns a promise and we can use
Async-Await
or.then and .catch
methods to handle the promise which returns us to the methods that are available in the module.Dynamic imports are useful for loading modules only when they are needed, which can improve initial load times and overall application performance.
Tree Shaking
Tree shaking is a technique used by modern JavaScript bundlers (like webpack) to eliminate dead code (unused modules) from the final bundle. Let's understand this with some examples:
// Module with some functions export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; export const multiply = (a, b) => a * b;
In the example above, three functions have been exported by name. These functions can be accessed by importing them directly using their respective function names.
// Main application imports only 'add' function import { add } from './mathUtils'; console.log(add(2, 3)); // Tree shaking will eliminate 'subtract' and 'multiply' function since it's not used.
In this scenario, we've specifically imported and utilized only the
add
function frommathUtils
. By doing so, unnecessary functions frommathUtils
are excluded from the final JavaScript bundle during the bundling process.This optimization reduces the overall size of the bundle that users need to download, resulting in enhanced loading speeds for websites and applications.
For further information on Tree shaking, you can refer to this article.
Conclusion
Code splitting is a powerful technique to make React apps faster by dividing the code into smaller parts that load only when needed. This reduces wait times for users and makes the app smoother to use, while also keeping the code organized and efficient.
That's all for this topic. Thank you for reading! If you found this article helpful, please consider liking, commenting, and sharing it with others.