Introduction
I'm a bit ashamed to admit it but I didn't know (or care) about the difference of how import
and require
worked under the hood until recently.
- I knew
import
was part of ES6 and both can be used for consuming JavaScript files. - I also knew that the syntax was different and I preferred Import's simpler syntax, but didn't think twice beyond that.
I guess I should've been a bit more inquisitive, but frankly I didn't really feel like I needed to know.
But this changed recently while I was playing around with the new React suspense and lazy loading APIs. I stumbled upon the requirement to use import()
. I started having questions about the difference between the various ways we can import and consume modules.
So here goes:
Require
This is the old way of consuming JavaScript files. It was introduced in 2009 and is part of commonJS - a module (AKA 'file') formatting system. It became a built-in function in nodeJS.
Require is just a function. It takes a string path and returns whatever is being exported from the specified path.
Being a function, it can be dynamically used inside of other functions or nested blocks like
if
statements.It is processed at run-time, like any other function.
Modules loads synchronously. Which is great server-side but not for front-end, which is why Webpack applies bundle magic to wrap
require
'd code inside of a IIFE (I am underplaying the complexity and I still don't 100% get this part but that is my TL;DR understanding).
ES6 import
This is the modern syntax introduced in JavaScript ES6.
It is static, meaning that exports are known at build-time. This means that you cannot run imports conditionally.
All imports are hoisted (moved to the top of their scope prior to execution) regardless of where you write this.
As they live on the top level of the scope,
import
cannot be nested.The static nature of ES6 import allows static analysis. This results in modules being imported to be analysed with static analysis tools. This in turn allows optimisations such as 'tree-shaking'.
Using import as a function
While import
is great, there are situations where we want to load modules dynamically.
For example, when using React suspense we want to dynamically load a module only when it is ready using the lazy
API. We can't use import
to do this.
import {lazy} from React
// Import here wouldn't run.
const loadLazyModule = lazy(() => {
import thisModuleWontWork from 'myModule';
})
For this situation you can use the import
keyword as a function ie. import()
It allows us to dynamically load the module.
It allows this by returning a promise that resolves into the module object which contains its exports.
This expression can be called from anywhere in our code.
This is how we can use this with React's lazy
API.
import {lazy} from React
// Using the import() expression we can load modules dynamically
const loadLazyModule = lazy(() => import('myModule'))
Takeaways
In a nutshell, all three work differently - it isn't just a matter of syntax.
-
require
is a function that is evaluated modules at run-time. -
import
is a static syntax that evaluates modules at build-time. -
import()
is a function that allows us to dynamically load modules.
Great resources on the topic:
- Stack overflow thread on the differences
- Youtube video on the difference between
require
andimport
- This amazing intense article by Tyler McGinnis on JavaScript Modules
Top comments (0)