babel-loader、webpack、ES2015 模块:"Element type is invalid"

babel-loader, webpack, ES2015 modules: "Element type is invalid"

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"。我在浏览器控制台中收到错误 "Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined."。

我可以追溯到一些生成的 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 进行设置,我可以毫无问题地克隆该示例存储库并将其构建到工作应用程序中。我意识到我一定错过了那个回购协议中发生的事情的一些重要部分,但我看不到它。

是否有理由在 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” 错误是转移注意力的错误。在此之前我看到:

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).warning @ app.min.js:2233createElement @ app.min.js:19531(anonymous function) @ app.min.js:61__webpack_require__ @ app.min.js:20(anonymous function) @ app.min.js:40(anonymous function) @ app.min.js:43 app.min.js:2233 Warning: render(): Rendering components directly into document.body is discouraged, since its children are often manipulated by third-party scripts and browser extensions. This may lead to subtle reconciliation issues. Try rendering into a container element created for your app.

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

适合我

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    

这题应该叫"why won't my NPM scripts update my bundle."

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

事实 1:npm build is a recognized NPM command, but it does not invoke scripts.build from package.json. As in @zhongjie-wu 's ,我需要做 npm run buildnpm 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 引用了原始文件,所以我没有看到开发服务器包。

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;

对我有用