How to Fix the “SyntaxError: Cannot Use Import Statement Outside a Module”

The “SyntaxError: cannot use import statement outside a module” is a common error in JavaScript that occurs when you try to use import or export statements incorrectly. This error happens because import and export statements can only be used inside JavaScript modules, but you tried using them in a regular script file.

In this comprehensive guide, you’ll learn:

  • What are JavaScript modules and how they are different from regular scripts
  • The proper way to use import and export statements
  • Common causes of the “cannot use import outside a module” error
  • How to fix this error by converting your code into a module
  • Tools like Babel and Webpack that can help bundle modules for browsers

With the right understanding of JavaScript modules and a few fixes, you can resolve frustrating import errors and use ES6 features like a pro. Let’s dive in!

What Are JavaScript Modules?

Before ES6, JavaScript only had script files that contained code which executed immediately. ES6 introduced modular JavaScript code that allows splitting code across multiple files that can import and export between each other.

Key characteristics of JavaScript modules:

  • Modules have their own local scope and don’t pollute the global scope
  • Modules explicitly export variables, functions, classes, etc. that need to be available publicly
  • Modules can import dependencies from other modules
  • The code inside a module doesn’t execute until imported elsewhere
  • Modules are declared using the .mjs file extension or "type": "module" in package.json

This modular structure makes it easy to maintain independent components that can be combined together in different ways.

Why Import and Export Only Work in Modules

Import and export statements were introduced as part of the module system in ES6. Therefore, they can only be used inside JavaScript modules due to the way modules are defined in the language specification.

Some key reasons why import/export statements work this way:

  • Allows encapsulation – modules explicitly declare their external interface
  • Prevents polluting global namespace – keeps module implementations private
  • Enables treeshaking – dropping unused exports during bundling
  • Import statements are static – they must be analyzed at compile time
  • Provides runtime encapsulation – limits dynamic code execution for reliability

So in summary, import and export statements were purposefully designed to only work inside modules to enable key benefits like encapsulation.

Common Causes of the Import Error

There are a few common ways this error can occur when trying to use import/export statements:

Using import/export in a regular script file

This is the core cause of the error – attempting to use import or export in a file without the .mjs extension. Remember, modules must be declared as such.

Forgetting to compile modules

Modern browsers don’t natively support modules yet. So you may need to compile modules with a bundler like Webpack or use Babel to transform them into compatible code.

Mixing script code with modules

Don’t include any non-module script code like import/export statements in .mjs module files, or vice versa. Keep the code separated.

Naming files with “.js” by accident

Double check your file extensions. It’s easy to mistakenly name the file .js instead of .mjs which prevents it from being recognized as a module.

How to Fix “Cannot Use Import Outside a Module”

Let’s go over different solutions to resolve this error:

Convert the code into a proper JS module

The best fix is to convert your code into a true JavaScript module by:

  1. Rename the file’s extension from .js to .mjs
  2. Remove any global script execution logic like:
// delete app initialization code
const app = doAppStartUpTasks();
JavaScript
  1. Add an export statement for anything needed externally:
// exported function
export function calculateTax(amount) {
  return amount * 0.05; 
}
JavaScript
  1. Import any dependencies required:
import lodash from 'lodash';
JavaScript
  1. Refactor into multiple files as needed. Each file becomes its own module.

Use Babel to transform module syntax

Babel is a popular JavaScript compiler that allows you to use the latest syntax like modules and transpiles it down into compatible code.

To use Babel for modules:

  1. Install the Babel CLI and preset-env:
npm install @babel/cli @babel/preset-env
JavaScript
  1. Create a .babelrc config file:
{
  "presets": ["@babel/preset-env"] 
}
JavaScript
  1. Run Babel on your files:
npx babel script.mjs --out-file script-compiled.js
JavaScript

Now your imports and exports will work in older browsers!

Use Webpack to bundle your modules

Bundlers like Webpack combine your modules into optimized bundles the browser can interpret. It also handles transpiling and polyfilling as needed.

Configuring Webpack is outside the scope of this article, but here are the key steps:

  1. Install Webpack and CLI
  2. Create webpack.config.js
  3. Add Babel loader rule
  4. Set output bundle name
  5. Run webpack on the command line

This will output a main bundle file containing your full module tree polyfilled and transpiled!

Example Fixing the Import Error

Let’s walk through a full example resolving the “cannot use import outside a module” error:

Original file script.js:

// import statements causing error in regular script 
import _ from 'lodash';
import { calculateTax } from './tax-utils.js';

// app code
const orderTotal = 100;
const tax = calculateTax(orderTotal); 

console.log(tax);
JavaScript

This throws an error because import is used in a regular .js script file.

Updated file script.mjs:

// converted to module script with .mjs extension
import _ from 'lodash';
import { calculateTax } from './tax-utils.mjs'; 

// app code
const orderTotal = 100;
const tax = calculateTax(orderTotal);

console.log(tax);
JavaScript

Success! This fixes the error by:

  1. Renaming file to .mjs
  2. Removing unnecessary app execution logic
  3. Changing import to matching .mjs module

We’ve converted the script into a proper ES6 module to use import statements correctly.

Common Questions about Import Errors

Can I use import statements in .js files?

No, import and export statements can only be used in .mjs JavaScript module files as defined in the language specification. Attempting to use them in regular .js script files will throw errors.

What if I don’t want to use .mjs modules?

You can use Babel or Webpack to transpile ES6 module syntax into compatible legacy browser code without needing .mjs. This allows using import/export in .js files.

How do I convert a script to an ES6 module?

Make it a module by renaming the extension to .mjs, removing unnecessary executable code, adding exports, removing globals, and updating imports to other modules.

What ES6 module features require compilation?

Import and export statements, default exports, and named exports typically need to be compiled for browser support with Babel or Webpack.

Can I mix module and non-module code?

No, always keep module code with import/export statements separate from regular script code. Combining them can cause tricky errors.

Conclusion

Dealing with “cannot use import outside a module” errors in JavaScript is frustrating but solvable. Now you understand that the issue arises from misusing module-only syntax in normal script files.

By converting your code into proper .mjs ES6 modules, running it through Babel, or bundling with Webpack, you can start enjoying the benefits of modular JavaScript!

Leave a Comment