Babel 和 ES6 出現意外的“Uncaught TypeError: XXX is not a constructor”錯誤 (Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6)


問題描述

Babel 和 ES6 出現意外的“Uncaught TypeError: XXX is not a constructor”錯誤 (Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6)

我正在嘗試使用 Webpack,並且正在嘗試本教程,給予或接受一些自定義的東西。

這是一個簡單的代碼,真的,但我對這個錯誤感到很困惑,覺得這是我錯過的愚蠢的東西。

我定義了兩個 ES6 類,每個對應一個 Handlebars 模板,我的應用程序的入口點應該用它們的內容替換索引文件中的佔位符 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');
}

索引:

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

    <script src="build/bloj.js"></script>
</body>
</html>

按鈕:

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

標題:

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

很遺憾,它不起作用,並且在顯示頁面時出現這兩個錯誤:

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

我可能缺少什麼?

這是我的 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
    }
};

參考解法

方法 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;

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

方法 3:

You can just put export var __useDefault = true; just after exporting your Class.

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

方法 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.

方法 5:

Although this is not the cause of your particular issue, I ran into a very similar problem when trying to rip babel out of an existing node app that was using ES6's import and export syntax, so this post is to help out anyone else struggling with this in the future.

Babel will resolve any circular dependencies between one module and another, so you can use ES6's import and export with reckless abandon. However, if you need to get rid of babel and use native node, you will need to replace any import and exports with require. This can reintroduce a latent circular reference issues that babel was taking care of in the background. If you find yourself in this situation, look for an area in your code that looks like this:

File A:

const B = require('B');

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

File B:

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

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

There are several different ways to resolve this issue depending on how you structured your code. The easiest way is probably to pass B a reference to A instead of creating a new instance of class A. You could also dynamically resolve the reference when loading A. There are a myriad of other alternatives, but this is a good place to get started.

(by Silver QuettierFelix KlingByebyemaufarinelliseantomburkextro)

參考文件

  1. Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6 (CC BY‑SA 2.5/3.0/4.0)

#Webpack #javascript #babeljs #ecmascript-6






相關問題

Babel 6 轉換運行時:$export 不是函數 (Babel 6 transform-runtime: $export is not a function)

Webpack 和 Sass 正確處理 background: url() 圖像,但是在與 webpack-dev-server 一起使用時找不到它 (Webpack and Sass correctly processes background: url() image but then it's not found when used with webpack-dev-server)

Babel 和 ES6 出現意外的“Uncaught TypeError: XXX is not a constructor”錯誤 (Unexpected "Uncaught TypeError: XXX is not a constructor" errors with Babel and ES6)

Webpack bundle ENOENT:沒有這樣的文件或目錄 fs.readdirSync (Webpack bundle ENOENT: no such file or directory fs.readdirSync)

有沒有辦法通過替換一些資產和組件從單個應用程序構建多個應用程序? (Is there a way to build multiple apps from single one with replacing some assets and components?)

Babel 7 不能正確轉換 index.js (Babel 7 don't convert index.js properly)

使用 Yarn 安裝的軟件包開始出現 sweetalert2 之類的錯誤 (packages installed with Yarn start to give error like sweetalert2)

找不到模塊 RecipeStyle.css (cannot find module RecipeStyle.css)

用於文件、子文件的 Webpack 加載器並將它們添加到跟踪列表 (Webpack loader for file, subfiles and add them to tracking list)

Webpack:沒有加載器來處理 SCSS 是輸入存在 (Webpack: no loader to handle the SCSS is input is present)

Webpack 在初始構建後不構建捆綁包 (Webpack not building bundle after initial build)

從其他機器訪問 webpack DevServer 子 URL 時出現 ERR_SSL_PROTOCOL_ERROR (ERR_SSL_PROTOCOL_ERROR when accessing webpack DevServer sub-URLs from a different machine)







留言討論