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 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 引用了原始文件,所以我没有看到开发服务器包。
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;
对我有用
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 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 引用了原始文件,所以我没有看到开发服务器包。
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;
对我有用