Silver Quettier Silver Quettier - 21 days ago 4
Javascript Question

Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6

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

Answer

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;