[IMPROVEMENT] Markdown perf (#1796)

This commit is contained in:
Diego Mello 2020-02-28 13:18:03 -03:00 committed by GitHub
parent 64002ba149
commit 39d9a00933
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 164 additions and 850 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ import { themes } from '../../constants/colors';
import styles from './styles';
const AtMention = React.memo(({
mention, mentions, username, navToRoomInfo, preview, style = [], useRealName, theme
mention, mentions, username, navToRoomInfo, style = [], useRealName, theme
}) => {
let mentionStyle = { ...styles.mention, color: themes[theme].buttonText };
if (mention === 'all' || mention === 'here') {
@ -40,8 +40,8 @@ const AtMention = React.memo(({
if (user) {
return (
<Text
style={[preview ? { ...styles.text, color: themes[theme].bodyText } : mentionStyle, ...style]}
onPress={preview ? undefined : handlePress}
style={[mentionStyle, ...style]}
onPress={handlePress}
>
{useRealName ? user.name : user.username}
</Text>
@ -60,7 +60,6 @@ AtMention.propTypes = {
username: PropTypes.string,
navToRoomInfo: PropTypes.func,
style: PropTypes.array,
preview: PropTypes.bool,
useRealName: PropTypes.bool,
theme: PropTypes.string,
mentions: PropTypes.oneOfType([PropTypes.array, PropTypes.object])

View File

@ -7,7 +7,7 @@ import { themes } from '../../constants/colors';
import styles from './styles';
const Hashtag = React.memo(({
hashtag, channels, navToRoomInfo, preview, style = [], theme
hashtag, channels, navToRoomInfo, style = [], theme
}) => {
const handlePress = () => {
const index = channels.findIndex(channel => channel.name === hashtag);
@ -21,8 +21,8 @@ const Hashtag = React.memo(({
if (channels && channels.length && channels.findIndex(channel => channel.name === hashtag) !== -1) {
return (
<Text
style={[preview ? { ...styles.text, color: themes[theme].bodyText } : styles.mention, ...style]}
onPress={preview ? undefined : handlePress}
style={[styles.mention, ...style]}
onPress={handlePress}
>
{hashtag}
</Text>
@ -39,7 +39,6 @@ Hashtag.propTypes = {
hashtag: PropTypes.string,
navToRoomInfo: PropTypes.func,
style: PropTypes.array,
preview: PropTypes.bool,
theme: PropTypes.string,
channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
};

View File

@ -10,7 +10,7 @@ import EventEmitter from '../../utils/events';
import I18n from '../../i18n';
const Link = React.memo(({
children, link, preview, theme
children, link, theme
}) => {
const handlePress = () => {
if (!link) {
@ -28,13 +28,9 @@ const Link = React.memo(({
// if you have a [](https://rocket.chat) render https://rocket.chat
return (
<Text
onPress={preview ? undefined : handlePress}
onLongPress={preview ? undefined : onLongPress}
style={
!preview
? { ...styles.link, color: themes[theme].actionTintColor }
: { color: themes[theme].bodyText }
}
onPress={handlePress}
onLongPress={onLongPress}
style={{ ...styles.link, color: themes[theme].actionTintColor }}
>
{ childLength !== 0 ? children : link }
</Text>
@ -44,8 +40,7 @@ const Link = React.memo(({
Link.propTypes = {
children: PropTypes.node,
link: PropTypes.string,
theme: PropTypes.string,
preview: PropTypes.bool
theme: PropTypes.string
};
export default Link;

View File

@ -3,6 +3,7 @@ import { Text, Image } from 'react-native';
import { Parser, Node } from 'commonmark';
import Renderer from 'commonmark-react-renderer';
import PropTypes from 'prop-types';
import removeMarkdown from 'remove-markdown';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
import I18n from '../../i18n';
@ -18,6 +19,7 @@ import MarkdownEmoji from './Emoji';
import MarkdownTable from './Table';
import MarkdownTableRow from './TableRow';
import MarkdownTableCell from './TableCell';
import mergeTextNodes from './mergeTextNodes';
import styles from './styles';
@ -83,10 +85,10 @@ class Markdown extends PureComponent {
constructor(props) {
super(props);
this.renderer = this.createRenderer(props.preview);
this.renderer = this.createRenderer();
}
createRenderer = (preview = false) => new Renderer({
createRenderer = () => new Renderer({
renderers: {
text: this.renderText,
@ -119,7 +121,7 @@ class Markdown extends PureComponent {
table_row: this.renderTableRow,
table_cell: this.renderTableCell,
editedIndicator: preview ? () => null : this.renderEditedIndicator
editedIndicator: this.renderEditedIndicator
},
renderParagraphsInLists: true
});
@ -141,19 +143,15 @@ class Markdown extends PureComponent {
renderText = ({ context, literal }) => {
const {
numberOfLines, preview, style = []
numberOfLines, style = []
} = this.props;
const defaultStyle = [
this.isMessageContainsOnlyEmoji && !preview ? styles.textBig : {},
this.isMessageContainsOnlyEmoji ? styles.textBig : {},
...context.map(type => styles[type])
];
return (
<Text
style={[
styles.text,
!preview ? defaultStyle : {},
...style
]}
style={[styles.text, defaultStyle, ...style]}
numberOfLines={numberOfLines}
>
{literal}
@ -162,18 +160,16 @@ class Markdown extends PureComponent {
}
renderCodeInline = ({ literal }) => {
const { preview, theme, style = [] } = this.props;
const { theme, style = [] } = this.props;
return (
<Text
style={[
!preview
? {
...styles.codeInline,
color: themes[theme].bodyText,
backgroundColor: themes[theme].bannerBackground,
borderColor: themes[theme].bannerBackground
}
: { ...styles.text, color: themes[theme].bodyText },
{
...styles.codeInline,
color: themes[theme].bodyText,
backgroundColor: themes[theme].bannerBackground,
borderColor: themes[theme].bannerBackground
},
...style
]}
>
@ -183,18 +179,16 @@ class Markdown extends PureComponent {
};
renderCodeBlock = ({ literal }) => {
const { preview, theme, style = [] } = this.props;
const { theme, style = [] } = this.props;
return (
<Text
style={[
!preview
? {
...styles.codeBlock,
color: themes[theme].bodyText,
backgroundColor: themes[theme].bannerBackground,
borderColor: themes[theme].bannerBackground
}
: { ...styles.text, color: themes[theme].bodyText },
{
...styles.codeBlock,
color: themes[theme].bodyText,
backgroundColor: themes[theme].bannerBackground,
borderColor: themes[theme].bannerBackground
},
...style
]}
>
@ -221,11 +215,10 @@ class Markdown extends PureComponent {
};
renderLink = ({ children, href }) => {
const { preview, theme } = this.props;
const { theme } = this.props;
return (
<MarkdownLink
link={href}
preview={preview}
theme={theme}
>
{children}
@ -235,14 +228,13 @@ class Markdown extends PureComponent {
renderHashtag = ({ hashtag }) => {
const {
channels, navToRoomInfo, style, preview, theme
channels, navToRoomInfo, style, theme
} = this.props;
return (
<MarkdownHashtag
hashtag={hashtag}
channels={channels}
navToRoomInfo={navToRoomInfo}
preview={preview}
theme={theme}
style={style}
/>
@ -251,7 +243,7 @@ class Markdown extends PureComponent {
renderAtMention = ({ mentionName }) => {
const {
username, mentions, navToRoomInfo, useRealName, preview, style, theme
username, mentions, navToRoomInfo, useRealName, style, theme
} = this.props;
return (
<MarkdownAtMention
@ -260,7 +252,6 @@ class Markdown extends PureComponent {
useRealName={useRealName}
username={username}
navToRoomInfo={navToRoomInfo}
preview={preview}
theme={theme}
style={style}
/>
@ -269,13 +260,13 @@ class Markdown extends PureComponent {
renderEmoji = ({ emojiName, literal }) => {
const {
getCustomEmoji, baseUrl, customEmojis = true, preview, style, theme
getCustomEmoji, baseUrl, customEmojis = true, style, theme
} = this.props;
return (
<MarkdownEmoji
emojiName={emojiName}
literal={literal}
isMessageContainsOnlyEmoji={this.isMessageContainsOnlyEmoji && !preview}
isMessageContainsOnlyEmoji={this.isMessageContainsOnlyEmoji}
getCustomEmoji={getCustomEmoji}
baseUrl={baseUrl}
customEmojis={customEmojis}
@ -336,10 +327,7 @@ class Markdown extends PureComponent {
};
renderBlockQuote = ({ children }) => {
const { preview, theme } = this.props;
if (preview) {
return children;
}
const { theme } = this.props;
return (
<MarkdownBlockQuote theme={theme}>
{children}
@ -367,7 +355,9 @@ class Markdown extends PureComponent {
}
render() {
const { msg, preview = false } = this.props;
const {
msg, numberOfLines, preview = false, theme, style = []
} = this.props;
if (!msg) {
return null;
@ -378,19 +368,22 @@ class Markdown extends PureComponent {
// Ex: '[ ](https://open.rocket.chat/group/test?msg=abcdef) Test'
// Return: 'Test'
m = m.replace(/^\[([\s]]*)\]\(([^)]*)\)\s/, '').trim();
m = shortnameToUnicode(m);
if (preview) {
m = m.split('\n').reduce((lines, line) => `${ lines } ${ line }`, '');
const ast = parser.parse(m);
return this.renderer.render(ast);
m = m.replace(/\n+/g, ' ');
m = shortnameToUnicode(m);
m = removeMarkdown(m);
return (
<Text style={[styles.text, { color: themes[theme].bodyText }, ...style]} numberOfLines={numberOfLines}>
{m}
</Text>
);
}
const ast = parser.parse(m);
let ast = parser.parse(m);
ast = mergeTextNodes(ast);
this.isMessageContainsOnlyEmoji = isOnlyEmoji(m) && emojiCount(m) <= 3;
this.editedMessage(ast);
return this.renderer.render(ast);
}
}

View File

@ -0,0 +1,27 @@
// TODO: should we add this to our commonmark fork instead?
// we loop through nodes and try to merge all texts
export default function mergeTextNodes(ast) {
// https://github.com/commonmark/commonmark.js/blob/master/lib/node.js#L268
const walker = ast.walker();
let event;
// eslint-disable-next-line no-cond-assign
while (event = walker.next()) {
const { entering, node } = event;
const { type } = node;
if (entering && type === 'text') {
while (node._next && node._next.type === 'text') {
const next = node._next;
node.literal += next.literal;
node._next = next._next;
if (node._next) {
node._next._prev = node;
}
if (node._parent._lastChild === next) {
node._parent._lastChild = node;
}
}
walker.resumeAt(node, false);
}
}
return ast;
}

View File

@ -6,7 +6,6 @@ import I18n from '../../i18n';
import styles from './styles';
import Markdown from '../../containers/markdown';
import { themes } from '../../constants/colors';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
const formatMsg = ({
lastMessage, type, showLastMessage, username, useRealName
@ -37,11 +36,7 @@ const formatMsg = ({
prefix = `${ useRealName ? name : lastMessage.u.username }: `;
}
let msg = `${ prefix }${ lastMessage.msg.replace(/[\n\t\r]/igm, '') }`;
if (msg) {
msg = shortnameToUnicode(msg);
}
return msg;
return `${ prefix }${ lastMessage.msg }`;
};
const arePropsEqual = (oldProps, newProps) => _.isEqual(oldProps, newProps);