269

Trying to implement a module following the official handbook, I get this error message:

Uncaught ReferenceError: exports is not defined

at app.js:2

But nowhere in my code do I ever use the name exports.

How can I fix this?


Files

app.ts

let a = 2;
let b:number = 3;

import Person = require ('./mods/module-1');

module-1.t

 export class Person {
  constructor(){
    console.log('Person Class');
  }
}
export default Person;

tsconfig.json

{
   "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": true,
        "outDir": "scripts/"
    },
    "exclude": [
        "node_modules"
    ]
}
4
  • 1
    Are you sure you did not type exports with an s at the end instead of export? That would explain the error message as with s is wrong.
    – Igor
    Commented Mar 27, 2017 at 10:18
  • 2
    i type export not exports
    – user6600549
    Commented Mar 27, 2017 at 10:29
  • any example from repositorie that gona work 10000%
    – user6600549
    Commented Mar 27, 2017 at 10:41
  • Where is this being run? On a web page? On a node.js server? You will need a module loader in the run-time environment that the javascript finally runs in. From the compiler flags you are using commonjs. I am not that familiar with commonjs, but you will need to get commonjs set up before Typescript modules will work or you will need to change to another module loader (like require.js) and get that one set up. Commented Apr 19, 2017 at 19:23

32 Answers 32

125

Add the following line before other references to JavaScript. This is a nice little hack.

<script>var exports = {};</script>
3
  • 3
    @ChuckLeButt Hope this helps stackoverflow.com/questions/19059580/… Commented Apr 25, 2018 at 23:43
  • 54
    I hate that this works! And it definitely works. Isn't there a way to get TypeScript to transpile into something that Node expects? Is it even Node that's complaining? Or is it the browser? I can't stand not understanding what the problem actually is. Commented Feb 14, 2020 at 18:08
  • Won't this cause clashes between modules exporting similar function names? Like I can imagine two modules using common verb names for example exports.get = whatever, leading to the latest import deleting the rest. Commented May 1 at 7:27
118

EDIT:

This answer might not work depending if you're not targeting es5 anymore, I'll try to make the answer more complete.

Original Answer

If CommonJS isn't installed (which defines exports), you have to remove this line from your tsconfig.json:

 "module": "commonjs",

As per the comments, this alone may not work with later versions of tsc. If that is the case, you can install a module loader like CommonJS, SystemJS or RequireJS and then specify that.

Note:

Look at your main.js file that tsc generated. You will find this at the very top:

Object.defineProperty(exports, "__esModule", { value: true });

It is the root of the error message, and after removing "module": "commonjs",, it will vanish.

