Skip to content
This repository has been archived by the owner on May 19, 2023. It is now read-only.

Commit

Permalink
feat: .perf prop for l-text
Browse files Browse the repository at this point in the history
  • Loading branch information
aidenybai committed Apr 29, 2021
1 parent d4f425d commit dd72554
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 45 deletions.
7 changes: 4 additions & 3 deletions src/core/directives/text.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DirectiveProps } from '../../models/structs';

export const textDirective = ({ el, data, state }: DirectiveProps): void => {
export const textDirective = ({ el, parts, data, state }: DirectiveProps): void => {
const ret = data.compute(state) ?? data.value;
if (ret !== el.innerText) {
el.innerText = ret;
const prop = parts[1] === 'perf' ? 'textContent' : 'innerText';
if (ret !== el[prop]) {
el[prop] = ret;
}
};
90 changes: 48 additions & 42 deletions src/core/render.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DIRECTIVE_PREFIX, UnknownKV } from '../models/generics';
import { ASTNode, ASTNodeType, Directives } from '../models/structs';
import { renderDirective } from './directive';
import lazy from './utils/lazy';
import { rawDirectiveSplitRE } from './utils/patterns';

const render = (
Expand All @@ -10,54 +11,59 @@ const render = (
changedProps: string[] = []
): void => {
const legalDirectiveNames = Object.keys(directives);
const LAZY_MODE_TIMEOUT = 25;

for (const node of ast) {
if (node.type === ASTNodeType.NULL) continue;
const isStatic = node.type === ASTNodeType.STATIC;
if (isStatic) node.type = ASTNodeType.NULL;

const nodeHasDep = changedProps.some((prop) => node.deps.includes(prop));

if (!nodeHasDep && !isStatic) continue;

for (const [directiveName, directiveData] of Object.entries(node.directives)) {
const rawDirectiveName = directiveName.split(rawDirectiveSplitRE())[0];
// Validate if it is a legal directive
if (!legalDirectiveNames.includes(rawDirectiveName.toUpperCase())) continue;
// Iterate through affected and check if directive value has prop
const directiveHasDep = changedProps.some((prop) => directiveData.deps.includes(prop));

const isMaskDirective = directiveName === `${DIRECTIVE_PREFIX}mask`;
const isStaticDirective = Object.keys(directiveData.deps).length === 0;

// If affected, then push to render queue
if (directiveHasDep || isStatic || isStaticDirective) {
const directiveProps = {
el: node.el,
parts: directiveName.split(rawDirectiveSplitRE()),
data: directiveData,
node,
state,
};

renderDirective(directiveProps, directives);

if (isStaticDirective || isMaskDirective) {
delete node.directives[directiveName];
if (isMaskDirective) {
/* istanbul ignore next */
node.el.removeAttribute(`${DIRECTIVE_PREFIX}mask`);
lazy(LAZY_MODE_TIMEOUT, function* () {
for (const node of ast) {
if (node.type === ASTNodeType.NULL) continue;
const isStatic = node.type === ASTNodeType.STATIC;
if (isStatic) node.type = ASTNodeType.NULL;
yield;

const nodeHasDep = changedProps.some((prop) => node.deps.includes(prop));

if (!nodeHasDep && !isStatic) continue;

for (const [directiveName, directiveData] of Object.entries(node.directives)) {
const rawDirectiveName = directiveName.split(rawDirectiveSplitRE())[0];
// Validate if it is a legal directive
if (!legalDirectiveNames.includes(rawDirectiveName.toUpperCase())) continue;
yield;
// Iterate through affected and check if directive value has prop
const directiveHasDep = changedProps.some((prop) => directiveData.deps.includes(prop));

const isMaskDirective = directiveName === `${DIRECTIVE_PREFIX}mask`;
const isStaticDirective = Object.keys(directiveData.deps).length === 0;

// If affected, then push to render queue
if (directiveHasDep || isStatic || isStaticDirective) {
const directiveProps = {
el: node.el,
parts: directiveName.split(rawDirectiveSplitRE()),
data: directiveData,
node,
state,
};

renderDirective(directiveProps, directives);

if (isStaticDirective || isMaskDirective) {
delete node.directives[directiveName];
if (isMaskDirective) {
/* istanbul ignore next */
node.el.removeAttribute(`${DIRECTIVE_PREFIX}mask`);
}
}
}
}
}

// Effect is like a watcher but detects changes to an el
if (node.directives['on:effect']) {
const effectEvent = new CustomEvent('effect');
node.el.dispatchEvent(effectEvent);
// Effect is like a watcher but detects changes to an el
if (node.directives['on:effect']) {
const effectEvent = new CustomEvent('effect');
node.el.dispatchEvent(effectEvent);
}
}
}
})();
};

export default render;
25 changes: 25 additions & 0 deletions src/core/utils/lazy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* istanbul ignore file */

// Lazy allows us to delay render calls if the main thread is blocked
// This is kind of like time slicing in React but less advanced

export const lazy = (
threshold: number,
generatorFunction: () => Generator<undefined, void, unknown>
// eslint-disable-next-line @typescript-eslint/ban-types
): Function => {
const generator = generatorFunction();
return function next() {
const start = performance.now();
let task = null;
do {
task = generator.next();
} while (performance.now() - start < threshold && !task.done);

if (task.done) return;
/* istanbul ignore next */
setTimeout(next);
};
};

export default lazy;

0 comments on commit dd72554

Please # to comment.