Babel和ES6出现意外的"Uncaught TypeError:XXX不是构造函数"错误

Sil*_*ier 35 javascript ecmascript-6 webpack babeljs

我正在尝试Webpack,并尝试了本教程中的说明,给出或采取一些自定义的东西.

这是一个简单的代码,真的,但我对这个错误感到很困惑,觉得这是我错过的傻事.

我定义了两个ES6类,分别对应于把手模板,我的应用程序的入口点应该替换占位符HTML通过其内容的索引文件:

入口点:

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');
}
Run Code Online (Sandbox Code Playgroud)

指数:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <h1>My title</h1>
    <a>Click me</a>

    <script src="build/bloj.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

按钮:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

标题:

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})
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

可悲的是,它不起作用,我在显示页面时得到这两个错误:

Uncaught TypeError: Header is not a constructor
Uncaught TypeError: Button is not a constructor
Run Code Online (Sandbox Code Playgroud)

我能错过什么?

这是我的webpack配置:

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
    }
};
Run Code Online (Sandbox Code Playgroud)

Fel*_*ing 56

我能错过什么?

Babel为该default属性分配默认导出.因此,如果您使用require导入ES6模块,则需要访问该default属性:

const Button = require('./Components/Button.js').default;
Run Code Online (Sandbox Code Playgroud)


Bye*_*bye 9

我意识到你已经有了答案.但是我有一个类似的问题,我找到了答案.开始我自己的问题并回答它似乎很奇怪.所以我只想把它留在这里.

我遇到了同样的错误.但是,我设法通过改变我的方式来解决它

export default {Class}
Run Code Online (Sandbox Code Playgroud)

至

export default Class
Run Code Online (Sandbox Code Playgroud)

我不知道为什么我把Class包装在一个对象中,但我记得曾经在某个地方看过它,所以我才开始使用它.

因此,返回一个类而不是默认返回一个类,它返回一个这样的对象{Class: Class}.这是完全有效的,但它会打破webpack + babel.

编辑:我已经知道为什么这可能会打破babel + webpack.这export default意味着只有1个出口.javascript-object可以包含许多属性.这意味着它可以有多个导出.(参见:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export).

对于多个出口使用:export {definition1, definition2}.

用例:我已经在我创建了一个导出不同类型编辑器的库的情况下使用了它(虽然底层代码是相同的,但编辑器的外观会根据您使用的导出而改变).


mau*_*lli 6

您可以export var __useDefault = true;在导出班级后立即放置.

export default class Header {
...
} 
export var __useDefault = true;
Run Code Online (Sandbox Code Playgroud)

  • 你能补充说明这是如何工作的吗? (12认同)