Based on uce and the latest custom-elements polyfill, this module glues most modern Web development patterns in a standard way that yet feels like magic.
The HTML content of each component is handled by tag-params partial utility, while the JS content is normalized as lightweight CommonJS environment, where anyone can feed the module system as they need.
As strawberry on top, hooks are provided behind the scene via the @uce/reactive
utility and thanks to augmentor.
The JS environment is likely the most complex part to grasp though, so here some extra detail on how it works.
The component script definition happens in a virtual Function
sandbox, where all imports and exports are normalized as CommonJS, and a require(module)
utility is provided.
Like it is for CommonJS, the require
utility always returns the same module, once such module has been provided.
In the previous example, the @uce/reactive
is virtually predefined in uce-template, but there are other modules too:
- augmentor to create any hooked wizardry we like
- qsa-observer to monitor nodes if needed
- reactive-props to create any reactive alchemy, even if this is provided already via
@uce/reactive
- uce to eventually import
html
,svg
, orrender
utilities from uhtml - @webreflection/lie to have basic Promise support in IE11 (resolves only)
While import {html} from 'uce'
, and uce in general, is very helpful to compose inner nodes of a defined component, every other module is there only because this library uses these modules to work, and it wouldn't make sense to not provide what's already included in uce-template.
However, it is possible to define any module using the resolve(name, module)
utility:
import {resolve} from 'uce-template';
import MyLibrary from 'MyLibrary';
resolve('my-library', MyLibrary);
Alternatively, it is also possible to define modules via the uce-template
class itself:
customElements.whenDefined('uce-template').then({resolve} => {
resolve('my-utility', {any(){}, module: 'really'});
});
Please note that modules are unique so it is encouraged to use real module names to avoid clashing within third parts libraries.
Modules can also be loaded at runtime, but only if relative or if the CDN supports Cross Origin Requests.
// provided by uce-template
import reactive from '@uce/reactive';
import doubleRainbow from './js/rainbow.js';
export default {
setup(element) {
const state = reactive({ count: 0 });
const inc = () => { state.count++ };
const dec = () => { state.count-- };
console.log(doubleRainbow); // 🌈🌈
return {state, inc, dec};
}
};
The js/rainbow.js
in example should be reachable, and contain some export either via ESM syntax, or CJS, so that export default '🌈🌈'
or module.exports = '🌈🌈'
would be both valid and accepted.
It is our duty to be sure that lazily loaded modules can run within our target browsers, so in case IE11 is one of these targets, it's our duty to transpile those file in a compatible way via Babel or others, as the require
utility only cares about imports and exports.
The advantage of having lazy modules resolution is that a component defined via <template is="uce-template" lazy>
will not need to have all dependencies pre-defined/resolved, and it will download once these only when any instance of such component is spot live.
As it is for ESM and CommonJS, every module is granted to be downloaded once and persist across multiple imports.
If the default export contains props
, or any onevent
handler, all the features available via uce will be available within the component too:
export default {
observedAttributes: ['thing'],
props: {test: 'default value'},
onClick() {
console.log('click');
},
setup(element) {
// setup an own attributeChanged
element.attributeChanged = (name, oldVal, newVal) => {
// will log "thing" and the value
console.log(name, newVal);
};
// log "default value"
console.log(element.test);
}
};
All props
will automatically re-render the component, while observedAttributes
must have an attributeChanged
callback attached on setup.
This is because the whole render is hooked once, and all lifecycle events will belong to it.
To know more about µce features, please check its own repository.