20
  • 35
    Yeah I recompiled my .ts file and the error still exists after commenting out "module": "commonJs", :(
    – Ari Seyhun
    Commented Sep 22, 2017 at 9:17
  • 21
    If installing CommonJS will make this error go away, then how does one actually install CommonJS? I have spent the better part of an hour Googling, and I cannot find any instructions on how to do so. Can someone please explain?
    – Sturm
    Commented Oct 8, 2018 at 14:45
  • 1
    @Sturm My answer may be worded confusingly. CommonJS is only a specification. You can find a (not necessarily exhaustive) list of implementations here: en.wikipedia.org/wiki/CommonJS
    – iFreilicht
    Commented Oct 13, 2018 at 22:00
  • 2
    I have module: amd, not module: commonjs, and I have this line in my transpiled .js file.
    – pabrams
    Commented Apr 5, 2019 at 16:45
  • 4
    If you have target as ES3 or ES5 in your tsconfig.json then typescript will automatically set your module to CommonJS if it's not defined. Removing module isn't enough, you need to set something else instead - see typescriptlang.org/docs/handbook/compiler-options.html
    – Jake
    Commented Jul 2, 2019 at 6:17
91

A solution:

Remove "type": "module" from package.json.

6
  • 9
    but why does this help?
    – DauleDK
    Commented Oct 8, 2020 at 13:07
  • 1
    @DauleDK because we use Webpack to bundle app, this field has usage in node.js engine. in webpack config we ues common module system Commented Oct 8, 2020 at 14:26
  • 92
    Without this the "import" can't be used.
    – mloureiro
    Commented Mar 26, 2022 at 17:09
  • 3
    Here's a good explanation: bobbyhadz.com/blog/… In NodeJS you would instruct TypeScript to generate CommonJS syntax when compiling but with "type": "module" you instruct nodejs to use ES6 modules (which you have compiled away). Commented Aug 30, 2022 at 11:39
  • 1
    it really depends: maybe the OP needs that to interop with ESM packages, consider the original trail that got him to this error... it is a good solution, but really it depends on the issue OP's trying to solve. Commented Jun 7, 2023 at 13:10
51

This is fixed by setting the module compiler option to es6:

{
  "compilerOptions": {     
    "module": "es6",
    "target": "es5",    
  }
}
5
  • This was it for me. Using Laravel Mix with Typescript.
    – Orchis
    Commented Apr 30, 2021 at 14:41
  • 4
    if you use nodejs you need to add "moduleResolution": "Node" to tsconfig.json
    – mixalbl4
    Commented Oct 4, 2021 at 7:48
  • i am building a nodejs-based command line tool and this worked for me
    – ndp
    Commented Nov 29, 2022 at 5:12
  • Why the different versions for module and target?
    – Timo
    Commented Jan 21 at 8:10
  • @mixalbl4 to be precise you need to add it to "compilerOptions" in tsconfig
    – Timo
    Commented Jan 21 at 18:11
20

npm install @babel/plugin-transform-modules-commonjs

and add to to .babelrc plugins resolved my question.

1
  • Welcome to SO. Please share a more detailed code solution. What do I have to add to .babelrc? Is this solution for switching from type commonjs to Module?
    – Timo
    Commented Jan 21 at 18:13
16

I ran into this issue a few weeks ago and used the exports hack above in the short term but finally figured out another way around this that's working great for me.

So unlike some of the other responses above, I actually wanted the code I'm compiling to be a module. By setting "target": "es6", "module": "esnext" and then linking to my compiled JS file with type="module" instead of type="text/javascript", my compiled code no longer has the Object.defineProperty(exports, "__esModule", { value: true }); line and it's still a module 🎉

My tsconfig:

{
  "compilerOptions": {
    "target": "es6",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "esnext",
    "moduleResolution": "node",
    "lib": ["es2016", "esnext", "dom"],
    "outDir": "build",
    "strict": true,
    "strictNullChecks": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true,
  },
  "include": ["src/index.ts"],
  "exclude": ["build"]
}

My link to my compiled code in HTML head tags:

<script src="../build/index.js" type="module" defer></script>

As a bonus, now I can also import anything that I export in that index.js file in a separate type="module" script down below the main HTML body code:

 <script type="module">
   import { coolEncodingFunction, coolDecodingFunction } from "../build/index.js";
   /* Do stuff with coolEncodingFunction and coolDecodingFunction */
   /* ... */
</script>
2
  • 1
    <script Type="Module" with "module": "ES2020" worked for me.
    – AltWouss
    Commented Jun 18, 2021 at 10:34
  • Error: tsconfig.json(8,15): error TS6046: Argument for '--module' option must be: 'none', 'commonjs', 'amd', 'system', 'umd', 'es6', 'es2015', 'esnext'. Commented Nov 18, 2021 at 19:41
11

my solution is a sum up of everything above with little tricks I added, basically I added this to my html code

<script>var exports = {"__esModule": true};</script>
<script src="js/file.js"></script>

this even allows you to use import instead of require if you're using electron or something, and it works fine with typescript 3.5.1, target: es3 -> esnext.

3
  • 12
    some progress here, the error just changed to be app.js:3 Uncaught ReferenceError: require is not defined Commented Feb 16, 2020 at 18:37
  • 1
    this happens if nodeIntegration is set to false when creating the window, the error happens because you updated your electronJS or you're following an outdated source. nodeIntegration was true by default, now it's false, so you have to enable it manually if you want to access nodeJS in renderer process. See [Electron require() is not defined][1] [1]: stackoverflow.com/questions/44391448/… Commented Feb 16, 2020 at 18:51
  • 1
    I'm not using electron, anyway I solved in my case by adding parcel to make bundle stuff and removed other tricky ways Commented Feb 16, 2020 at 18:56
10

I had the same problem and solved it adding "es5" library to tsconfig.json like this:

{
    "compilerOptions": {
        "target": "es5", //defines what sort of code ts generates, es5 because it's what most browsers currently UNDERSTANDS.
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true, //for angular to be able to use metadata we specify in our components.
        "experimentalDecorators": true, //angular needs decorators like @Component, @Injectable, etc.
        "removeComments": false,
        "noImplicitAny": false,
        "lib": [
            "es2016",
            "dom",
            "es5"
        ]
    }
}
7

In package.json, add "type": "module"

In terminal type in

npx tsc --init

It will create a tsconfig.json.

In tsconfig.json,

  1. change "target": "es5" to "target": "es6"
  2. comment out //"module": "commonjs",
  3. uncomment "moduleResolution": "node",

You should be good to go.

In package.json, create a build script:

"build": "tsc -p tsconfig.json"

Then, when you want to build, you just compile npm run build

then execute and should be good

1
  • This will break imports: error TS2792: Cannot find module '@jest/globals'. Did you mean to set the 'moduleResolution' option to 'node',
    – Ian Smith
    Commented Jun 28 at 6:06
5

For people still having this issue, if your compiler target is set to ES6 you need to tell babel to skip module transformation. To do so add this to your .babelrc file

{
  "presets": [ ["env", {"modules": false} ]]
}
2
  • 1
    Thanks man! I've been trying to work with older code base which dump all into global and scripts are included in browser with the <script> tag. I was hoping to use module along with older code and it seems like that is not possible. This at least allow me to use ES6 and let me deal with export later.
    – huggie
    Commented Feb 9, 2018 at 7:01
  • 2
    doing this I got the following error: Using removed Babel 5 option: .modules - Use the corresponding module transform plugin in the plugins option. Check out babeljs.io/docs/plugins/#modules
    – chharvey
    Commented Apr 6, 2019 at 15:01
5

I had this same error too. In my case it was because we had an old-fashioned import statement in our TypeScript AngularJS project like this:

import { IAttributes, IScope } from "angular";

which was compiled to JavaScript like this:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

This was needed back in the old days because we then used IAttributes in the code and TypeScript wouldn't have known what to do with it otherwise. But after removing the import statement, and converting IAttributes to ng.IAttributes those two JavaScript lines disappeared - and so did the error message.

4
  • 1
    How would that work for a Typescript type? I have to import it, so Typescript compiles it.
    – Tigerware
    Commented Jul 8, 2019 at 9:39
  • What do you mean by "Typescript type"? If it's an integeral type known by TypeScript - such as number or string - then you can use that right away. If you define your own types in a module, check this: typescriptlang.org/docs/handbook/modules.html
    – MatX
    Commented Jul 8, 2019 at 11:18
  • 1
    I meant the type definitions of an external library like @types/jquery from npmjs.com/package/@types/jquery . To make the $ variable usable from within my Typescript code, I put this in my code: import * as $ from "jquery";
    – Tigerware
    Commented Jul 8, 2019 at 11:25
  • I am targeting es5, do I need another library like requirejs to make this work?
    – Tigerware
    Commented Jul 8, 2019 at 11:26
4

I had similar issue as the original poster of the question:

I better tell you what mistakes I made and how I corrected it, that might help someone.

I had javascript nodejs project and converted it to typescript.

Previously in package.json I had "type":"module" when I was running in JavaScript.

When I converted it to TypeScript project and started converting files in .ts files and started running using following command:

npx tsc test.ts && node test.ts

I would get the above error.

I got rid of the error by simply removing the "type":"module" from package.json

My tsconfig.json would like below:

{
    "compilerOptions": {
        "target": "esnext",
        "lib": ["es6", "es5", "es7", "dom"],
        "allowJs": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "es6",
        "outDir": "./build",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "skipLibCheck": true
    },
    "exclude": ["node_modules", "build"]

I am using node 14 and TypeScript 4.2.4

0
4

I have this issue too. then I just change "module": "commonjs" to "module": "ESNext" everything is working fine.
this my tsconfig.json:

{
    "compilerOptions": {
      "module": "ESNext",
      "esModuleInterop": true,
      "target": "ESNext",
      "moduleResolution": "node",
      "sourceMap": true,
      "outDir": "dist",
    },
    "lib": ["ESNext"],
  }

I hope it can solve your problem!

0
3

for me, removing "esModuleInterop": true from tsconfig.json did the trick.

2
  • How does removing it work since exports can ONLY be used if esModuleInterop is set to true ? Commented Jan 11, 2021 at 12:48
  • This worked for me (removed the above error). I'm using ESM with typescript (with jest), so I don't want exports.
    – crimbo
    Commented Jan 20, 2021 at 23:41
3

First, go to your index.html in your public folder find the reference of the script <script src="myScript.js"></script> and add type="module"

Like so:

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

Secondly, in your tsconfig.json make sure target is set to es5 and module to es2015

 "compilerOptions": {
    "target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    /* Modules */
    "module": "es2015", /* Specify what module code is generated. */
}

important: make sure to import with the .js extension e.g. import Piece from './classes/piece.js'

3

I hit this error shortly after switching to "Node 16 + ESM + strict" tsconfig.json.

I think the ESM change was the bit that caused it.

I had to bisect the file to figure out the root cause:

exports.webhookTaskProcessor = functions.firestore
  .document("items/{itemId}/tasks/{taskId}")
  .onCreate((_change, context) => {
    processItemTasks(context.params.itemId);
  });

This fixed it:

export const webhookTaskProcessor = functions.firestore
  .document("items/{itemId}/tasks/{taskId}")
  .onCreate((_change, context) => {
    processItemTasks(context.params.itemId);
  });

Would be rad if the error message was a little more helpful. I hope this breadcrumb is useful to you.

2

Simply add libraryTarget: 'umd', like so

const webpackConfig = {
  output: {
    libraryTarget: 'umd' // Fix: "Uncaught ReferenceError: exports is not defined".
  }
};

module.exports = webpackConfig; // Export all custom Webpack configs.
2

Note: This might not be applicable for OP's answer, but I was getting this error, and this how I solved it.

So the problem that I was facing was that I was getting this error when I retrieved a 'js' library from a particular CDN.

The only wrong thing that I was doing was importing from the CDN's cjs directory like so: https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/cjs/popper.min.js

Notice the dist/cjs part? That's where the problem was.

I went back to the CDN (jsdelivr) in my case and navigated to find the umd folder. And I could find another set of popper.min.js which was the correct file to import: https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js.

2

To solve this issue, put these two lines in your index.html page.

<script>var exports = {"__esModule": true};</script>
<script type="text/javascript" src="/main.js">

Make sure to check your main.js file path.

1
  • This only works if you don't have any require() statements in your code. Commented Oct 9, 2020 at 11:02
2

If you are are using webpack along with babel-loader and @babel/preset-env, then make sure to callout loose and modules. So instead of the following:

"presets": ["@babel/preset-env"]

instead do

"presets": [["@babel/preset-env", { "loose": true, "modules": false }]],
0
1

For some ASP.NET projects import and export may not be used at all in your Typescripts.

The question's error showed up when I attempted to do so and I only discovered later that I just needed to add the generated JS script to the View like so:

<script src="~/scripts/js/[GENERATED_FILE].Index.js" asp-append-version="true"></script>
1

I think the problem may be the mismatched configuration.

  1. Working solution 1 below give you a correct configuration for ES Module.
  2. Working solution 2 below give you a correct configuration for CommonJS.
  3. Mixed solution 1+2 give you an Error.

I just post partial content here, for clarity. Github project https://github.com/jmmvkr/ts-express/ have a complete set of files demonstrate the working solution 1 and solution 2.

Working solution 1, ES Module

/* Configuration for ES Module */

// tsconfig.json
{
    "compilerOptions": {
        "module": "es6", // or "esnext"
    }
}
// package.json
{
    "type": "module", // type is module
}

Working solution 2, CommonJS

/* Configuration for CommonJS */

// tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
    }
}
// package.json
{
    "type": "", // type is NOT module
}

