之前在《CodeMirror实现关键词高亮及自定义主题》中简单介绍过react-codeMirror的使用和主题的自定义方式,最近在另外一个webpack打包的React项目中再次使用时遇到题目中比较奇怪的问题,请教了两位同事,终于解决了该问题,特此记录一下排查问题的过程及导致问题的原因。
首先说明一下问题,在组件中使用最简单的方式使用react-codeMirror,代码示例如下:
import React from 'react'
import CodeMirror from 'react-codemirror';
import 'codemirror/mode/sql/sql';
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/lib/codemirror.css';
import ReactDOM from "react-dom";
export default class CodemirrorTest extends React.Component{
constructor(props){
super(props);
this.state = {};
this.options = {
lineNumbers: true
};
}
handleChange(code){
console.warn(code);
}
render(){
return(
<CodeMirror
ref={ref => this.codeComponent = ref}
value={'test'}
onChange={this.handleChange}
options={this.options}
/>
)
}
}
ReactDOM.render(<CodemirrorTest />, document.getElementById('container'));
当渲染该组件时,会出现如下错误:
可以看到错误原因是:
在Codemirror.js文件中componentDidMount周期会通过调用getCodeMirrorInstance方法获取codemirror的instance,出现Uncaught TypeError codeMirrorInstance.fromTextArea is not a function的错误肯定是getCodeMirrorInstance方法没有正常返回,并没有提示undefined相关。
看到这里,比较简单的一种解决方式就已经出现了,getCodeMirrorInstance方法没有正常返回肯定是require('codemirror')执行有问题,因为我们没有通过props传递codeMirrorInstance,所以比较简单的方式就是:
import React from 'react'
import CodeMirror from 'react-codemirror';
import 'codemirror/mode/sql/sql';
import 'codemirror/mode/javascript/javascript.js';
import 'codemirror/lib/codemirror.css';
import ReactDOM from "react-dom";
export default class CodemirrorTest extends React.Component{
constructor(props){
super(props);
this.state = {};
this.options = {
lineNumbers: true
};
this._codeMirrorInstance = require('codemirror');
}
handleChange(code){
console.warn(code);
}
render(){
return(
<CodeMirror
ref={ref => this.codeComponent = ref}
value={'test'}
onChange={this.handleChange}
options={this.options}
codeMirrorInstance={this._codeMirrorInstance}
/>
)
}
}
ReactDOM.render(<CodemirrorTest />, document.getElementById('container'));
经过测试,这样已经可以解决问题。但是,依然不知道导致问题的原因是什么。
要找到问题的原因,就要确认getCodeMirrorInstance方法返回的到底是什么,通过在
getCodeMirrorInstance中console.log 相关信息,我们发现,getCodeMirrorInstance返回的竟然是react-codemirror自己,这里比较奇怪的是codemirror的文件命名为,而react-codemirror的主文件命名为Codemirros.js,结合webpack编译时的warning:
猜想应该是module名称有冲突,所以猜测是打包过程中require的module有问题。
下面就是查webpack文件,终于发现如下配置:
modules的查找会先从自己的目录开始,而windows对大小写不敏感(Codemirror,codemirror),所以就导致了题目中问题的产生。
比较方便的解决方式为在resolve中给codemirror加一个别名:
至此,Uncaught TypeError codeMirrorInstance.fromTextArea is not a function的问题已经解决,出现该问题的原因也比较清楚了。
总结如下:
出现Uncaught TypeError codeMirrorInstance.fromTextArea is not a function的原因:
- resolve模块时本目录优先;
- react-codemirror和codemirror的文件命名(Codemirror,codemirror);
- 编译时对大小写不敏感。
碰到此问题的解决方法:
- 在组件中先require codemirror,通过props传递给react-codemirror;
resolve加别名。