无需React脚手架,通过Babel在浏览器渲染组件报错的解决办法
如何在浏览器中直接使用Babel渲染React组件(无需脚手架)?
问题重现
你尝试在浏览器中直接通过Babel转译React代码,未使用脚手架,但页面无法渲染,出现两个关键错误:
Uncaught ReferenceError: exports is not defined React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
你的原始HTML代码:
<script type="text/jsx" src="Link.react.js"></script> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <body> <div id="root"></div> <script type="text/babel"> ReactDOM.render(<Link page="https://www.facebook.com" />, document.getElementById('root')); </script> </body>
Link.react.js代码:
export default class Link extends React.Component { // basic implementation }
问题原因
- 脚本加载顺序错误:你先加载了依赖React的
Link.react.js,但此时React还未被引入,导致组件无法识别React对象。 - 浏览器不支持ES模块语法:浏览器原生环境(非模块模式下)不认识
export default这类ES模块语法,所以会抛出exports is not defined错误。 - 脚本类型配置不当:
Link.react.js包含JSX和ES6类语法,需要指定type="text/babel"才能被Babel转译,但你设置的是text/jsx(旧类型,babel-standalone更推荐text/babel)。
解决方法(无需脚手架)
完全不需要用react-scripts编译就能实现需求,只需要调整以下几点:
1. 调整脚本加载顺序
必须先加载React、ReactDOM和Babel,再加载你的自定义组件脚本,确保组件执行时依赖库已经就绪。
2. 全局暴露React组件
因为浏览器不支持模块导出,直接把组件挂载到全局window对象上,这样后续的渲染脚本就能访问到。
3. 正确配置脚本类型
给自定义组件脚本设置type="text/babel",让Babel处理里面的JSX和ES6语法。
修正后的代码
HTML页面代码:
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> <body> <div id="root"></div> <!-- 先加载依赖,再加载自定义组件,指定正确的类型 --> <script type="text/babel" src="Link.react.js"></script> <script type="text/babel"> ReactDOM.render(<Link page="https://www.facebook.com" />, document.getElementById('root')); </script> </body>
Link.react.js代码:
// 把组件挂载到全局window对象上 window.Link = class Link extends React.Component { render() { // 补充基础渲染逻辑,否则组件不会输出内容 return ( <a href={this.props.page} target="_blank" rel="noopener noreferrer"> 前往 {this.props.page} </a> ); } };
额外说明
如果你的Babel版本较新(比如@7+),也可以尝试使用ES模块模式:给所有脚本加上type="module",保留export default,并在导入时用import Link from './Link.react.js',但要注意:
- 浏览器需要支持ES模块(现代浏览器都支持)
- 脚本文件必须通过HTTP服务访问(不能直接打开本地HTML文件,否则会有跨域问题)
- babel-standalone对模块的支持需要额外配置
不过对于简单测试场景,全局挂载组件的方式更简单、兼容性更好,完全不需要依赖脚手架编译工具。
内容的提问来源于stack exchange,提问作者Teoman shipahi
相关产品推荐
相关产品推荐