Mixed, do NOT work

/* Mixed, got ReferenceError: exports is not defined in ES module scope */

// tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
    }
}
// package.json
{
    "type": "module", // type is module
}
1

Not answering the question directly, but no stackoverflow thread mentionned this case, took me a while to debug, and so adding it here in case it could help someone in the future.

I had the error "exports is not defined" coming from an imported NPM module. Changing my typescript config did nothing as I had no control over the imported third-party code. The problem was an invalid import syntax for that package. For example, I had imported "@mui/material/TextField/TextField", yet the correct import was supposed to be "@mui/material/TextField".

1

So this is a super generic TypeScript error and this StackOverflow question is the first result for various queries I made researching my problem. It has 385k views.

For those with Angular / TypeScript and an Angular Library using ng-packagr seeing a generic "ReferenceError: exports is not defined", you'll need to define public-api.ts for each feature/component/service such that you include it with index.ts such as found in this repo for this article

  • Node 16 or 18 (18 is LTS next week)
  • Angular 2+ (14 currently)
  • TypeScript 4.6.4-4.8.2

Several shallow examples go something like this referencing Creating Libraries

ng new workspace --no-create-application
cd workspace
ng generate app home --routing=true --style=scss
ng generate app admin --routing=true --style=scss
ng generate library lib
... # include your library 'lib' into your application 'home'
ng build lib --watch &
ng serve home --open

