0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-24 20:42:43 +00:00

Do not Server-Side Render the markdown (#1177)

1) Rendering is fast enough on the client we don't need to provide SSR for the brew contents.
2) This leaves our server open to REDOS attacks if users create ridiculously long single lines of text. The Markdown parser slows down with exponential time which becomes noticeable at 10,000+ characters in one line, and at 200,000+ characters will stall the server and eventually crash.
3) This now shows a nice loading circle for the half-second that a page takes to render. If a user tries to load a huge line of text the loading circle will be there instead of a blank white page.
This commit is contained in:
Trevor Buckner
2021-01-02 16:54:50 -05:00
committed by GitHub
parent 19ca1db674
commit aa065fa4d8

View File

@@ -58,9 +58,7 @@ const BrewRenderer = createClass({
updateSize : function() {
this.setState({
height : this.refs.main.parentNode.clientHeight,
isMounted : true,
visibility : 'visible'
height : this.refs.main.parentNode.clientHeight,
});
},
@@ -116,7 +114,7 @@ const BrewRenderer = createClass({
renderPages : function(){
if(this.state.usePPR){
return _.map(this.state.pages, (page, index)=>{
if(this.shouldRender(page, index)){
if(this.shouldRender(page, index) && typeof window !== 'undefined'){
return this.renderPage(page, index);
} else {
return this.renderDummyPage(index);
@@ -125,7 +123,11 @@ const BrewRenderer = createClass({
}
if(this.props.errors && this.props.errors.length) return this.lastRender;
this.lastRender = _.map(this.state.pages, (page, index)=>{
return this.renderPage(page, index);
if(typeof window !== 'undefined') {
return this.renderPage(page, index);
} else {
return this.renderDummyPage(index);
}
});
return this.lastRender;
},
@@ -134,13 +136,28 @@ const BrewRenderer = createClass({
setTimeout(()=>{ //We still see a flicker where the style isn't applied yet, so wait 100ms before showing iFrame
this.updateSize();
window.addEventListener('resize', this.updateSize);
this.renderPages(); //Make sure page is renderable before showing
this.setState({
isMounted : true,
visibility : 'visible'
});
}, 100);
},
render : function(){
//render in iFrame so broken code doesn't crash the site.
//Also render dummy page while iframe is mounting.
return (
<React.Fragment>
{!this.state.isMounted
? <div className='brewRenderer' onScroll={this.handleScroll}>
<div className='pages' ref='pages'>
{this.renderDummyPage(1)}
</div>
</div>
: null}
<Frame initialContent={this.state.initialContent} style={{ width: '100%', height: '100%', visibility: this.state.visibility }} contentDidMount={this.frameDidMount}>
<div className='brewRenderer'
onScroll={this.handleScroll}
@@ -153,7 +170,9 @@ const BrewRenderer = createClass({
</div>
<div className='pages' ref='pages'>
{this.renderPages()}
{this.state.isMounted
? this.renderPages()
: null}
</div>
</div>
</Frame>