webpack imported module is not a constructor
Asked Answered
I

9

53

I created a small JS module which I intend to make an npm package, but for now is just on GitHub. This module is written in ES6 and SCSS, and is thus relying on webpack and babel for transpilation.

To test it, I created a separate project with a similar setup (webpack and babel). After npm installing my module, when trying to import it into my index.js, I get the following error in Chrome Developer Tools: (with x being my module's name)

index.js:11 Uncaught TypeError: x__WEBPACK_IMPORTED_MODULE_1___default.a is not a constructor
    at eval (index.js:11)
    at Object../src/index.js (main.js:368)
    at __webpack_require__ (main.js:20)
    at eval (webpack:///multi_(:8081/webpack)-dev-server/client?:2:18)
    at Object.0 (main.js:390)
    at __webpack_require__ (main.js:20)
    at main.js:69
    at main.js:72

I've looked through countless answers and tried countless solutions, to no avail. My module's setup is as follows.

.babelrc

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["ie >= 11"]
      }
    }]
  ],
  "plugins": [
    "transform-es2015-modules-commonjs",
    "transform-class-properties"
  ]
}

webpack.common.js

const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const cleanWebpackPlugin = require('clean-webpack-plugin')

const baseSCSS = new ExtractTextPlugin('main/_base.css')
const themeSCSS = new ExtractTextPlugin('main/_theme.css')

module.exports = {
  entry: {
    example: [
      path.join(__dirname, 'src', 'example', 'index.js')
    ],
    main: [
      'idempotent-babel-polyfill',
      path.join(__dirname, 'src', 'index.js')
    ]
  },
  output: {
    path: path.join(__dirname, 'dist'),
    filename: path.join('[name]', 'index.js')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        }
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          }
        )
      },
      {
        test: /\_base-scss$/,
        use: baseSCSS.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          }
        )
      },
      {
        test: /\_theme-scss$/,
        use: themeSCSS.extract(
          {
            fallback: 'style-loader',
            use: ['css-loader', 'sass-loader']
          }
        )
      }
    ]
  },
  plugins: [
    new cleanWebpackPlugin('dist', {}),
    new ExtractTextPlugin({ filename: path.join('example', 'style.css') }),
    baseSCSS,
    themeSCSS,
    new HtmlWebpackPlugin({
      inject: false,
      hash: true,
      template: path.join(__dirname, 'src', 'example', 'index.html'),
      filename: path.join('example', 'index.html')
    })
  ]
}

webpack.prod.js

const merge = require('webpack-merge')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const webpack = require('webpack')
const common = require('./webpack.common.js')

module.exports = merge(common, {
  plugins: [
    new UglifyJSPlugin({
      sourceMap: true
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    })
  ],
  mode: 'production'
})

package.json

{
  "name": "my-module-name",
  "version": "1.0.0-beta.1",
  "description": "",
  "main": "dist/main/index.js",
  "scripts": {
    "start": "webpack-dev-server --config webpack.dev.js",
    "server": "node src/server",
    "format": "prettier-standard 'src/**/*.js'",
    "lint": "eslint src",
    "build": "webpack --config webpack.prod.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Liran",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-eslint": "^8.2.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^0.28.11",
    "eslint": "^4.19.1",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "html-webpack-plugin": "^3.2.0",
    "idempotent-babel-polyfill": "^0.1.1",
    "node-sass": "^4.9.0",
    "prettier-standard": "^8.0.1",
    "sass-loader": "^7.0.1",
    "style-loader": "^0.21.0",
    "uglifyjs-webpack-plugin": "^1.2.5",
    "webpack": "^4.6.0",
    "webpack-cli": "^2.0.15",
    "webpack-dev-middleware": "^3.1.3",
    "webpack-dev-server": "^3.1.3",
    "webpack-merge": "^4.1.2"
  }
}

Any help/pointers would be greatly appreciated. If you need more information, please let me know.

Interactive answered 20/5, 2018 at 13:19 Comment(4)
what is the target set on your libraryTarget on your webpack config?Calvillo
Hi @MatheusSilva, I don't have this property in my webpack config. I've added my whole setup to my post for greater clarity.Interactive
Look at this!. webpack.js.org/guides/author-libraries/#expose-the-libraryCalvillo
Wow @MatheusSilva, I can't believe it, but after adding the library and libraryTarget properties, my module now works flawlessly in my test project! Thank you so much for this really helpful pointer. If you'd like to write a short answer with the properties needed to be added (library and libraryTarget) and the source (the webpack link), I would gladly choose it as the accepted answer.Interactive
C
27

It is not working because it is missing libraryTarget and library properties. By doing that webpack know which format of module you would like to create, i.e: commonjs (module.exports) or es (export).

I would do something like:

...
  output: {
    path: path.join(__dirname, 'dist'),
    filename: path.join('[name]', 'index.js'),
    library: "my-library",
    libraryTarget: "umd" // exposes and know when to use module.exports or exports.
  },
...
Calvillo answered 20/5, 2018 at 16:56 Comment(0)
M
83

If you are not the library author and are having a problem consuming another library, you may be seeing an error like this:

TypeError: [LIBRARY_NAME]__WEBPACK_IMPORTED_MODULE_3__ is not a constructor

If that's the case, you may be importing the library incorrectly in your code (it may be a problem with default exports). Double check the library docs for usage.