What's not directly explained is your index.ts and public-api.ts files need to be in each feature/component/service. Such as these example features A, B, and C in the repo below if you have a complex library. repo has the following:

  • src/lib
    • feature-a
      • index.ts (referencing only ./public-api)
      • public-api.ts (referencing only exported files in the directory)
    • feature-b
      • index.ts (referencing only ./public-api)
      • public-api.ts (referencing only exported files in the directory)
    • feature-c
      • index.ts (referencing only ./public-api)
      • public-api.ts (referencing only exported files in the directory)
1

Hello o fix this probleme by using this :

{
  "compilerOptions": {
    "target": "es6",  // 👈️ set this to es6
    // "module": "commonjs", // 👈️ REMOVE this (if browser env)
  }
}
0

Try what @iFreilicht suggested above. If that didn't work after you've installed webpack and all, you may have just copied a webpack configuration from somewhere online and configured there that you want the output to support CommonJS by mistake. Make sure this isn't the case in webpack.config.js:

module.exports = {
  mode: process.env.NODE_ENV || "development",
  entry: { 
    index: "./src/js/index.ts"
  },
  ...
  ...
  output: {
    libraryTarget: 'commonjs',         <==== DELETE THIS LINE
    path: path.join(__dirname, 'build'),
    filename: "[name].bundle.js"
  }
};
0

Had the same issue and fixed it by changing the JS packages loading order.

Check the order in which the packages you need are being called and load them in an appropriate order.

In my specific case (not using module bundler) I needed to load Redux, then Redux Thunk, then React Redux. Loading React Redux before Redux Thunk would give me exports is not defined.

0

I had the same issue, but my setup required a different solution.

I'm using the create-react-app-rewired package with a config-overrides.js file. Previously, I was using the addBabelPresets import (in the override() method) from customize-cra and decided to abstract those presets to a separate file. Coincidentally, this solved my problem.

I added useBabelRc() to the override() method in config-overrides.js and created a babel.config.js file with the following:

module.exports = {
    presets: [
        '@babel/preset-react',
        '@babel/preset-env'
    ],
}
0

I stuck with such error in a SSR client part because it used a lib which was built with tsconfig.json compilerOptions as target: ES5 what brought using CommonJS for module resolution tsc CLI Options Compiler Options: target === "ES3" or "ES5" ? "CommonJS" : "ES6". While it used the target ESNext.

0

As ES5/ES2009 doesn't support modules (import/export/require) on the client / browser you have to use libraries, which bundle the modules into a single file, which can be included via <script> tag, such as

See also this answer.