webpack imported module is not a constructor

83,429

Solution 1

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.
  },
...

Solution 2

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';

Solution 3

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

Solution 4

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.)

Share:
83,429
Liran H
Author by

Liran H

Updated on February 17, 2022

Comments

  • Liran H
    Liran H about 2 years

    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.

  • Konrad Gałęzowski
    Konrad Gałęzowski about 4 years
    It worked like a charm when importing Typescript class in .js file.
  • brance
    brance almost 4 years
    Could you elaborate what is the difference when using the curly brackets and when not using them? Thanks!
  • David Calhoun
    David Calhoun almost 4 years
    @brance 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.
  • brance
    brance almost 4 years
    @DavidCalhoun Thank you very much for the explanation!
  • n.sh
    n.sh about 2 years
    Thanks a lot! This helped me to fix my issue regarding creating a React wrapper package around workbox-window using webpack.