Here is a unique version: "Dealing with Node.js ES6 (ESM) Modules in TypeScript can be tricky, especially when the TypeScript Compiler (TSC) fails to emit the

I am facing an issue while transpiling my TypeScript project to JavaScript. I have set the project to resolve as an ES6 Module (ESM) by using the

"module":"ES6"
configuration, but the problem persists.


This is the current setup in my tsconfig.json:
  {
    "compilerOptions": {
      "module": "es6",
      "target": "es6",
      "lib": ["es6"],
      "sourceMap": true,
    }
  }

Test Scenario Involving Two Modules:

I created a basic test scenario with two modules.

  1. The first module — module1.ts — exports only a constant, like so:

    •   export const testText = "It works!"; 
      
  2. The second module — main.ts — simply imports the exported constant from the first module:

    •   import { testText } from 'module1';
        alert(testText);
      

The resulting file for the second module (or main.js) is included in my index.html file, with the type attribute set as type="module" in the <script ...> tag, which looks like this:

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

Testing this setup in Firefox (dom.moduleScripts.enabled enabled) or Chrome Canary (Experimental Web Platform flag enabled) does not yield the expected results.

It appears that the Typescript compiler transpiles the TS

import { testText } from 'module1';
statement into the JS equivalent
import { testText } from 'module1';
. (Both are identical)

The correct ES6 import statement should be:

import { testText } from 'module1.js';
(Note the .js extension) Adding the file extension manually to the generated code makes it work as intended.

Have I made an error in my settings or is there an issue with the Typescript

"module": "es6"
configuration? Is there a way to configure tsc to automatically add .js file extensions to generated import statements?

Answer №1

This is a puzzling decision in TypeScript.

For now, you can navigate around this by explicitly stating the output file:

inside main.ts specify the .js extension and file path:

import { testText } from './module1.js';
alert(testText);

This method will locate module.ts correctly, but it will be saved with the addition of the .js extension.

Also, remember to start local files with ./ since 'bare' module names are reserved for future purposes.

Answer №2

NOTE FROM AUTHOR: "This answer was published on a different date than its original creation due to changes in TypeScript, requiring me to rewrite it twice. Dates are important here to prevent staleness and provide context for referenced technologies."

Written in December 2021

The Fix for the ``es-module-specifier`` Flag in TS, ESM, NODE stacks


Integrating ESM into Node wasn't straightforward, especially when using TypeScript for Node ES-Modules. Initially, it seemed unlikely, but now projects have evolved to support ESM in Node back-end RTE.

Previously, a workaround involved using the flag:

node --es-module-specifier-resolution=node
(Source of solution linked)

This flag served as the best solution until the release of TS 4.7 Nightly.


A Better Solution Emerges


Recent updates include new module & moduleResolution specifiers in the `tsconfig.json`, introduced during the v4.6 nightly builds and transitioned to beta with v4.7 nightly releases. The upcoming v4.7 will officially incorporate these settings.

New specifiers/settings available:
  1. "module": "NodeNext"
  2. "moduleResolution": "NodeNext"
v4.7 announcement with new settings

For optimal functionality, pair these with

"esModuleInterop": true
. This aligns well with ESM implementation and ensures proper operation with node modules.

Here's a template for the ESM `tsconfig.*.json` configuration:

    "compilerOptions": {
        "rootDir": "source",
        "outDir": "build", 
        "lib": ["ESNext"],
        "target": "ES2020",
        "module": "NodeNext",
        "moduleResolution": "NodeNext", 
        "esModuleInterop": true, // Eases ESM support
        "types": ["node"],
        "allowSyntheticDefaultImports": true,
    }

Authored on: May 22nd, 2022 8:50am PST

Adopting module & moduleResolution Specifiers



Varying versions of TS support these configurations: Beta, Nightly, or Latest. Current `typescript@latest` at v4.6 lacks this support.


TS RELEASE VERSION NPM COMMAND TO EXECUTE HAS SUPPORT?
TS Latest v4.6 npm i -D typescript@latest NO
TS Beta v4.7 npm i -D typescript@beta YES
TS Nightly v4.8 npm i -D typescript@next YES

Configure Development Environment for Latest Version

Adjust environment settings for the updated TypeScript version. For VS Code users, ensure appropriate configuration in ./.vscode/settings.json.

  {"typescript.tsdk": "./node_modules/typescript/lib"}

Configuring Runtime Environment

(In this case, Node.js)


Configuration necessity explained:

  • RTE needs explicit instructions beyond just tsconfig.json settings.

**To inform Node about executing an ECMAScript Module instead of CommonJS, utilize either of two methods:

  1. Configure the package.json file via the `"type": "module"` field.
    {
        "name": "project-name",
        "version: "2.4.16",
        "type": "module", 

        // other package.json configurations...
    }
  1. Alternatively, employ the `--input-type “module”` flag along with specific file extensions like `.ets`. This practice clarifies ESM usage.
Example: index file would be named index.ets while TSC emits index.ejs.

Understanding import nuances is crucial for efficient "ES-Module" writing. Key points summarized:

  1. Javascript file extensions required for imports.
  2. ESM imports used URIs, unlike CJS Modules' posix filepaths.
  3. Special characters should be percent-encoded in ESM.
  4. TypeScript doesn’t mandate MimeType prefixes, but they are recommended for clarity.

Best practice example for importing from Node API's & Libraries:

import EventEmitter from 'node:events';

const eEmit = new EventEmitter();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is getElementById() returning null?

