El mensaje de error «No se puede utilizar la sentencia import fuera de un módulo» se produce cuando se encuentra la palabra clave import en un módulo JavaScript o TypeScript mal configurado.

En un entorno de ejecución del lado del servidor de JavaScript, este error suele producirse por el uso de la sintaxis import para módulos escritos en ECMAScript (ES) cuando Node.js espera la palabra clave require utilizada por el sistema de módulos CommonJS.

TypeScript admite diferentes formatos de módulos, pero los errores de codificación que confunden los enfoques ES y CommonJS para importar módulos también provocan este error.

En el lado del navegador, el error suele producirse cuando no utilizas un bundler para tus archivos de código JavaScript.

Este artículo explora estas tres fuentes de error y detalla una solución para cada entorno.

Cómo Resolver el Error en JavaScript del Lado del Servidor

Esta sección muestra cómo resolver el error en entornos JavaScript del lado del servidor.

Antecedentes

Node.js utiliza por defecto la palabra clave require del sistema CommonJS. Por lo tanto, recibirás el conocido error a menos que configures Node.js para que admita la sintaxis de módulo ES. Del mismo modo, Node.js requiere la extensión .mjs para reconocer y trabajar con módulos ES.

Solución

Como alternativa al uso de .mjs, puedes hacer que las versiones antiguas de Node.js sean compatibles con el módulo ES actual utilizando bundlers o ejecutando Node.js con la bandera --experimental-modules. Si no, podrías establecer el campo type en el archivo package.json a module de la siguiente manera:

{
  "name": "test-package",
  "version": "1.0.0",
  "type": "module",
  "main": "app.js",
  "dependencies": { }
}

(Nota: Debes incluir la propiedad type en el archivo package.json de todos los paquetes. Esta práctica facilita la identificación del sistema de módulos en uso y garantiza la coherencia entre tus bibliotecas)

Otra forma de evitar el error es asegurarte de que las sintaxis import y export son correctas y se cargan adecuadamente. Es fundamental utilizar siempre rutas de archivo relativas, exportaciones con nombre, extensiones de archivo para las exportaciones y evitar las exportaciones por defecto.

Aquí tienes un ejemplo:

//module import 
import { sampleFunction } from './sampleModule.js';

// function export
export function sampleFunction() {
     // code goes here
}

Por último, debes asegurarte de la compatibilidad de todas las bibliotecas de terceros con los módulos ES. Para ello, consulta la documentación de la biblioteca en el archivo package.json. Alternativamente, utiliza un bundler para transpilar el código de modo que un entorno JavaScript pueda entenderlo.

Cómo Resolver el Error en Entornos TypeScript

Esta sección muestra cómo resolver el mensaje de error en entornos TypeScript.

Antecedentes

Con los módulos, puedes reutilizar, organizar y compartir código entre varios archivos de un proyecto. ES admite módulos externos para compartir código entre varios archivos utilizando las palabras clave import y export.

Este error suele producirse en entornos TypeScript cuando se utiliza la sintaxis de módulos ES sin configurar TypeScript para utilizarla. Dado que TypeScript es un superconjunto de JavaScript, utiliza por defecto la sintaxis CommonJS para las importaciones, que utiliza require en lugar de import. En este caso, la sentencia import provoca el error. No obstante, es necesario configurar correctamente TypeScript para que admita módulos ES.

También puedes encontrarte con este error si utilizas una extensión de archivo incorrecta. Por ejemplo, al utilizar TypeScript en un entorno Node.js con sintaxis de módulos ES, el módulo que quieras importar debe tener la extensión de archivo .mjs en lugar de la habitual .js.

Otra fuente habitual del error es la configuración incorrecta del campo module en tus archivos tsconfig.json o package.json cuando utilizas bundlers como Webpack. Sin embargo, puedes utilizar bundlers para módulos ES en TypeScript configurando los campos module y target en el archivo tsconfig.json a ECMAScript. Entonces, Webpack entenderá el entorno de destino y utilizará las extensiones de archivo correctas al transpilar el código.

Solución

Para cargar módulos ES utilizando un cargador de módulos como RequireJS o un bundler como Webpack, añade lo siguiente al archivo tsconfig.json:

{
  "compilerOptions": {
    "module": "es20215",
    "target": "es20215",
    "sourceMap": true
  }
}

En la parte compilerOptions del código anterior, los campos module y target están configurados para utilizar un módulo es20215. Con estas adiciones, puedes utilizar las declaraciones import y export en un entorno TypeScript sin que se produzca el error.

Como TypeScript utiliza CommonJS por defecto, si no modificas el archivo tsconfig.json en consecuencia, aparecerá el mensaje de error.

Afortunadamente, una vez que hayas configurado los campos module y target para utilizar un módulo ECMAScript, puedes utilizar la sentencia export para exportar una función o variable de un módulo y la sentencia import para cargar otro módulo en el ámbito del actual. Este proceso ocurre en el siguiente código:

// sum.ts
export function sum(a: number, b: number, c: number): number {
  return a + b + c;
}

// main.ts
import { sum } from './sum';
console.log(add(4, 4, 9));

Si utilizas una versión anterior de Node.js, puedes activar la compatibilidad con módulos ES ejecutando tu código con la bandera --experimental-modules. También debes utilizar un bundler como Webpack, Browserify o Rollup para empaquetar todo el código ES y enviarlo a un único archivo. Asegúrate de que está en una versión que los navegadores y las versiones antiguas de Node.js puedan entender y configura un archivo Webpack.config.js en el root de tu proyecto que especifique el tipo de módulo.

Aquí tienes un ejemplo extraído de la documentación de Webpack:

module.exports = {
  entry: './src/index.ts',
  output: {
    filename: 'bundle.js',
   path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    extensions: ['.ts', '.js', '.mjs']
  },
  module: {
    rules: [
      {
        test: /.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  experiments: {
    outputModule: true
  }
};

El código compilado se envía a un archivo bundle.js en el directorio dist del directorio root del proyecto.

También puedes utilizar polyfills como es-module-shims para dirigirte a navegadores antiguos que no admiten las sentencias import y export de los módulos ES.

Cómo Resolver el Error en JavaScript del Lado del Navegador

Esta sección te muestra cómo resolver el error en entornos JavaScript del lado del navegador.

Entorno

La mayoría de los navegadores modernos, incluidos Chrome, Firefox, Edge y Safari, soportan módulos ES, por lo que no necesitarás utilizar polyfills, bundlers o transpiladores del navegador.

Tampoco los necesitarás si utilizas las bibliotecas frontend basadas en JavaScript React o Vue, porque admiten por defecto los campos ES imports y exports. Sin embargo, los navegadores más antiguos no admiten la sintaxis ES, por lo que necesitan estas herramientas para la compatibilidad entre plataformas.

La razón más frecuente del error en un navegador antiguo es cuando los archivos HTML de una página no contienen el atributo type="module". En este caso, el error se produce porque el JavaScript que se ejecuta en la web no incluye soporte por defecto para la sintaxis de módulos ES. Para el código JavaScript enviado a través de la red, podrías encontrarte con un error de compartición de recursos de origen cruzado (CORS) al intentar cargar un módulo ES desde un dominio diferente.

Solución

Para evitar el error de módulo en un navegador antiguo, asegúrate de que estás utilizando el atributo correcto de la etiqueta scripttype="module" —  en el archivo root HTML. Alternativamente, puedes utilizar Webpack para transpilar el código de modo que los navegadores antiguos puedan entenderlo.

Para utilizar el atributo type="module", incluye la siguiente línea en tu archivo root HTML:

<script type="module" src="app.js"></script>

Es igualmente importante que te asegures de que las rutas de los archivos import son válidas y de que utilizas la sintaxis import correcta.

Además, puedes visitar sitios como Can I Use para confirmar la compatibilidad de los navegadores con los módulos ES.

Por último, dado que el uso de la extensión de archivo .js es una práctica habitual, puedes establecer el atributo type en la etiqueta script del archivo HTML del módulo como solución. Establecer este atributo en module indica al navegador que ignore la extensión .js y trate el archivo como un módulo.

Resumen

El error «No se puede utilizar la sentencia import fuera de un módulo» puede aparecer por varias razones, dependiendo de si estás en un entorno JavaScript del lado del navegador o del lado del servidor. La sintaxis incorrecta, las configuraciones inadecuadas y las extensiones de archivo no compatibles siguen siendo algunas de las fuentes más comunes de este error.

Aunque la mayoría de los navegadores modernos admiten módulos ES, debes asegurarte de que los navegadores antiguos sean compatibles. Bundlers como Webpack te permiten compilar todo el código fuente con sus dependencias en una única salida que los navegadores antiguos puedan entender.

Recuerda añadir el atributo type="module" en el archivo HTML para informar al navegador de que el módulo es un módulo ES. Por último, aunque utilizar la extensión .js para CommonJS es la práctica por defecto, puedes utilizar la extensión .mjs para permitir la importación de módulos ES.

¿Tienes una aplicación JavaScript que necesitas poner online pero no quieres gestionar tú mismo los servidores? Las plataformas de Alojamiento de Aplicaciones y Alojamiento de Bases de Datos de Kinsta podrían ser la respuesta. Incluso puedes combinar estos servicios con el Alojamiento de Sitios Estáticos de Kinsta para que el front-end de tu aplicación se sirva gratuitamente.