Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

cache-component stability

npm versionbuild statusdownloadsjs-standard-style

Cached bel components. Makes rendering elements very fast™. Analogous to React's .shouldComponentUpdate() method, but only using native DOM methods.

Runs a _render function whenever arguments changed according to an _update function. If the _update function determines an update is needed, a newly _rendered bel element is calculated and then nanomorphed onto the children nodes of the last render. After the first render, a _proxy element is always returned. When the component is removed from the live DOM tree, all internal proxy and element references are deleted.

Deprecation Warning

This module is deprecated! Please use nanocomponent instead.

Features

  • makes rendering elements very fast™
  • implemented in only a few lines
  • only uses native DOM methods
  • Class based components, which offer a great place to store methods for re-use.

Usage

// Implementer APIvarCacheComponent=require('cache-component')varhtml=require('bel')functionCachedButton(){if(!(thisinstanceofCachedButton))returnnewCachedButton()this._color=nullCacheComponent.call(this)}CachedButton.prototype=Object.create(CacheComponent.prototype)CachedButton.prototype._render=function(color){this._color=colorreturnhtml`<buttonstyle="background-color: ${color}"> Click Me</button> `}// Override default shallow compare _update functionCachedButton.prototype._update=function(newColor){returnnewColor!==this._color}varelement=CachedButton()letel=element.render('red')// creates new elementletel=element.render('red')// returns cached element (proxy)letel=element.render('blue')// returns cached element (proxy) and mutates children
// Consumer APIvarCachedButton=require('./cached-button.js')varcachedButton=CachedButton()document.body.appendChild(cachedButton.render('green'))

API

CacheComponent.prototype()

Inheritable CachedComponent prototype. Should be inherited from using CacheComponent.call(this) and prototype = Object.create(CacheComponent.prototype).

Internal properties are:

  • this._proxy: proxy element that's returned on subsequent render() calls that don't pass the ._update() check.
  • this._element: rendered element that should be returned from the ._render() call. This is a DOM pointer to the DOM node in the live DOM tree that you actually see and interact with.
  • this._hasWindow: boolean if window exists. Can be used to create elements that render both in the browser and in Node.
  • this._args: a reference to the arguments array that was used during the last _render() call.

CacheComponent.prototype._render([arguments])

Must be implemented. Render an HTML node with arguments. The Node that's returned is cached as this._element. Only called on first render and whenever you return true from prototype._update(). You must return a DOM node from this function on every call.

CacheComponent.prototype._update([arguments])

Return a boolean to determine if prototype._render() should be called. Not called on the first render. Defaults to the following shallow compare function:

CacheElement.prototype._update=function(){varlength=arguments.lengthif(length!==this._args.length)returntruefor(vari=0;i<length;i++){if(arguments[i]!==this._args[i])returntrue}returnfalse}

CacheComponent.prototype._willMount(el)

Called before returning a fully rendered dom node that is presumably inserted into the document. This is called on first render, and once every subsequent render after the element is found to have been removed from the dom. It gets passed a reference el to the dom node that will be returned.

CacheComponent.prototype._didMount(el)

This function is called after the fully rendered dom node is returned and receives a reference el to that dom node. In practice, this hooks indicates the dom node has been mounted and can be interacted with to set scroll position and other attributes.

CacheComponent.prototype._willUpdate(el)

Called before the component will update. _willUpdate gets a el reference so that you can modify the element that will be use to internally morph the mounted dom node.

CacheComponent.prototype._didUpdate()

Called after a mounted component updates. You can use this hook to call scroll to or other dom methods on the mounted component. You can access this._element to reference the root node mounted in the page. This hook does not get a el argument as this node is tossed away at this stage.

Installation

$ npm install cache-component

FAQ

Where does this run?

Make sure you're running a diffing engine that checks for .isSameNode(), if it doesn't you'll end up with super weird results because proxy nodes will probably be rendered which is not what should happen. Probably make sure you're using morphdom or nanomorph. Seriously.

What's a proxy node?

It's a node that overloads Node.isSameNode() to compare it to another node. This is needed because a given DOM node can only exist in one DOM tree at the time, so we need a way to reference mounted nodes in the tree without actually using them. Hence the proxy pattern, and the recently added support for it in certain diffing engines:

varhtml=require('bel')varel1=html`<div>pink is the best</div>`varel2=html`<div>blue is the best</div>`// let's proxy el1varproxy=html`<div></div>`proxy.isSameNode=function(targetNode){return(targetNode===el1)}el1.isSameNode(el1)// trueel1.isSameNode(el2)// falseproxy.isSameNode(el1)// trueproxy.isSameNode(el2)// false

How does it work?

Morphdom is a diffing engine that diffs real DOM trees. It runs a series of checks between nodes to see if they should either be replaced, removed, updated or reordered. This is done using a series of property checks on the nodes.

Since v2.1.0morphdom also runs Node.isSameNode(otherNode). This allows us to override the function and replace it with a custom function that proxies an existing node. Check out the code to see how it works. The result is that if every element in our tree uses cache-component, only elements that have changed will be recomputed and rerendered making things very fast.

nanomorph, which saw first use in choo 5, has supported isSameNode since it's conception.

What's the exact difference between cache-component and nanocomponent?

  • cache-component is very similar to nanocomponent, except it handles morphing for you if you want by re-running the _render function. It works similar to react's component class. Additionally, it retains the class interface so you can store your event handlers on the prototype chain and on the class instance. Once the component is rendered + mounted in the DOM for the first time, cache-component always returns a proxy node.
  • nanocomponent will render a new node initially and always return a proxy node on subsequent calls to prototype.render. This means the component is responsible for mutating any internal changes.

Whats the relationship beteen cache-component and cache-element?

This module was essentially a merge of cache-element v2.0.1 with the API of nanomorph before cache-element switched over to using nanomorph and essentially had a different purpose. There are still ongoing discussions on the future of cache-element. The idea behind the inheritance API is that it provides a handy place to store event handler functions so they don't get redeclared between render frames like inline functions do.

See Also

Similar Packages

License

MIT

About

DEPRECATED: Use nanocomponent. Will continue to operate as normal

Topics

Resources

Stars

16 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages