admin管理员组文章数量:1303551
tl;dr I've created a React wrapper to render an array of log messages into a terminal but resizing is giving a weird output (see screenshot). (There is a React-Wrapper on NPM but that wasn't working for my use-case - caused screen flickering)
I'm working on a feature for Guppy where I'm adding Xterm.js for the terminal output. The PR can be found here.
I've added xterm because of hyperlink scanning/parsing and that is working.
But I'm stuck with getting resize to work. If I'm starting the devServer in the app and wait for some text it will display with correct letter width. If I reduce the size I'm getting an output with an incorrect letter width. Like in the following screenshot:
It is always looking correct in the not resized state but after resize it will get the wrong display - so this will happen for enlarging & shrinking the screen width.
The output should look similar to the following screenshot (maybe with some wrapped lines):
I think this is caused by Fit addon or the way I'm handling resizing with the resize observer but I'm not sure.
The span style of xterm letter are getting a width of NaNpx
like in the following screenshot:
Is this caused by a media query I'm using? I haven't seen that yet maybe I have to temporarily disable all media queries to see if that's causing the behaviour.
What I have tried so far:
- Wrapped
this.xterm.fit()
into asetTimeout(func, 0)
but with-out an effect - Modified some of the styles I'm using but I haven't found the cause.
Code
The code I'm using can be found on Github branch feature-terminal-links but here I'd like to extract the parts I've added to get Xterm to work with React:
- I created a styled-ponent
XtermContainer
as a div so I can add Xterm styles and own styling. The following code is insiderender
and will be our xterm.js container (innerRef
will be used later inComponentDidMount
to intialize Xterm with that container):
<XtermContainer
width={width}
height={height}
innerRef={node => (this.node = node)}
/>
- Init xterm in
ponentDidMount
with the container above:
ponentDidMount() {
Terminal.applyAddon(webLinks);
Terminal.applyAddon(localLinks);
Terminal.applyAddon(fit);
this.xterm = new Terminal({
convertEol: true,
fontFamily: `'Fira Mono', monospace`,
fontSize: 15,
rendererType: 'dom', // default is canvas
});
this.xterm.setOption('theme', {
background: COLORS.blue[900],
foreground: COLORS.white,
});
this.xterm.open(this.node);
this.xterm.fit();
/* ... some addon setup code here (not relevant for the problem) ... */
}
- Added react-resize-observer inside of the wrapper that is also containing the terminal container so I can trigger
this.xterm.fit()
if the size changes (in the repo there is asetTimeout
wrapper around for testing).
<ResizeObserver onResize={() => this.xterm && this.xterm.fit()} />
- Using
ponentDidUpdate(prevProps, prevState)
to update the terminal and scroll the terminal to the bottom if the ponent is getting new logs:
ponentDidUpdate(prevProps, prevState) {
if (prevProps.task.logs !== this.state.logs) {
if (this.state.logs.length === 0) {
this.xterm.clear();
}
for (const log of this.state.logs) {
/*
We need to track what we have added to xterm - feels hacky but it's working.
`this.xterm.clear()` and re-render everything caused screen flicker that's why I decided to not use it.
Todo: Check if there is a react-xterm wrapper that is not using xterm.clear or
create a wrapper ponent that can render the logs array (with-out flicker).
*/
if (!this.renderedLogs[log.id]) {
this.writeln(log.text);
this.xterm.scrollToBottom();
this.renderedLogs[log.id] = true;
}
}
}
}
Ideas I have to find the cause:
Check ResizeObserver code.(see update below)- Try to find why xterm css is getting a NaN width. Is Xterm.js using the style width of the container? If yes, maybe that's not correctly set.
Update
OK, the resize obeserver is probably not needed as I'm getting the same behaviour after menting out the <ResizeObserver/>
in render. So I think it's caused by xterm.js or the css in Guppy.
tl;dr I've created a React wrapper to render an array of log messages into a terminal but resizing is giving a weird output (see screenshot). (There is a React-Wrapper on NPM but that wasn't working for my use-case - caused screen flickering)
I'm working on a feature for Guppy where I'm adding Xterm.js for the terminal output. The PR can be found here.
I've added xterm because of hyperlink scanning/parsing and that is working.
But I'm stuck with getting resize to work. If I'm starting the devServer in the app and wait for some text it will display with correct letter width. If I reduce the size I'm getting an output with an incorrect letter width. Like in the following screenshot:
It is always looking correct in the not resized state but after resize it will get the wrong display - so this will happen for enlarging & shrinking the screen width.
The output should look similar to the following screenshot (maybe with some wrapped lines):
I think this is caused by Fit addon or the way I'm handling resizing with the resize observer but I'm not sure.
The span style of xterm letter are getting a width of NaNpx
like in the following screenshot:
Is this caused by a media query I'm using? I haven't seen that yet maybe I have to temporarily disable all media queries to see if that's causing the behaviour.
What I have tried so far:
- Wrapped
this.xterm.fit()
into asetTimeout(func, 0)
but with-out an effect - Modified some of the styles I'm using but I haven't found the cause.
Code
The code I'm using can be found on Github branch feature-terminal-links but here I'd like to extract the parts I've added to get Xterm to work with React:
- I created a styled-ponent
XtermContainer
as a div so I can add Xterm styles and own styling. The following code is insiderender
and will be our xterm.js container (innerRef
will be used later inComponentDidMount
to intialize Xterm with that container):
<XtermContainer
width={width}
height={height}
innerRef={node => (this.node = node)}
/>
- Init xterm in
ponentDidMount
with the container above:
ponentDidMount() {
Terminal.applyAddon(webLinks);
Terminal.applyAddon(localLinks);
Terminal.applyAddon(fit);
this.xterm = new Terminal({
convertEol: true,
fontFamily: `'Fira Mono', monospace`,
fontSize: 15,
rendererType: 'dom', // default is canvas
});
this.xterm.setOption('theme', {
background: COLORS.blue[900],
foreground: COLORS.white,
});
this.xterm.open(this.node);
this.xterm.fit();
/* ... some addon setup code here (not relevant for the problem) ... */
}
- Added react-resize-observer inside of the wrapper that is also containing the terminal container so I can trigger
this.xterm.fit()
if the size changes (in the repo there is asetTimeout
wrapper around for testing).
<ResizeObserver onResize={() => this.xterm && this.xterm.fit()} />
- Using
ponentDidUpdate(prevProps, prevState)
to update the terminal and scroll the terminal to the bottom if the ponent is getting new logs:
ponentDidUpdate(prevProps, prevState) {
if (prevProps.task.logs !== this.state.logs) {
if (this.state.logs.length === 0) {
this.xterm.clear();
}
for (const log of this.state.logs) {
/*
We need to track what we have added to xterm - feels hacky but it's working.
`this.xterm.clear()` and re-render everything caused screen flicker that's why I decided to not use it.
Todo: Check if there is a react-xterm wrapper that is not using xterm.clear or
create a wrapper ponent that can render the logs array (with-out flicker).
*/
if (!this.renderedLogs[log.id]) {
this.writeln(log.text);
this.xterm.scrollToBottom();
this.renderedLogs[log.id] = true;
}
}
}
}
Ideas I have to find the cause:
Check ResizeObserver code.(see update below)- Try to find why xterm css is getting a NaN width. Is Xterm.js using the style width of the container? If yes, maybe that's not correctly set.
Update
OK, the resize obeserver is probably not needed as I'm getting the same behaviour after menting out the <ResizeObserver/>
in render. So I think it's caused by xterm.js or the css in Guppy.
1 Answer
Reset to default 5I have a fix for the issue. It's now working in the above mentioned feature branch. Not sure if there is a better solution but it's working for me.
I like to explain how I have fixed the resizing issue:
The problem was the OnlyOn
ponent that was used in DevelopmentServerPane
. It always rendered two TerminalOutput
ponents. One terminal was hidden with display: none
and the other was displayed with display: inline
- the style change was handled with a media query inside a styled-ponent.
After replacing OnlyOn
with React-responsive and using the render props to check mdMin
breakpoint it was working as expected. React-responsive is removing the not displayed mediaquery ponent from DOM so only one terminal in DOM at the same time.
I still don't know why there was a problem with the letter width but probably the two instances collided somehow. I couldn't create a minimal reproduction. I tried to recreate the issue in this Codesandbox but I have only resized one Terminal at a time and so I haven't got the issue there.
The code that fixed the problem (simplified version from the above mentioned repo):
import MediaQuery from 'react-responsive';
const BREAKPOINT_SIZES = {
sm: 900,
};
const BREAKPOINTS = {
mdMin: `(min-width: ${BREAKPOINT_SIZES.sm + 1}px)`,
};
const DevelopmentServerPane = () => (
<MediaQuery query={BREAKPOINTS['mdMin']}>
{matches =>
matches ? (
<div>{/* ... render Terminal for matching mdMin and above */}</div>
) : (
<div> {/* ... render Terminal for small screens */}</div>
)
}
</MediaQuery>
);
本文标签: javascriptHow to get Xtermjs resize properlyStack Overflow
版权声明:本文标题:javascript - How to get Xterm.js resize properly? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741759112a2396294.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论