【问题标题】:babel-loader, webpack, ES2015 modules: "Element type is invalid"babel-loader、webpack、ES2015 模块:“元素类型无效”
【发布时间】:2016-03-24 14:57:46
【问题描述】:

Github repo 包含所有内容:https://github.com/b-paul/react-lifecycle

12/18 更新:很大一部分问题是用于运行项目的 npm 命令。我注意到npm build 没有成功,但npm start 报告构建正常。下面是关于为什么没有按预期工作的完整答案。这个问题的其余部分留给后代。


我的第一个 webpack 项目的基本设置有问题。我正在使用 React 和 Babel,以及以下 webpack.config.js:

var path = require('path');

module.exports = {
  entry: [ path.resolve('./js/app.js'),
           'webpack-dev-server/client?http://localhost:8080' ],
  output: {
    path: path.resolve('./js/build'),
    filename: 'app.min.js'
  },
  module: {
    loaders: [
      { test: /\.jsx?$/,
        loader: 'babel',
        query: {
          presets: ['react', 'stage-1', 'es2015']
        },
        include: path.resolve('js/') } ]
  },
  devtool: 'source-map'
};

js/app.js

import Lifecycle from './components/lifecycle';
import React from 'react';
import {render} from 'react-dom';

var shell = document.createElement('div');
shell.className = 'app-shell';
document.body.appendChild(shell);
render(<Lifecycle />, shell);

js/components/lifecycle.js

import React from 'react';

class Lifecycle extends React.Component {
  render() {
    return (
      <div>Hello, world</div>
    );
  }
}

export default Lifecycle;

上面的构建没有错误,但它不会呈现“Hello, world”。我收到错误消息:“不变违规:元素类型无效:需要字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。”在浏览器控制台中。

我可以追踪到一些生成的 babel 代码,它试图检查我的模块 Lifecycle 是否是 ES6 模块(babel 识别它是这样的)并期望它在内部模块对象上有一个属性 default (它没有)。这是生成的代码:

/* 0 */
/***/ function(module, exports, __webpack_require__) {

  'use strict';

  var _lifecycle = __webpack_require__(1);

  var _lifecycle2 = _interopRequireDefault(_lifecycle);

  var _react = __webpack_require__(2);

  var _react2 = _interopRequireDefault(_react);

  var _reactDom = __webpack_require__(159);

  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

  (0, _reactDom.render)(_react2.default.createElement(_lifecycle2.default, null), document.body);

/***/ }

最后说明:我多次引用https://github.com/code0wl/react-example-es2015 进行设置,我可以克隆该示例存储库并将其构建到一个正常工作的应用程序中,没有任何问题。我意识到我一定错过了该回购中发生的一些重要部分,但我看不到它。

【问题讨论】:

    标签: reactjs ecmascript-6 webpack babeljs


    【解决方案1】:

    Layout.js

    export default class Layout extends Component {
      constructor(props) {
       super(props);
      }
    
      render() {
        return (
          <div className="Layout">
    
          </div>
        )
      }
    };
    

    .babelrc 需要添加 stage-1 预设以尝试转译类

        {
          "presets": ["stage-1", "es2015", "react"],
          "plugins": ["transform-runtime"]
        }
    

    和入口文件需要做ES5导出:

    import React from 'react';
    import Layout from './Layout';
    import {render} from 'react-dom';
    
    if (typeof document !== 'undefined') {
      render(<Layout />, document.getElementById('app'));
    }
    
    module.exports = Layout;
    

    它对我有用

    【讨论】:

      【解决方案2】:

      这个问题应该被称为“为什么我的 NPM 脚本不会更新我的包”。

      在开发早期的某个时候,我已经成功地将我的代码与 webpack 捆绑在一起。该捆绑包在磁盘上的名称为js/build/app.min.js。在那之后,我以为我正在使用来自package.json 的 NPM 脚本在每次更改时重建应用程序,但是在浏览器中,我仍然得到旧的行为(来自原始包)。我错过了两个事实:

      事实 1: npm build 是公认的 NPM 命令,但它确实package.json 调用 scripts.build。就像@zhongjie-wu 的answer 一样,我需要做npm run build。另一方面,npm start确实调用了scripts.start,它成功地用webpack-dev-server构建了一个包。

      事实 2: webpack-dev-server 在提供重建的捆绑包时,无法将 webpack 配置文件中的 output.path 识别为路由的一部分。因此,鉴于我使用的配置,webpack 构建为/js/build/app.min.js,但webpack-dev-server 从内存中以/app.min.js 提供该捆绑包。由于我的 HTML 引用了原始文件,因此我没有看到开发服务器包。

      【讨论】:

        【解决方案3】:

        为我工作

        git clone https://github.com/b-paul/react-lifecycle.git
        cd react-lifecycle.git
        npm install
        npm run build
        npm run start
        # go to http://localhost:8090/index.html    
        

        【讨论】:

          【解决方案4】:

          是否有理由在 app.js 中动态创建应用的容器 div,而不是仅仅将其放入 index.html 中?我克隆了您的存储库并通过进行以下更改来构建应用程序:

          index.html:

          <body>
             <div id="app-shell"></div>
             <script type="application/javascript" src="js/build/app.min.js"></script>
          </body>
          

          app.js

          import React from 'react';
          import {render} from 'react-dom';
          import Lifecycle from './components/lifecycle';
          
          render(<Lifecycle />, document.getElementById('app-shell'));
          

          我认为 “Element type is invalid” 错误是一个红鲱鱼。在此之前我看到的是:

          警告:React.createElement:类型不应为 null、未定义、 布尔值或数字。它应该是一个字符串(对于 DOM 元素)或 ReactClass(用于复合组件).warning @ app.min.js:2233createElement@app.min.js:19531(匿名函数)@ app.min.js:61__webpack_require__ @ app.min.js:20(匿名函数) @ app.min.js:40(匿名函数)@ app.min.js:43 app.min.js:2233 警告:render():将组件直接渲染到 document.body 是 气馁,因为它的孩子经常被第三方操纵 脚本和浏览器扩展。这可能会导致微妙的和解 问题。尝试渲染到为您的应用创建的容器元素中。

          这可能是由于您在 app.js 中创建 shell 元素的方式...

          【讨论】:

            猜你喜欢
            • 2018-02-06
            • 1970-01-01
            • 2019-03-10
            • 2020-11-18
            • 1970-01-01
            • 1970-01-01
            • 2016-04-01
            • 2016-11-12
            • 1970-01-01
            相关资源
            最近更新 更多