Comparing version 1.0.0 to 1.0.1
60
celo.js
(function(){ | ||
// Where components are located | ||
let folder = '/components' | ||
// A list to keep track of loaded components, so we don't fetch them twice. | ||
@@ -24,7 +27,13 @@ const loadedComponents = [] | ||
setUpContainer() | ||
else if( tagName.includes('-') && isNew( tagName )){ | ||
getMarkUp( tagName ) | ||
.then( markUp => splitMarkup( markUp )) | ||
.then( markUpSplit => recreateElements( markUpSplit )) | ||
.then( elementList => addMarkUp( elementList )) | ||
if( tagName.includes('-') ){ | ||
if( isNew( tagName ) ){ | ||
markDefined(tagName) | ||
getMarkUp( tagName ) | ||
.then( markUp => splitMarkup( markUp )) | ||
.then( markUpSplit => recreateElements( markUpSplit )) | ||
.then( elementList => addMarkUp( elementList )) | ||
} | ||
} | ||
@@ -45,13 +54,18 @@ } | ||
tagName = tagName.toLowerCase() | ||
return loadedComponents.includes( tagName ) | ||
? false | ||
: loadedComponents.push( tagName ) | ||
return !loadedComponents.includes( tagName ) | ||
} | ||
// Make a note of loaded web component | ||
function markDefined( tagName ){ | ||
loadedComponents.push( tagName ) | ||
} | ||
// Fetches the needed markup from the server | ||
function getMarkUp( tagName ){ | ||
return fetch(`/components/${ tagName }.html`) | ||
return fetch(`${folder}/${ tagName }.html`) | ||
.then( res => { | ||
if( !res.ok ) | ||
console.error(`Component <${ tagName }> not found.`) | ||
if( !res.ok ){ | ||
console.warn(`Component <${ tagName }> not found. Is it a subcomponent?`) | ||
return false | ||
} | ||
else { | ||
@@ -63,8 +77,16 @@ return res.text() | ||
// Splits the markup between pure markup and code, which needs to be parsed differently | ||
function splitMarkup( markUp ){ | ||
let matches = markUp.match(/<script[\S\s]*?>([\S\s]*?)<\/script>/i) | ||
let markUpText = markUp.replace(matches[0],"") | ||
let scriptText = matches[1] | ||
return {markUp:markUpText,script:scriptText} | ||
if(!markUp) return {markUp:"",script:""} | ||
let textMarkup = markUp | ||
let textScript = "" | ||
let scriptRegex = /<script[\S\s]*?>([\S\s]*?)<\/script>/gi | ||
let matchScript | ||
while( matchScript = scriptRegex.exec(markUp) ){ | ||
textMarkup = textMarkup.replace( matchScript[0],"" ) | ||
textScript += matchScript[1] | ||
} | ||
return {markUp:textMarkup,script:textScript} | ||
} | ||
@@ -92,4 +114,10 @@ | ||
// Extend cusdtomElements.define to keep synchrounous tag on the custom elements | ||
let originalCustomElementDefinition = customElements.define | ||
customElements.define = function(){ | ||
loadedComponents.push( arguments[0] ) | ||
return originalCustomElementDefinition.apply( customElements, arguments ) | ||
} | ||
setUpObserver() | ||
}()) |
@@ -1,1 +0,1 @@ | ||
"use strict";function _instanceof(a,b){return null!=b&&"undefined"!=typeof Symbol&&b[Symbol.hasInstance]?b[Symbol.hasInstance](a):a instanceof b}(function(){function a(a){a.forEach(function(a){if(a=a.addedNodes[0],_instanceof(a,HTMLElement)&&a.tagName){var h=a.tagName.toLowerCase();"body"==h?b():h.includes("-")&&c(h)&&d(h).then(function(a){return e(a)}).then(function(a){return f(a)}).then(function(a){return g(a)})}})}function b(){var a=document.createElement("div");a.id="_celo",document.body.appendChild(a)}function c(a){return a=a.toLowerCase(),!h.includes(a)&&h.push(a)}function d(a){return fetch("/components/".concat(a,".html")).then(function(b){return b.ok?b.text():void console.error("Component <".concat(a,"> not found."))})}function e(a){var b=a.match(/<script[\S\s]*?>([\S\s]*?)<\/script>/i),c=a.replace(b[0],""),d=b[1];return{markUp:c,script:d}}function f(a){var b=document.createDocumentFragment(),c=document.createElement("div");for(c.innerHTML=a.markUp;c.firstChild;)b.appendChild(c.firstChild);var d=document.createElement("script");return d.appendChild(document.createTextNode(a.script)),[b,d]}function g(a){var b=document.querySelector("#_celo");a.forEach(function(a){return b.append(a)})}var h=[];(function(){var b=new MutationObserver(a);return b.observe(document,{childList:!0,subtree:!0}),this})()})(); | ||
"use strict";function _instanceof(n,e){return null!=e&&"undefined"!=typeof Symbol&&e[Symbol.hasInstance]?e[Symbol.hasInstance](n):n instanceof e}!function(){var n="/components",e=[];function t(t){t.forEach(function(t){if(_instanceof(t=t.addedNodes[0],HTMLElement)&&t.tagName){var o=t.tagName.toLowerCase();"body"==o&&((c=document.createElement("div")).id="_celo",document.body.appendChild(c)),o.includes("-")&&function(n){return n=n.toLowerCase(),!e.includes(n)}(o)&&(!function(n){e.push(n)}(o),function(e){return fetch("".concat(n,"/").concat(e,".html")).then(function(n){return n.ok?n.text():(console.warn("Component <".concat(e,"> not found. Is it a subcomponent?")),!1)})}(o).then(function(n){return function(n){if(!n)return{markUp:"",script:""};var e,t=n,o="",c=/<script[\S\s]*?>([\S\s]*?)<\/script>/gi;for(;e=c.exec(n);)t=t.replace(e[0],""),o+=e[1];return{markUp:t,script:o}}(n)}).then(function(n){return function(n){var e=document.createDocumentFragment(),t=document.createElement("div");t.innerHTML=n.markUp;for(;t.firstChild;)e.appendChild(t.firstChild);var o=document.createElement("script");return o.appendChild(document.createTextNode(n.script)),[e,o]}(n)}).then(function(n){return function(n){var e=document.querySelector("#_celo");n.forEach(function(n){return e.append(n)})}(n)}))}var c})}var o=customElements.define;customElements.define=function(){return e.push(arguments[0]),o.apply(customElements,arguments)},new MutationObserver(t).observe(document,{childList:!0,subtree:!0})}(); |
{ | ||
"name": "celo", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "A loader for HTML based web components.", | ||
@@ -5,0 +5,0 @@ "main": "celo.js", |
# Celo | ||
This is a loader script for web components written down in HTML, as they should be! It listens for changes in DOM, and when it detects a custom element, it fetches its markup and inserts it in the DOM. | ||
This is a loader script for web components that were written down in HTML, as they should be! It listens for changes in DOM, and when it detects a custom element, it fetches its markup and inserts it in the DOM. Its name comes from **C**ustom **E**lement **LO**ader and from the fact that good names in NPM are hard to get. | ||
## How do I use it? | ||
Each component must be an HTML file located in a folder called "/components" (you can change where in the script file). The name of the HTML file must be lowercase and match the tag name used, so you must use "<my-example>" to call a component called "my-example.html". | ||
Celo must be included at the top of your HTML, as it won't parse any elements before it. | ||
Now you can just add the custom element tags and Celo will load the web components for you. | ||
Celo will autoload the web component for you if your follow the rules: | ||
+ Your should include Celo in your html's <head> since it reacts to the body element entering the DOM. | ||
+ Your components should be in the root folder "/components" (you can change the location in the script file). | ||
+ Each component's name must be lowercase and match the tag intended. So the "<my-example>" component will be loaded from the file "my-example.html". | ||
### A word about subcomponents | ||
You can have multiple components in a single html file, but you should only do it if you have a main component with one or more subcomponents. Think of a _subcomponent_ as: | ||
+ necessary for the main component to function properly; | ||
+ not suitable to be added as a standalone component; | ||
+ not intended to be reused by other components. | ||
Subcomponents are separated from their masters only for clarity. If you add the subcomponent tag to your html, Celo will try to load it from a file matching its tagName, resulting in an error. | ||
## And how does it work? | ||
Celo uses a MutationObserver to listen for any element inserted in the DOM that carries a hyphen. Upon detection, it checks if that component has already been used. If it is a new component, it will fetch the markup and add its code to a hidden div with an id of "#\_celo". | ||
Celo uses a MutationObserver to listen for any element inserted in the DOM that carries a hyphen (ie. a custom element). | ||
Upon detection, it checks if that component has already been used. If it is a new component, it will fetch the markup and add its code to a hidden div with an id of "#\_celo". | ||
### But, there's a caveat | ||
In order to separate markup from code within your component, Celo uses regex instead of parsing the whole thing. Currently it assumes all <script> tags are meant to be added to the light DOM, so if you add them within the <template> tags, they'll be stripped away. | ||
You probably don't _need_ <script> tags within the template and will be using lifecycle hooks anyway. But if you do, _then Celo currently isn't for you_. | ||
## Requirements | ||
Celo has no dependencies, but the non-minified version assumes ES6. | ||
## What it doesn't do | ||
+ The web components, for one. You must create them yourself: I suggest using one HTML file per component with <template>, <style> and <script> tags. | ||
## What Celo doesn't do for you | ||
+ The web components, for one. You must create them yourself. | ||
+ It doesn't make your app descriptive, reactive, responsive or progressive. It just allows you to load web components and lets you do your other chores whichever way you see fit. | ||
+ It doesn't cache your components for other visits. Try setting that up with service workers. | ||
+ It doesn't polyfill your components. | ||
## And how am I supposed to be writing the components? | ||
Here's how a "simple-example.html" file could look like (I'm not advocating this is the _right_ way to do it, just stating that it works): | ||
``` | ||
<template id="tpl-simple-example"> | ||
<div> | ||
<p>This is a demo web component.</p> | ||
</div> | ||
<style> | ||
p{ | ||
padding: 5px 10px; | ||
background-color: antiquewhite; | ||
} | ||
</style> | ||
</template> | ||
<script> | ||
class SimpleExample extends HTMLElement{ | ||
constructor(){ | ||
super() | ||
const el = document.querySelector("#tpl-simple-example") | ||
.content.cloneNode(true) | ||
this.attachShadow({mode:'open'}).appendChild( el ) | ||
} | ||
} | ||
customElements.define( 'simple-example',SimpleExample ) | ||
</script> | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14271
9
101
64