Fix xterm.js resource leaks in split pane (#3409)

This commit is contained in:
Igor Sadikov 2019-01-18 17:58:09 -05:00 committed by CHaBou
parent ee8e95b8f1
commit 3881703e01
2 changed files with 25 additions and 19 deletions

View file

@ -76,13 +76,11 @@ export default class Term extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
props.ref_(props.uid, this); props.ref_(props.uid, this);
this.termRef = null;
this.termWrapperRef = null; this.termWrapperRef = null;
this.termRect = null; this.termRect = null;
this.onOpen = this.onOpen.bind(this); this.onOpen = this.onOpen.bind(this);
this.onWindowResize = this.onWindowResize.bind(this); this.onWindowResize = this.onWindowResize.bind(this);
this.onWindowPaste = this.onWindowPaste.bind(this); this.onWindowPaste = this.onWindowPaste.bind(this);
this.onTermRef = this.onTermRef.bind(this);
this.onTermWrapperRef = this.onTermWrapperRef.bind(this); this.onTermWrapperRef = this.onTermWrapperRef.bind(this);
this.onMouseUp = this.onMouseUp.bind(this); this.onMouseUp = this.onMouseUp.bind(this);
this.termOptions = {}; this.termOptions = {};
@ -94,15 +92,21 @@ export default class Term extends React.PureComponent {
this.termOptions = getTermOptions(props); this.termOptions = getTermOptions(props);
this.term = props.term || new Terminal(this.termOptions); this.term = props.term || new Terminal(this.termOptions);
this.term.attachCustomKeyEventHandler(this.keyboardHandler);
this.term.open(this.termRef);
this.term.webLinksInit();
this.term.winptyCompatInit();
if (props.term) { // The parent element for the terminal is attached and removed manually so
//We need to set options again after reattaching an existing term // that we can preserve it across mounts and unmounts of the component
Object.keys(this.termOptions).forEach(option => this.term.setOption(option, this.termOptions[option])); let parent = props.term ? props.term._core._parent : document.createElement('div');
parent.className = 'term_fit term_term';
this.termWrapperRef.appendChild(parent);
if (!props.term) {
this.term.attachCustomKeyEventHandler(this.keyboardHandler);
this.term.open(parent);
this.term.webLinksInit();
this.term.winptyCompatInit();
} }
if (this.props.isTermActive) { if (this.props.isTermActive) {
this.term.focus(); this.term.focus();
} }
@ -302,12 +306,9 @@ export default class Term extends React.PureComponent {
this.termWrapperRef = component; this.termWrapperRef = component;
} }
onTermRef(component) {
this.termRef = component;
}
componentWillUnmount() { componentWillUnmount() {
terms[this.props.uid] = null; terms[this.props.uid] = null;
this.termWrapperRef.removeChild(this.term._core._parent);
this.props.ref_(this.props.uid, null); this.props.ref_(this.props.uid, null);
// to clean up the terminal, we remove the listeners // to clean up the terminal, we remove the listeners
@ -334,12 +335,10 @@ export default class Term extends React.PureComponent {
onMouseUp={this.onMouseUp} onMouseUp={this.onMouseUp}
> >
{this.props.customChildrenBefore} {this.props.customChildrenBefore}
<div ref={this.onTermWrapperRef} className="term_fit term_wrapper"> <div ref={this.onTermWrapperRef} className="term_fit term_wrapper" />
<div ref={this.onTermRef} className="term_fit term_term" />
</div>
{this.props.customChildren} {this.props.customChildren}
<style jsx>{` <style jsx global>{`
.term_fit { .term_fit {
display: block; display: block;
width: 100%; width: 100%;

View file

@ -42,8 +42,6 @@ export default class Terms extends React.Component {
onRef(uid, term) { onRef(uid, term) {
if (term) { if (term) {
this.terms[uid] = term; this.terms[uid] = term;
} else if (!this.props.sessions[uid]) {
delete this.terms[uid];
} }
} }
@ -71,6 +69,15 @@ export default class Terms extends React.Component {
}); });
} }
componentDidUpdate(prevProps) {
for (let uid in prevProps.sessions) {
if (!this.props.sessions[uid]) {
this.terms[uid].term.dispose();
delete this.terms[uid];
}
}
}
componentWillUnmount() { componentWillUnmount() {
this.props.ref_(null); this.props.ref_(null);
} }