Skip to content

Commit

Permalink
Merge pull request #742 from contember/perf/static-render
Browse files Browse the repository at this point in the history
static render micro optim
  • Loading branch information
matej21 committed Jul 8, 2024
2 parents 32c8fc7 + a422e0f commit a6d5cc7
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 56 deletions.
2 changes: 2 additions & 0 deletions build/api/binding.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,8 @@ export namespace TokenRegExps {
entityIdentifier: RegExp;
const // (undocumented)
identifier: RegExp;
const // (undocumented)
dotSeparatedIdentifier: RegExp;
}

// @public (undocumented)
Expand Down
6 changes: 3 additions & 3 deletions build/api/react-repeater.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import { EntityListAccessor } from '@contember/binding';
import { JSX as JSX_2 } from 'react/jsx-runtime';
import { default as React_2 } from 'react';
import { ReactNode } from 'react';
import { SugaredFieldProps } from '@contember/react-binding';
import { SugaredQualifiedEntityList } from '@contember/binding';
import { SugaredRelativeEntityList } from '@contember/binding';
import { SugaredRelativeSingleField } from '@contember/binding';

// @public (undocumented)
export const Repeater: React_2.NamedExoticComponent<RepeaterProps>;
Expand Down Expand Up @@ -83,13 +83,13 @@ export type RepeaterProps = RepeaterQualifiedProps | RepeaterRelativeProps;
// @public (undocumented)
export type RepeaterQualifiedProps = SugaredQualifiedEntityList & {
children?: React_2.ReactNode;
sortableBy?: SugaredFieldProps['field'];
sortableBy?: SugaredRelativeSingleField['field'];
};

// @public (undocumented)
export type RepeaterRelativeProps = SugaredRelativeEntityList & {
children?: React_2.ReactNode;
sortableBy?: SugaredFieldProps['field'];
sortableBy?: SugaredRelativeSingleField['field'];
};

// @public (undocumented)
Expand Down
9 changes: 5 additions & 4 deletions build/api/react-slate-editor-legacy.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { RenderElementProps } from 'slate-react';
import * as Slate from 'slate';
import { SugaredFieldProps } from '@contember/react-binding';
import { SugaredRelativeEntityList } from '@contember/react-binding';
import { SugaredRelativeSingleField } from '@contember/react-binding';

// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@contember/react-slate-editor-legacy" does not have an export "BlockRepeater"
// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "@contember/react-slate-editor-legacy" does not have an export "DiscriminatedBlocks"
Expand All @@ -57,17 +58,17 @@ export interface BlockEditorProps extends SugaredRelativeEntityList, CreateEdito
// (undocumented)
children?: ReactNode;
// (undocumented)
contentField: SugaredFieldProps['field'];
contentField: SugaredRelativeSingleField['field'];
// (undocumented)
embedContentDiscriminationField?: SugaredFieldProps['field'];
embedContentDiscriminationField?: SugaredRelativeSingleField['field'];
// (undocumented)
embedHandlers?: Iterable<EmbedHandler>;
// (undocumented)
embedReferenceDiscriminateBy?: SugaredDiscriminateBy;
// (undocumented)
monolithicReferencesMode?: boolean;
// (undocumented)
referenceDiscriminationField?: SugaredFieldProps['field'];
referenceDiscriminationField?: SugaredRelativeSingleField['field'];
// (undocumented)
referencesField?: SugaredRelativeEntityList | string;
// (undocumented)
Expand All @@ -77,7 +78,7 @@ export interface BlockEditorProps extends SugaredRelativeEntityList, CreateEdito
// (undocumented)
renderSortableBlock: OverrideRenderElementOptions['renderSortableBlock'];
// (undocumented)
sortableBy: SugaredFieldProps['field'];
sortableBy: SugaredRelativeSingleField['field'];
}

// @public (undocumented)
Expand Down
6 changes: 6 additions & 0 deletions packages/binding/src/core/MarkerMerger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ export class MarkerMerger {
if (original === fresh) {
return original
}
if (original.size === 0) {
return fresh
}
const newOriginal: Map<PlaceholderName, MeaningfulMarker> = new Map(original)
for (const [placeholderName, freshMarker] of fresh) {
const markerFromOriginal = newOriginal.get(placeholderName)
Expand All @@ -160,6 +163,9 @@ export class MarkerMerger {
if (original === fresh) {
return original
}
if (original.size === 0) {
return fresh
}
const newOriginal: EntityFieldPlaceholders = new Map(original)
for (const [fieldName, freshPlaceholders] of fresh) {
const placeholderFromOriginal = newOriginal.get(fieldName)
Expand Down
75 changes: 52 additions & 23 deletions packages/binding/src/queryLanguage/QueryLanguage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
import { Parser } from './Parser'
import { GraphQlLiteral } from '@contember/client'
import { ParsedHasManyRelation, ParsedHasOneRelation } from './ParserResults'
import { TokenRegExps } from './tokenList'

const emptyObject = Object.freeze({})

Expand Down Expand Up @@ -293,13 +294,17 @@ export class QueryLanguage {
}

private static augmentDesugaredHasOneRelationPath(
path: ParsedHasOneRelation[],
path: (ParsedHasOneRelation | string)[],
unsugarable: UnsugarableHasOneRelation,
environment: Environment,
): HasOneRelation[] {
return path.map((desugaredHasOneRelation, i) =>
// Unsugarable applies to the last
this.desugarHasOneRelation(desugaredHasOneRelation, i === path.length - 1 ? unsugarable : {}, environment),
this.desugarHasOneRelation(
typeof desugaredHasOneRelation === 'string' ? { field: desugaredHasOneRelation } : desugaredHasOneRelation,
i === path.length - 1 ? unsugarable : {},
environment,
),
)
}

Expand Down Expand Up @@ -636,19 +641,30 @@ export class QueryLanguage {
sugaredRelativeSingleEntity: string | SugaredRelativeSingleEntity,
environment: Environment,
): RelativeSingleEntity {
let field: SugaredRelativeSingleEntity['field']
let unsugarableEntity: Omit<SugaredRelativeSingleEntity, 'field'>
if (typeof sugaredRelativeSingleEntity === 'string') {
return this.desugarRelativeSingleEntity({ field: sugaredRelativeSingleEntity }, environment)
field = sugaredRelativeSingleEntity
unsugarableEntity = {}
} else {
field = sugaredRelativeSingleEntity.field
unsugarableEntity = sugaredRelativeSingleEntity
}

const { field, ...unsugarableEntity } = sugaredRelativeSingleEntity
let hasOneRelationPath: HasOneRelation[]
if (typeof field === 'string') {
const parsed = this.parseRelativeSingleEntity(field, environment)
hasOneRelationPath = this.augmentDesugaredHasOneRelationPath(
parsed.hasOneRelationPath,
unsugarableEntity,
environment,
)
// fast path
if (field.match(TokenRegExps.dotSeparatedIdentifier)) {
const parts = field.split('.')
hasOneRelationPath = this.augmentDesugaredHasOneRelationPath(parts, unsugarableEntity, environment)
} else {
const parsed = this.parseRelativeSingleEntity(field, environment)
hasOneRelationPath = this.augmentDesugaredHasOneRelationPath(
parsed.hasOneRelationPath,
unsugarableEntity,
environment,
)
}

} else {
hasOneRelationPath = this.desugarHasOneRelationPath(field, unsugarableEntity, environment)
Expand All @@ -663,18 +679,30 @@ export class QueryLanguage {
sugaredRelativeSingleField: string | SugaredRelativeSingleField,
environment: Environment,
): RelativeSingleField {
let field: SugaredRelativeSingleField['field']
let unsugarableField: Omit<SugaredRelativeSingleField, 'field'>
if (typeof sugaredRelativeSingleField === 'string') {
return this.desugarRelativeSingleField({ field: sugaredRelativeSingleField }, environment)
field = sugaredRelativeSingleField
unsugarableField = {}
} else {
field = sugaredRelativeSingleField.field
unsugarableField = sugaredRelativeSingleField
}

const { field, ...unsugarableField } = sugaredRelativeSingleField

let hasOneRelationPath: HasOneRelation[]
let fieldName: FieldName
if (typeof field === 'string') {
const parsed = this.parseRelativeSingleField(field, environment)
hasOneRelationPath = this.augmentDesugaredHasOneRelationPath(parsed.hasOneRelationPath, {}, environment)
fieldName = parsed.field
// fast path
if (field.match(TokenRegExps.dotSeparatedIdentifier)) {
const parts = field.split('.')
fieldName = parts.pop()!
hasOneRelationPath = this.augmentDesugaredHasOneRelationPath(parts, {}, environment)
} else {
const parsed = this.parseRelativeSingleField(field, environment)
hasOneRelationPath = this.augmentDesugaredHasOneRelationPath(parsed.hasOneRelationPath, {}, environment)
fieldName = parsed.field
}

} else {
hasOneRelationPath = this.desugarHasOneRelationPath(field.hasOneRelationPath, {}, environment)
fieldName = field.field
Expand All @@ -696,16 +724,17 @@ export class QueryLanguage {
sugaredRelativeEntityList: string | SugaredRelativeEntityList,
environment: Environment,
): RelativeEntityList {
let field: SugaredRelativeEntityList['field']
let unsugarableEntityList: Omit<SugaredRelativeEntityList, 'field'>

if (typeof sugaredRelativeEntityList === 'string') {
return this.desugarRelativeEntityList(
{
field: sugaredRelativeEntityList,
},
environment,
)
field = sugaredRelativeEntityList
unsugarableEntityList = {}
} else {
field = sugaredRelativeEntityList.field
unsugarableEntityList = sugaredRelativeEntityList
}

const { field, ...unsugarableEntityList } = sugaredRelativeEntityList
let hasOneRelationPath: HasOneRelation[]
let hasManyRelation: HasManyRelation
if (typeof field === 'string') {
Expand Down
2 changes: 2 additions & 0 deletions packages/binding/src/queryLanguage/tokenList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { createToken, Lexer } from 'chevrotain'
export namespace TokenRegExps {
export const entityIdentifier = /[A-Z_]\w*/
export const identifier = /[a-zA-Z_]\w*/

export const dotSeparatedIdentifier = /^[a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*$/
}

const identifier = createToken({
Expand Down
21 changes: 5 additions & 16 deletions packages/react-repeater/src/components/Repeater.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,21 @@ import React, { useEffect, useMemo } from 'react'
import { verifySortableProp } from '../internal/verifySortableProp'
import { useCreateRepeaterMethods } from '../internal/useCreateRepeaterMethods'
import { RepeaterEntityListAccessorContext, RepeaterMethodsContext, RepeaterSortedEntitiesContext } from '../contexts'
import {
Component,
EntityListSubTree,
HasMany,
repairEntitiesOrder,
sortEntities,
SugaredField,
SugaredFieldProps,
useEntityList,
useEntityListSubTree,
useEnvironment,
} from '@contember/react-binding'
import { EntityListAccessor, QueryLanguage, SugaredQualifiedEntityList, SugaredRelativeEntityList } from '@contember/binding'
import { Component, EntityListSubTree, HasMany, repairEntitiesOrder, sortEntities, SugaredField, useEntityList, useEntityListSubTree, useEnvironment } from '@contember/react-binding'
import { EntityListAccessor, QueryLanguage, SugaredQualifiedEntityList, SugaredRelativeEntityList, SugaredRelativeSingleField } from '@contember/binding'

export type RepeaterRelativeProps =
& SugaredRelativeEntityList
& {
children?: React.ReactNode
sortableBy?: SugaredFieldProps['field']
sortableBy?: SugaredRelativeSingleField['field']
}

export type RepeaterQualifiedProps =
& SugaredQualifiedEntityList
& {
children?: React.ReactNode
sortableBy?: SugaredFieldProps['field']
sortableBy?: SugaredRelativeSingleField['field']
}

export type RepeaterProps =
Expand Down Expand Up @@ -90,7 +79,7 @@ const RepeaterQualified = Component(
interface RepeaterInnerProps {
accessor: EntityListAccessor
children: React.ReactNode
sortableBy?: SugaredFieldProps['field']
sortableBy?: SugaredRelativeSingleField['field']
}

const RepeaterInner = ({ sortableBy, accessor, children }: RepeaterInnerProps) => {
Expand Down
20 changes: 10 additions & 10 deletions packages/react-slate-editor-legacy/src/blockEditor/BlockEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import {
BindingError,
Component,
Environment,
Field,
FieldValue,
HasMany,
SugaredField,
SugaredFieldProps,
SugaredRelativeEntityList,
SugaredRelativeEntityList, SugaredRelativeSingleField,
TreeNodeEnvironmentFactory,
useDesugaredRelativeSingleField,
useEntity,
Expand Down Expand Up @@ -36,17 +36,17 @@ import { createEditor, CreateEditorPublicOptions, paragraphElementType } from '@

export interface BlockEditorProps extends SugaredRelativeEntityList, CreateEditorPublicOptions {

contentField: SugaredFieldProps['field']
sortableBy: SugaredFieldProps['field']
contentField: SugaredRelativeSingleField['field']
sortableBy: SugaredRelativeSingleField['field']
children?: ReactNode

referencesField?: SugaredRelativeEntityList | string
referenceDiscriminationField?: SugaredFieldProps['field']
referenceDiscriminationField?: SugaredRelativeSingleField['field']
monolithicReferencesMode?: boolean
renderReference?: ComponentType<ReferenceElementRendererProps>

embedReferenceDiscriminateBy?: SugaredDiscriminateBy
embedContentDiscriminationField?: SugaredFieldProps['field']
embedContentDiscriminationField?: SugaredRelativeSingleField['field']
embedHandlers?: Iterable<EmbedHandler>
renderSortableBlock: OverrideRenderElementOptions['renderSortableBlock']
}
Expand Down Expand Up @@ -196,11 +196,11 @@ const BlockEditorComponent: FunctionComponent<BlockEditorProps> = Component(
{...(typeof props.referencesField === 'string' ? { field: props.referencesField } : props.referencesField)}
initialEntityCount={0}
>
<SugaredField field={props.referenceDiscriminationField} />
<Field field={props.referenceDiscriminationField} />
{props.children}
{props.embedContentDiscriminationField && (
<>
<SugaredField field={props.embedContentDiscriminationField} />
<Field field={props.embedContentDiscriminationField} />
{embedHandlers.map((handler, i) => (
<Fragment key={i}>{handler.staticRender(environment)}</Fragment>
))}
Expand All @@ -212,8 +212,8 @@ const BlockEditorComponent: FunctionComponent<BlockEditorProps> = Component(
return (
<>
<HasMany field={props.field} initialEntityCount={0}>
<SugaredField field={props.sortableBy} />
<SugaredField field={props.contentField} />
<Field field={props.sortableBy} />
<Field field={props.contentField} />
{!props.monolithicReferencesMode && references}
</HasMany>
{props.monolithicReferencesMode && references}
Expand Down

0 comments on commit a6d5cc7

Please sign in to comment.