It may be as simple as changing this:

import Foo from 'some-library/Foo';

to this:

import { Foo } from 'some-library';
Manage answered 27/3, 2020 at 20:25 Comment(4)
It worked like a charm when importing Typescript class in .js file.Dichogamy
Could you elaborate what is the difference when using the curly brackets and when not using them? Thanks!Beauharnais
@Beauharnais Sure. The first example without curly braces is called the "default export" where the entire exported library is available through the Foo variable (e.g. Foo.doSomething()). The second example with curly braces is the "module exports" pattern, where modules are explicitly cherrypicked from the library piecemeal, which is ideal for treeshaking. The idea is that if a library has 100 modules and you only want to use 1, this pattern makes it explicit, so module bundlers know they don't need to bring in the other 99 modules, like they would have with the default export example.Manage
@DavidCalhoun Thank you very much for the explanation!Beauharnais
C
27

It is not working because it is missing libraryTarget and library properties. By doing that webpack know which format of module you would like to create, i.e: commonjs (module.exports) or es (export).

I would do something like:

...
  output: {
    path: path.join(__dirname, 'dist'),
    filename: path.join('[name]', 'index.js'),
    library: "my-library",
    libraryTarget: "umd" // exposes and know when to use module.exports or exports.
  },
...
Calvillo answered 20/5, 2018 at 16:56 Comment(0)
S
7

Besides setting the libraryTarget, it may also be necessary to move the export in the JavaScript file to the default.

function MyClassName() {
  ...
}

export default MyClassName;

And then in the webpack configuration the library type umd ...

(Note that I have used the newer library.type instead the older libraryTarget (see https://webpack.js.org/configuration/output/#outputlibrarytarget).

 const path = require('path');
 
 module.exports = {
    mode: "production",
    entry: '../wherever/MyClassName.js',
    
    output: {
        library: {
          name: "MyClassName",
          type: "umd",  // see https://webpack.js.org/configuration/output/#outputlibrarytype
          export: "default",  // see https://github.com/webpack/webpack/issues/8480
        },
        filename: 'MyClassName.min.js',
        path: path.resolve(__dirname, '../wherever/target/')
    },
    optimization: {
        minimize: true
    }
 };

The export default makes the class available in JavaScript like the file was embedded directly, i.e.,

<script type="text/javascript" src="MyClassName.min.js"></script>
<script type="text/javascript">
<!--

var myInstance = new MyClassName();

// -->
</script>

Disclaimer: I added this answer even though the original question is three years old by now. After encountering the "is not a constructor" issue, it took me hours of searching to find the default solution. And that was the second time, I searched and found it :D

Somebody answered 5/8, 2021 at 8:27 Comment(2)
Thanks a lot! This helped me to fix my issue regarding creating a React wrapper package around workbox-window using webpack.Knox
It was as simple as exporting the class... Thx!!Creature
A
2

In case something is using wepack 5 + babel 7

"webpack": "5.73.0",
"@babel/core": "7.4.4",
"@babel/preset-env": "7.4.4",
"babel-loader": "8.0.5",

AND want to use class instead function, this worked for me:

class Person {
   constructor(fname, lname, age, address) {
      this.fname = fname;
      this.lname = lname;
      this.age = age;
      this.address = address;
   }

   get fullname() {
      return this.fname +"-"+this.lname;
   }
}

export default Person;

In my case .babelrc was not necesary

Abbacy answered 5/7, 2022 at 23:57 Comment(0)
L
1

Cf. David Calhoun's answer, if you run into this with a third-party library, you may be trying to import a CommonJS module as an ECMAScript module. The workaround there seems to be to use require instead of import, e.g., instead of

import { Foo } from 'bar'

you need to write

const Foo = require('bar')

(There may be a more elegant way to handle this, but this is what worked for me.)

Lappet answered 26/7, 2021 at 4:33 Comment(0)
H
1

For me, it was the cache issue. Just cleared the cookies, cache data and closed, reopened the browser. It worked.

Hayne answered 10/3, 2022 at 13:8 Comment(0)
E
0

In my case, the error was being caused in React when trying to invoke JS's built-in Error constructor, or in other words, basically when calling throw new Error("something").

On inspection of my code, I realised I had a component called Error in my project which was being imported into the same file. The name clash between this component and JS's built-in Error constructor was causing the error mentioned in the question.

Exocrine answered 17/2, 2022 at 9:46 Comment(0)
B
0

tl;dr

Make sure that you import properly through index files.

Explanation

For me, this error was caused by importing through index files. I had multiple directories with their index.ts files that exported all the files inside the directory. These index files were accumulated/reexported by a main index.ts file so everything can be imported through it.

src/
├── index.ts
├── module1/
│   ├── index.ts
│   ├── file1.ts
│   └── file2.ts
└── module2/
    ├── index.ts
    ├── file3.ts
    └── file4.ts

In file4.ts I had an import like this:

import { file1Class, file2Class, file3Class } from "src";

I had to split it into two separate imports:

import { file1Class, file2Class } from "src/module1";
import { file3Class } from "src/module2";
Breann answered 15/11, 2022 at 10:9 Comment(0)
S
0

The accepted answer worked for me with

const { SubresourceIntegrityPlugin } = require('webpack-subresource-integrity');

If this helps anyone :D trying for SRI in react.

Selfevident answered 26/6, 2024 at 13:20 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.