I'm currently working on a JavaScript program that takes an image URL and displays it on the page by creating an <img> tag. This way, I can easily add multiple images to the page. Here is my code: <!DOCTYPE html> <html lang="en&quo ...

What is the best way to style the header of a table when scrolling in CSS?

Currently, I am facing an issue with applying the top CSS property to the thead element of a table while scrolling. I have attempted various methods but have been unsuccessful in achieving the desired outcome. Initially, I used the scroll event, however, ...

What are some ways to create a flashing effect for text in HTML and JavaScript?

Although flashing text is typically prohibited in many places, my client has requested it for a project. I need to create one line of text that flashes using HTML and JavaScript. The text should appear and disappear within seconds, repeating this cycle. I ...

What is the best way to align a series of divs vertically within columns?

Struggling to find the right words to ask this question has made it difficult for me to locate relevant search results. However, I believe a picture is worth a thousand words so...https://i.stack.imgur.com/LfPMO.png I am looking to create multiple columns ...

What is the process for invoking a JavaScript function and storing form data in a text file within an HTML document?

My HTML code is here..... <!DOCTYPE html> <html> <title>Plot</title> <head> <script type="text/javascript" src="d3.min.js"></script> <script> function filter() { var choice = document.ge ...

remove MongoDB entry using unique identifier

I am currently working on a blog project using nodejs, express, and mongodb. My goal is to delete a specific document by its ID. For instance, if I want to remove a blog post with the ID 52976b1b0855c7e81a6192e9, I would make a request to localhost:3000/bl ...

Encountering a WriteableDraft error in Redux when using Type Definitions in TypeScript

I'm facing a type Error that's confusing me This is the state type: export type Foo = { animals: { dogs?: Dogs[], cats?: Cats[], fishs?: Fishs[] }, animalQueue: (Dogs | Cats | Fishs)[] } Now, in a reducer I&a ...

Retrieving data with JQuery when encountering an XHR error

When I send a jQuery AJAX request and receive a successful response, I am able to retrieve my JSON data. However, if the response code is anything other than 200, I am unable to access the data in the jQuery callback function. This data is crucial as it co ...

Finding the correlation between SVG element IDs and JSON keysUnderstanding how to pair up

Currently, I have an SVG file that can be viewed here. My goal is to present specific data when elements within the SVG are clicked. The data is in JSON format and I am looking to match each ID of an SVG element with a key in the JSON data. If both the key ...

What is the best way to attach an event listener to a div so that clicking on it increases the width and height of the div by 20%?

I've started working on it and decided to use the same dimensions (100px by 100px) as a previous question. Right now, I'm sticking with just Javascript, but I might incorporate jQuery down the line. One big issue is that in the line (this.style.w ...

Configuring the baseUrl for Axios in a Vue.js application triggers the sending of a request

I have encountered an issue in my app where Axios automatically makes a request to the baseUrl without me explicitly making one. This occurs even when the app is loaded in the browser. In my main.js file, I have set the baseUrl using: axios.defaults.baseU ...

The picture is displayed just once, despite the fact that it was supposed to be returned 50 times within the loop

I'm encountering an issue while trying to use a for loop to render an image in a React component. The loop is not functioning as expected, resulting in the image being displayed only once on the screen even though the intention is to show the same ima ...

Retrieve the value of "this" dynamically in Typescript using a string variable

Currently my project is using Angular 10 and I have a specific requirement. In the function below, I need to pass in a filter variable dynamically so that I can extract the startValue property from it. let filter = "AgeRange"; ValidateValues(end ...

Attempting to retrieve exclusively the checked records in Vue.js

Currently, I am referring to this library for checkboxes. As I delve into the code, I notice how it is declared and utilized. Initially within the el-table, we have @selection-change="handleSelectionChange". They have initialized an empty array ...

Issue with Pebble SDK/SimplyJS failing to recognize the tab character

Currently, I am facing an interesting challenge while attempting to make my Pebble watch recognize the escape sequence character \t when sending data to my watch using SimplyJS. Here is the code snippet I have been working with: simply.scrollable(tr ...

Looking to minimize the amount of HTML code in Angularjs by utilizing ng-repeat

Working with some HTML <tr class="matrix_row" ng-repeat="process in matrixCtrl.processes | filter : { park: parentIndex } track by $index"> <td class="properties" ng-click="dashboardCtrl.currParam=0; dashboardCtrl.currentProcess=process"> ...

Issue with JavaScript JSON.parse converting string values to Infinity

Does anyone have an explanation for this peculiar behavior I encountered while using the JSON.parse() function in Javascript? Normally, when you pass a string to it, it should generate an error. For example, JSON.parse("5ffc58ed1662010012d45b30" ...

The object in three.js disappears from the scene but remains visible

I am attempting to showcase text as a sprite in three.js and aim to move the sprite along with an object. I achieve this by utilizing a canvas to generate a texture, which is then mapped using SpriteMaterial to create a sprite from it. However, when I remo ...

I am facing issues connecting my Express Node server to my MongoDB database using Mongoose

Starting my backend journey, I keep encountering the same error with my server.js --> // Step 1 - Create a folder named backend // Step 2 - Run npm init -y // Step 3 - Open in VS Code // Step 4 - Install express using npm i express // Step 5 - Create se ...

How can I declare CSS variables in Next.js components' module.css just like in global CSS?

When writing CSS in our global file, we often define variables and styles like this: :root{ --orange:#e67e22; --black:#333; --light-color:#777; --border:.1rem solid rgba(0,0,0,.2); --box-shadow:0 .5rem 1rem rgba(0,0,0,.1); } *{ mar ...