Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6
Solution 1
What could I be missing?
Babel assigns default exports to the default
property. So if you use require
to import ES6 modules, you need to access the default
property:
const Button = require('./Components/Button.js').default;
Solution 2
I realize that you already have an answer. However I had a similar issue to which I found an answer. Starting my own question and answering it seems weird. So I'm just going to leave this here.
I had the same error as you got. However, I managed to solve it by changing my
export default {Class}
to
export default Class
I don't know why I wrapped the Class in an object but I remember having seen it somewhere so I just started using it.
So instead of the default returning a Class it returned an object like this {Class: Class}
.
This is completely valid yet it will break webpack+babel.
EDIT: I've since come to know why this probably breaks babel+webpack. The export default
is meant to only have 1 export. A javascript-object can contain many properties. Which means it can have more than 1 export. (See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).
For multiple exports use: export {definition1, definition2}
.
Use-case: I've used this in a situation where I've created a library which exported different types of an editor (while the underlying code was the same, the appearance of the editor changes depending on which export you use).
Solution 3
You can just put export var __useDefault = true;
just after exporting your Class.
export default class Header {
...
}
export var __useDefault = true;
Solution 4
I was able to fix this by adding babel-plugin-add-module-exports
to the .babelrc
file
npm install babel-plugin-add-module-exports --save-dev
{
"presets": ["@babel/env"],
"plugins": ["add-module-exports"]
}
this adds
module.exports = exports.default;
to the last line when compiling the class with babel.
Silver Quettier
Computer enthusiast, working as web / Java developper at CGI Group. Also does some basic system administration from time to time, and runs some servers for a small gaming community.
Updated on February 05, 2022Comments
-
Silver Quettier over 2 years
I am giving a try to Webpack, and am giving a try to the instructions in this tutorial, give or take a few custom things.
This is simple code, really, but I'm quite puzzled about this error, and feel this is something silly that I missed.
I defined two ES6 classes, each corresponding to a Handlebars template, and my app's entrypoint is supposed to replace the placeholder HTML in the index file by their contents:
Entrypoint:
import './bloj.less' // If we have a link, render the Button component on it if (document.querySelectorAll('a').length) { require.ensure([], () => { const Button = require('./Components/Button.js'); const button = new Button('9gag.com'); button.render('a'); }, 'button'); } // If we have a title, render the Header component on it if (document.querySelectorAll('h1').length) { require.ensure([], () => { const Header = require('./Components/Header.js'); new Header().render('h1'); }, 'header'); }
Index:
<!DOCTYPE html> <html> <head> </head> <body> <h1>My title</h1> <a>Click me</a> <script src="build/bloj.js"></script> </body> </html>
Button:
import $ from 'jquery'; import './Button.less'; export default class Button { constructor(link) { this.link = link; } onClick(event) { event.preventDefault(); alert(this.link); } render(node) { const text = $(node).text(); var compiled = require('./Button.hbs'); // Render our button $(node).html( compiled({"text": text, "link": this.link}) ); // Attach our listeners $('.button').click(this.onClick.bind(this)); } }
Header:
import $ from 'jquery'; import './Header.less'; export default class Header { render(node) { const text = $(node).text(); var compiled = require('./Header.hbs'); // Render the header $(node).html( compiled({"text": text}) ); } }
Sadly, it does not work, and I get both these errors when displaying the page:
Uncaught TypeError: Header is not a constructor Uncaught TypeError: Button is not a constructor
What could I be missing?
Here is my webpack configuration:
var path = require('path'); var webpack = require('webpack'); var CleanPlugin = require('clean-webpack-plugin'); var ExtractPlugin = require('extract-text-webpack-plugin'); var production = process.env.NODE_ENV === 'production'; var appName = 'bloj'; var entryPoint = './src/bloj.js'; var outputDir = './build/'; var publicDir = './build/'; // ************************************************************************** // var plugins = [ //new ExtractPlugin(appName + '.css', {allChunks: true}), new CleanPlugin(outputDir), new webpack.optimize.CommonsChunkPlugin({ name: 'main', children: true, minChunks: 2 }) ]; if (production) { plugins = plugins.concat([ new webpack.optimize.DedupePlugin(), new webpack.optimize.OccurenceOrderPlugin(), new webpack.optimize.MinChunkSizePlugin({ minChunkSize: 51200 // 50ko }), new webpack.optimize.UglifyJsPlugin({ mangle: true, compress: { warnings: false // Suppress uglification warnings } }), new webpack.DefinePlugin({ __SERVER__: false, __DEVELOPMENT__: false, __DEVTOOLS__: false, 'process.env': { BABEL_ENV: JSON.stringify(process.env.NODE_ENV) } }) ]); } module.exports = { entry: entryPoint, output: { path: outputDir, filename: appName + '.js', chunkFilename: '[name].js', publicPath: publicDir }, debug: !production, devtool: production ? false : 'eval', module: { loaders: [ { test: /\.js/, loader: "babel", include: path.resolve(__dirname, 'src'), query: { presets: ['es2015'] } }, { test: /\.less/, //loader: ExtractPlugin.extract('style', 'css!less') loader: "style!css!less" }, { test: /\.html/, loader: 'html' }, { test: /\.hbs/, loader: "handlebars-template-loader" } ] }, plugins: plugins, node: { fs: "empty" // Avoids Handlebars error messages } };