未捕获的TypeError:无法将类作为函数调用

时间:2017-11-16 15:48:07

标签: javascript reactjs npm gulp babeljs

我查看了这个问题的所有答案:
Getting "Cannot call a class as a function" in my React Project

我仍然无法解决为什么以下错误'无法将类称为函数'。我在语法方面遗漏了什么吗?

  • 我正在通过Gulp,Rollup和Babel
  • 包含以上所有插件
  • reactDOM.render的选择器很好,不需要导出类

代码:

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {

    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div />
        );
    }
}

// Selector is fine, changes bg to red
document.querySelector('#app').style.background = 'red';

ReactDOM.render(<App />, document.querySelector('#app'));

错误:

enter image description here

使用Rollup和Babel进行Gulp任务:

gulp.task('js', () => {

    // Package up ES6 moduleswith stream
    const stream = plugins.rollupStream({
        input: paths.dev + '/script/app.js',
        sourcemap: true,
        format: 'iife',
        name: 'app',
        plugins: [
            plugins.rollupPluginReplace({'process.env.NODE_ENV': JSON.stringify( 'production' )}),
            plugins.rollupPluginJsx({ factory: 'React.createElement' }),
            plugins.rollupPluginCommonjs({}),           
            plugins.rollupPluginNodeResolve({ jsnext: true, main: true }),
            plugins.rollupPluginIncludepaths({ paths: [paths.dev + '/script/'] })
        ]
    })

    return stream
        .on('error', e => {
            console.error(e.stack);

            notifier.notify({
                title: 'Rollup error',
                message: e.stack
            });
            stream.emit('end');
        })
        // Error handling
        .pipe(plugins.plumber())
        // Prepare files for sourcemap
        .pipe(plugins.vinylSourceStream('app.js', paths.dev + '/script/'))
        .pipe(plugins.vinylBuffer())
        .pipe(plugins.sourcemaps.init({ loadMaps: true }))
        // Convert ES6
        .pipe(plugins.babel({ presets: ['es2015', 'react'] }))
        // Write sourcemap
        .pipe(plugins.sourcemaps.write('.'))
        .pipe(gulp.dest(paths.tmp + '/script/'))
        .pipe(plugins.browserSync.stream());
});

代码库:

https://github.com/alexplummer/framework-react/blob/master/_dev/script/app.js

1 个答案:

答案 0 :(得分:1)

问题是你的JSX没有正确编译。如果你查看devtools中的输出(堆栈跟踪底部的第二个错误),你会看到该类被称为常规函数:

reactDom.render(App(), document.querySelector('#app'));
//              ^^^^^

您正在使用rollup-plugin-jsx,它似乎处理方式不同。如果你正在使用Babel,真的没有理由使用它,因为Babel也可以转换你的JSX。我假设你添加了这个,因为Rollup抱怨JSX。那是因为你的构建管道不太正确。您目前首先使用Rollup捆绑代码,然后在其上运行Babel。

您可以使用rollup-plugin-babel将Babel直接集成到Rollup中,因此Rollup捆绑的所有内容都将由Babel自动转换。通过添加此插件,您可以完全删除rollup-plugin-jsx,之后也不需要将其传输到Babel。

这些是tasks/js.js的更改(Stack Overflow没有git diffs的语法高亮,但您可以在Gist - tasks/js.js diff中看到突出显示的版本):

diff --git a/tasks/js.js b/tasks/js.js
index 0caabc1..7c5319d 100644
--- a/tasks/js.js
+++ b/tasks/js.js
@@ -70,7 +70,10 @@ gulp.task('js', () => {
                name: 'app',
                plugins: [
                        plugins.rollupPluginReplace({'process.env.NODE_ENV': JSON.stringify( 'development' )}),
-                       plugins.rollupPluginJsx({ factory: 'React.createElement' }),
+                       plugins.rollupPluginBabel({
+                               exclude: 'node_modules/**',
+                               presets: [['es2015', { modules: false }], 'react']
+                       }),
                        plugins.rollupPluginCommonjs({}),
                        plugins.rollupPluginNodeResolve({ jsnext: true, main: true }),
                        plugins.rollupPluginIncludepaths({ paths: [paths.dev + '/script/'] })
@@ -93,8 +96,6 @@ gulp.task('js', () => {
                .pipe(plugins.vinylSourceStream('app.js', paths.dev + '/script/'))
                .pipe(plugins.vinylBuffer())
                .pipe(plugins.sourcemaps.init({ loadMaps: true }))
-               // Convert ES6
-               .pipe(plugins.babel({ presets: ['es2015', 'react'] }))
                // Write sourcemap
                .pipe(plugins.sourcemaps.write('.'))
                .pipe(gulp.dest(paths.tmp + '/script/'))

请注意,您需要在Babel中关闭模块转换,因为Rollup需要ES模块。在旁注中,不推荐使用babel-preset-es2015,而是babel-preset-env,其中包含es201x预设所做的所有事情。它是es2015的替代品,有关详细信息,请参阅Migration guide from es2015 to env