Last updated: Mar 7, 2024
Reading time·6 min
The error 'Failed to resolve module specifier "X". Relative references must
start with either "/", "./", or "../"' occurs when you try to import a module
directly in the browser, e.g. import axios from 'axios'
.
To resolve the issue, use a CDN, load the module from a relative path or use an import map.
Here is the complete error message.
Uncaught TypeError: Failed to resolve module specifier "X". Relative references must start with either "/", "./", or "../". Uncaught TypeError: The specifier “X” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.
Here is an example of how the error occurs.
This is my index.html
file.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <body> <div id="box">bobbyhadz.com</div> <script type="module" src="index.js"></script> </body> </html>
Make sure that
type is set to module
on the script
tag to be able to use the import/export
syntax.
And here is the related index.js
file.
// ⛔️ Uncaught TypeError: Failed to resolve module specifier "axios". Relative references must start with either "/", "./", or "../". import axios from 'axios'; async function getUser() { try { const response = await axios.get( 'https://randomuser.me/api/', ); return response.data; } catch (err) { console.log(err); } } console.log(getUser());
The issue in the code sample is that we are trying to import a module as
import module from 'module'
.
When importing modules in the browser, you have 3 options:
https://some-cdn.com/module-name
../module-name.js
or
../module-name.js
.If you are trying to load a third-party library, you could use a CDN such as
jsdelivr.com
.
For example, you can Google for "jsdelivr axios" to get the ESM script that you have to import from.
When you visit the jsdelivr.com
website:
Here is an example of how this works with the axios module.
import axios from 'https://cdn.jsdelivr.net/npm/axios@1.3.5/+esm'; async function getUser() { try { const response = await axios.get( 'https://randomuser.me/api/', ); return response.data; } catch (err) { console.log(err); } } console.log(await getUser());
If I start my server with npx serve .
and open my browser, I can see that the
error is resolved and the module is loaded successfully.
You can also directly import and use the module in a script
tag in your
index.html
file.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <body> <div id="box">bobbyhadz.com</div> <script type="module"> // 👇️ import and use module here... import axios from 'https://cdn.jsdelivr.net/npm/axios@1.3.5/+esm'; async function getUser() { try { const response = await axios.get( 'https://randomuser.me/api/', ); return response.data; } catch (err) { console.log(err); } } console.log(await getUser()); </script> </body> </html>
The code sample achieves the same result but imports the axios
module using a
CDN directly in the index.html
file and not in an external JS file.
You can also use a relative path when importing a module in the browser.
The example uses the following file structure.
my-project/ └── index.html └── index.js └── greet.js
Here is the code for the index.html
file.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <body> <div id="box">bobbyhadz.com</div> <script type="module" src="index.js"></script> </body> </html>
Note that type
is set to module
on the script
tag.
And here is the code for the greet.js
file.
export function greet(name) { return `hey ${name}`; }
The file uses a named export to export a function.
Here is how we can import the file in our index.js
file.
import {greet} from './greet.js'; console.log(greet('bobby hadz'));
If I issue the npx serve .
command and open the page in my browser, I can see
that everything works as expected.
Notice that we used the ./
prefix when importing the file.
This means that the greet.js
file is located in the same directory as the
index.js
file.
If the file that you are importing is located one directory up, you would use
the ../
prefix, e.g. import {greet} from '../greet.js'
.
This assumes that you have a folder structure similar to the following.
└── project-folder/ └── greet.js └── nested-folder/ └── index.html └── index.js
If the file you are importing from is located two directories up, you would use
the ../../
prefix.
I've written a detailed guide on how to import and export classes and functions in JavaScript.
Here are a couple of things to note:
// ✅ correct (specified extension) import {greet} from './greet.js'; // ⛔️ incorrect (did not specify extension) import {greet} from './greet';
named
exports.// 👇️ when using a named export in the other file import {greet} from './greet.js' // --------------------------------- // 👇️ when using a default export in the other file import greet from './greet.js'
./
or ../
.You can also set the type
attribute of a module to
importmap
to import one or more modules in the browser.
Here is the index.html
file for the example.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <!-- 👇️ setting type to importmap --> <script type="importmap"> { "imports": { "axios": "https://cdn.jsdelivr.net/npm/axios@1.3.5/+esm", "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm" } } </script> <body> <div id="box">bobbyhadz.com</div> <script type="module" src="index.js"></script> </body> </html>
Note that the type
attribute of the script
is set to importmap
.
axios
and lodash
libraries as in the previous subheading.For example, you can Google for "jsdelivr axios" to get the ESM script that you have to import from.
When you visit the jsdelivr.com
website:
Here is how you can import and use the libraries in your index.js
file.
import axios from 'axios'; import _ from 'lodash'; async function getUser() { try { const response = await axios.get( 'https://randomuser.me/api/', ); return response.data; } catch (err) { console.log(err); } } console.log(await getUser()); console.log(_.multiply(5, 5)); console.log(_.reverse(['bobby', 'hadz', 'com']));
If I issue the npx serve .
command and open the page in my browser, I can see
that everything works as expected.
The importmap
value of the type
attribute on a script
tag enables us to
specify a JSON object that instructs the browser how to resolve module
specifiers when importing modules.
<script type="importmap"> { "imports": { "axios": "https://cdn.jsdelivr.net/npm/axios@1.3.5/+esm", "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.21/+esm" } } </script>
The object provides a mapping between the text that is used as the module
specifier in the import
statement and the source where the module should be
loaded from.
script
with type
of importmap
before any other scripts on the page that rely on it.Otherwise, you'd run the code in your index.js
file before the module
specifiers have been set up.
You can read more about the importmap
value of the type
attribute in
this section
of the MDN docs.
You can also use an import map when importing local modules.
The example uses the following file structure.
my-project/ └── index.html └── index.js └── module-1.js └── module-2.js
Here is the code for the index.html
file.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> </head> <script type="importmap"> { "imports": { "m-1": "./module-1.js", "m-2": "./module-2.js" } } </script> <body> <div id="box">bobbyhadz.com</div> <script type="module" src="index.js"></script> </body> </html>
We defined an import map that maps the m-1
string to the module-1.js
file
and the m-2
string to the module-2.js
file.
Here is the code for the module-1.js
file.
export function sum(a, b) { return a + b; }
And here is the code for the module-2.js
file.
export function multiply(a, b) { return a * b; }
Finally, this is the code for the index.js
file.
import {sum} from 'm-1'; import {multiply} from 'm-2'; console.log(sum(5, 5)); console.log(multiply(5, 5));
If I issue the npx serve .
command and load the page in my browser, I can see
that everything works as expected.
I've also written an article on how to conditionally import ES6 modules in JavaScript.
You can learn more about the related topics by checking out the following tutorials: