web-dev-qa-db-ger.com

Unerwarteter Fehler "Nicht gefundener TypeError: XXX ist kein Konstruktor" bei Babel und ES6

Ich mache einen Versuch mit Webpack, und ich versuche die Anweisungen in dieses Tutorial , zu geben oder einige benutzerdefinierte Dinge mitzunehmen.

Dies ist wirklich ein einfacher Code, aber ich bin ziemlich verwirrt über diesen Fehler und fühle, dass dies etwas Dummes ist, das ich vermisst habe.

Ich habe zwei ES6-Klassen definiert, die jeweils einer Handlebars-Vorlage entsprechen, und der Einstiegspunkt der App soll den Platzhalter-HTML-Code in der Indexdatei durch deren Inhalt ersetzen:

Einstiegspunkt:

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>

Taste:

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

Leider funktioniert es nicht und ich erhalte beide Fehler beim Anzeigen der Seite:

Uncaught TypeError: Header is not a constructor
Uncaught TypeError: Button is not a constructor

Was könnte ich vermissen?

Hier ist meine Webpack-Konfiguration:

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
    }
};
27
Silver Quettier

Was könnte ich vermissen?

Babel weist der Eigenschaft default Standardexporte zu. Wenn Sie also mit require ES6-Module importieren, müssen Sie auf die Eigenschaft default zugreifen:

const Button = require('./Components/Button.js').default;
46
Felix Kling

Mir ist klar, dass Sie bereits eine Antwort haben. Ich hatte jedoch ein ähnliches Problem, auf das ich eine Antwort gefunden hatte. Meine eigene Frage zu beginnen und sie zu beantworten, scheint seltsam zu sein ... Ich lass das hier einfach.

Ich hatte den gleichen Fehler wie du. Ich konnte es jedoch lösen, indem ich meine veränderte

export default {Class}

zu 

export default Class

Ich weiß nicht, warum ich die Klasse in ein Objekt eingepackt habe, aber ich erinnere mich, dass ich sie irgendwo gesehen habe, also fing ich an, sie zu benutzen.

Anstelle des Standardwerts, der eine Klasse zurückgibt, wurde ein Objekt wie dieses {Class: Class}..__ zurückgegeben. Dies ist vollständig gültig, aber es wird webpack + babel beschädigt.

EDIT: Ich habe seither erfahren, warum dies wahrscheinlich Babel + Webpack bricht. Der export default soll nur einen Export haben. Ein Javascript-Objekt kann viele Eigenschaften enthalten. Was bedeutet, dass es mehr als 1 Export haben kann. (Siehe: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export ).

Für mehrere Exporte verwenden Sie: export {definition1, definition2}

Anwendungsfall: Ich habe dies in einer Situation verwendet, in der ich eine Bibliothek erstellt habe, die verschiedene Arten eines Editors exportiert hat (während der zugrunde liegende Code derselbe war, ändert sich das Erscheinungsbild des Editors je nach verwendetem Export).

8
Byebye

Sie können einfach export var __useDefault = true; direkt nach dem Export Ihrer Klasse einfügen.

export default class Header {
...
} 
export var __useDefault = true;
6
maufarinelli

Es ist nicht das Problem in dieser speziellen Frage, aber aus einigen Gründen hebt babel keine Klassen in derselben Datei.

Wenn Sie also Ihre Klasse Token oben in der Datei deklarieren und später new Token() schreiben, wird sie ausgeführt.

Wenn Sie Ihre Klasse nach dem Konstruktoraufruf deklarieren, haben Sie xxx keinen Konstruktor Fehler

1
Nicolas Zozol

Obwohl dies nicht die Ursache für Ihr spezielles Problem ist, bin ich auf ein sehr ähnliches Problem gestoßen, als ich versuchte, Babel aus einer vorhandenen Knoten-App herauszureißen, die die import- und export-Syntax von ES6 verwendete. Daher soll dieser Beitrag allen anderen helfen, die mit diesem Problem zu kämpfen haben in der Zukunft.

Babel löst alle zirkularen Abhängigkeiten zwischen einem Modul und einem anderen auf, sodass Sie die import und export von ES6 ohne Rücksicht aufgeben können. Wenn Sie jedoch babel loswerden und den nativen Knoten verwenden müssen, müssen Sie import und exports durch require ersetzen. Dadurch können latente zirkuläre Referenzthemen wieder eingeführt werden, die sich im Hintergrund von babel erledigt haben. Wenn Sie sich in dieser Situation befinden, suchen Sie in Ihrem Code nach einem Bereich, der folgendermaßen aussieht:

Datei A:

const B = require('B');

class A {
  constructor() {
    this.b = new B();
  }
}
module.exports = A;

Datei B:

const A = require('A'); // this line causes the error

class B {
  constructor() {
    this.a = new A();
  }
}
module.exports = B;

Es gibt verschiedene Möglichkeiten, dieses Problem zu lösen, je nachdem, wie Sie Ihren Code strukturiert haben. Am einfachsten ist es wahrscheinlich, B einen Verweis auf A zu übergeben, anstatt eine neue Instanz der Klasse A zu erstellen. Sie können den Verweis auch dynamisch auflösen, wenn Sie A laden. Es gibt unzählige andere Alternativen, aber dies ist ein guter Anfangspunkt.

0
xtro