serkansipahi / app-decorators Goto Github PK
View Code? Open in Web Editor NEWCollection of JavaScript decorators (ES7) for building fast, scalable, performant web apps
License: MIT License
Collection of JavaScript decorators (ES7) for building fast, scalable, performant web apps
License: MIT License
develop runtime for router.js for reducing filesize and increasing performance
@component({
element: 'div',
name: 'my-element',
is: true,
})
alternate style
@component('div', 'my-element', true)
It should be possible to reinit routes if destroyed and init again when it registered with:
routes.on('myRoute /some/path', () => {});
routes.destroy();
routes.init();
this works well:
let routes = Router.create({
routes: {
'myRoute /some/path': () => {}
}
});
routes.destroy();
routes.init();
find ideas:
js based:
@component({
name: 'todo-list',
extends: 'ul',
})
@inject({
WorkflowService,
UserService
})
class Foo {
create({ WorkflowService, UserService }){
this.workflowService = WorkflowService;
this.userService = UserService;
}
}
html based:
<com-foo>
<env-inject export="$" module="jQuery"></env-inject>
<env-inject export="_" module="underscore"></env-inject>
</com-foo>
<com-image src="foo.jpg" height="200" width="200 />
@component()
class SomeImage {
created({src, height, width}){
}
}
instead of (now)
@component()
class SomeImage {
created(){
this.src;
this.height;
this.width;
}
}
class Foo {
parentMethodCall(){
}
a() { }
b() { }
}
class Bar extends Foo {
parentMethodCall(){
super.parentMethodCall();
}
c() { }
d() { }
}
class Baz extends Bar {
parentMethodCall(){
super.parentMethodCall();
}
e() { }
f() { }
}
@component(HTMLFormElement)
class Yellow extends Baz {
static x() {}
static y() {}
parentMethodCall(){
super.parentMethodCall();
}
createdCallback() {
}
attachedCallback() {
}
attributeChangedCallback(attrName, oldVal, newVal) {
}
detachedCallback() {
}
}
// create domInstance
let yellow = Yellow.instance();
@component({
extends: 'progress',
})
@view(`
<div class="progress-wrapper">
<black-hole category="1"></back-hole>
</div>
`)
class Progress {
}
let progress = Progress.create();
// or if put put this into dom
<progress is="com-progress"></progress>
will render to
<div class="progress-wrapper">
<black-hole>
<progress is="com-progress"></progress>
</back-hole>
</div>
load.js proposal required for outfile (see below)
let load = async (...args, modules) => {
let modules = await Promise.all([...args].map(module => System.import(module)));
Object.assign(modules, _modules);
}
export {
load,
}
in
@component({
name: 'com-page',
extends: 'form',
})
class Pages {
@action('/', ['startpage']) onStartpageAction({ modules, params }){
// ..code ...
}
@action('/?sidebar={{type}}', ['sidebar']) onSidebarAction({ modules, params }){
// ..code ...
}
@on('click .buy', ['checkout', 'payment']) onBuyAction({ modules, event }){
// ..code ...
}
}
out:
import * as _load from './helpers/load'
@component()
class Pages {
@action('/', ['startpage']) async onStartpageAction({ modules, params }){
await _load.load(['startpage'], modules);
// ..code ...
}
@action('/?sidebar={{type}}', ['sidebar']) async onSidebarAction({ modules, params }){
await _load.load(['sidebar'], modules);
// ..code ...
}
@on('click .buy', ['checkout', 'payment']) async onBuyAction({ modules, event }){
await _load.load(['checkout', 'payment'], modules);
// ..code ...
}
}
Info: modules declaration can be used for auto bundling!
@on('resize', window) onResize(event) <== test that type of 'resize'
@on('click .foo') onClick(event) <=== test that type of 'click'
or
Eventhandler.create({
events : {
'click .a': function(event) { // <== test that type of 'click'
}
}
});
const expressions = {
['@on']: /^@on\((\S+)\)$/i,
['@view.bind']: /^@view\.bind\.(\S+)$/i,
};
Looking up npm:app-decorators
Updating registry cache...
Downloading npm:[email protected]
warn Error on processPackageConfig
Package.json dependency es6-module-loader set to npm:[email protected], which is not a valid dependency format for npm.
It's advisable to publish jspm-style packages to GitHub or another registry so conventions are clear.
@component({
extends: 'img'
})
@view(`
<div class="foo">{{id}}</div>
<div class="bar">{{nr}}</div>
`)
@style(´
.bar {
background-color: red;
}
.foo {
background-color: blue;
}
´)
class Baz {
}
should compiled to:
<com-baz>
<style>
.bar {
background-color: red;
}
.foo {
background-color: blue;
}
</style>
<div class="foo"><view-node class="com-baz-id"></view-node></div>
<div class="bar"><view-node class="com-baz-nr"></view-node></div>
<script>
// compiled javascript code from Class Baz
</script>
<!-- or -->
<script async src="file.js"></script>
</com-baz>
https://github.com/SerkanSipahi/app-decorators/blob/master/src/libs/eventhandler.js#L272 change passed third argument to "true!
Redruce complexity of data structure
this:
registerNamespaces: (target) => {
// define $appDecorators.on namespace
if(!target.$appDecorators) target.$appDecorators = {};
if(!target.$appDecorators.on) {
target.$appDecorators.on = {
events : { local: {} },
};
}
// define $onCreated.on namespace
if(!target.$onCreated) target.$onCreated = {};
if(!target.$onCreated.on) target.$onCreated.on = [];
// define $onDetached.on callbacks
if(!target.$onDetached) target.$onDetached = {};
if(!target.$onDetached.on) target.$onDetached.on = [];
// define $onAttached.on callbacks
if(!target.$onAttached) target.$onAttached = {};
if(!target.$onAttached.on) target.$onAttached.on = [];
return target;
}
to
registerNamespaces: (target) => {
// define $appDecorators.on namespace
if(!target.$appDecorators) target.$appDecorators = {};
if(!target.$appDecorators.on) {
target.$appDecorators.on = {
events: { local: {} },
created: [],
attached: [],
detached: [],
};
}
return target;
}
@component()
@view(`
<div class="foo">
<com-loader></com-loader>
<com-foo></com-foo>
</div>
`)
class Foo {
// fetch event bubbles over .loader an event with promise as value.
// If Promise resolved then onFetch will be called
@on('fetch com-loader') @then onFetch({ result }) {
}
@on('ready com-foo') @then onReady({ result }){
}
// eventA, eventB and eventC send an promise through the event.
// only when the promises (internal promise.all) resolved onAbc will be called
@subscribe('eventA, eventB, eventC') @then onAbc({ resA, resB, resC }){
}
}
// or
let component = Comfoo.create();
component.ready.then(() => {
// awesome code
});
// or for subscriber
pubsub.publish('eventA', new Promise((resolve, reject) => setTimeout(resolve, 5000)));
pubsub.publish('eventB', new Promise((resolve, reject) => setTimeout(resolve, 2000)));
pubsub.publish('eventC', new Promise((resolve, reject) => setTimeout(resolve, 3000)));
initianal commit done 8fdec1c
using instead of
export {
foo,
foo as default
};
Name of Plugin: babel-plugin-app-decorators-component
in:
@component()
class Helloworld {
}
out:
@component()
class Helloworld extend HTMLElement {
}
in:
@component({
extends: 'img'
})
class Helloworld {
}
out:
@component({
extends: 'img'
})
class Helloworld extends HTMLImageElement {
}
in:
class Foo {}
class Bar extends Foo {}
@component({
extends: 'form'
})
class Helloworld extends Bar {
}
out:
class Foo extends HTMLFormElement {}
class Bar extends Foo {}
@component({
extends: 'img'
})
class Helloworld extends Bar {
}
see babel-preset-env
Es sollte egal sein welcher decorator als ersten getagged wurde. Es sollte immer gewährleistet werden das eine Klasse mit seinen Komponenten initialisiert werden kann. Hintergrund: Die decorator lösen sich von innen nach außen auf. Wenn wie im "Beispiel 2 - siehe unten" der äußerste decorator nicht die @ component ist, geht @view verloren weil @ component denk er hätte alles und beginnt mit dem instanziieren.
Beispiel 1:
@component()
@view(`
<div>Hello world</div>
`)
@style(`
.bar {
display: block;
}
`)
class Foo {
}
Beispiel 2:
@view(`
<div>Hello world</div>
`)
@component()
@style(`
.bar {
display: block;
}
`)
class Foo {
}
Lösungen/Ideen:
do something like this:
let routerConfig = {
event: {
popstate: 'popstate'
},
popstate_scope: Eventhandler.create({
element: window
}),
};
// and in src/libs/router.js
_bindInternalCoreEvents(){
this.popstate_scope.on(this.event.popstate, ::this._onAction);
}
_removeInternalCoreEvents(){
this.popstate_scope.off(this.event.popstate);
}
this is important because we want to make sure that every event is removed from eventlistener if eventhandler will be destroyed.
let router = Router.create({
scope: document.body,
routes: [
// will match all registered routes
['all /*', function wildcard() {} ],
// will match if route not found and if notFound registered
['notFound /notFound', function notFound() {} ],
],
});
or
let router = Router.create({
scope: document.body,
});
// will match all registered routes
router.on('all /*', () => {
});
// will match if route not found and if notFound registered
router.on('notFound /notFound', () => {
});
see: https://www.w3.org/TR/custom-elements/ (W3C Working Draft 02 October 2016)
see also:
class Foo {
@on('created') created(){
}
@on('attached') attached(){
}
@on('detached') detached(){
}
@on('attributeChanged') attributeChanged(){
}
// or listen a nested component
@on('created com-bar') onCreatedComBar(){
}
@on('ready li[is="item"]') onReadyLiItem(){
}
@on('viewport com-image.big') onViewPortComImage(){
}
}
<google-maps lat="40.731" lng="33.33"></google-maps>
we should use it without "extends". <com-image src="image" /> vs <img is="image" />
<black-hole />
element if CustomElement has Markup:<com-foo> <img class="im-always-here" /> </com-foo>
<com-foo></com-foo>
<my-element></my-element>
<div is="my-element"></div>
.class checkout {
// already implemented
@action('/index') startpage() {
// do something
}
// already implemented
@action('/index/{{id}}/{{type}}?a=1&b=2#c=3&d=4') details({actions, params, hashes}) {
// params and hashes are reserved?!?!
}
// for next step
@post @action('error.html') error(){
}
}
/*
- for e.g. url: /checkout/index/123/descrption
- alias for routename checkout::details, checkout::startpage
- Todo´s for that: need Class Router, and something like a dispatcher
- Useful for Router - HTML5 History-API:
- for resolving url -> new URL('https://my-domain.com')
- see for more information black-book
*/
// For Safari ( dont forget a generic form for see: "src/datas/elements.js" )
if (typeof HTMLElement !== 'function'){
var _HTMLElement = function(){};
_HTMLElement.prototype = HTMLElement.prototype;
HTMLElement = _HTMLElement;
}
// For IE10
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent
(function () {
function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}
CustomEvent.prototype = window.Event.prototype;
window.CustomEvent = CustomEvent;
})();
@ on in views ( by injection )
// example/idea
@view(`
<div @on('click')="methodClickFoo()" class="foo">Foo</div>
<div @on('mousenter')="methodMouseenterFoo()" class="bar">bar</div>
`)
see also polyfill: https://github.com/WebReflection/dom4
Should be removed (Libs)
FRONTEND
- Progressiv Webapps
-- Blogs
+ https://medium.com/javascript-scene/native-apps-are-doomed-ac397148a2c0
- Promises ( use it everywhere you can )
- Web Workers
- Client Caching
- - Service Workers
+ cache api
+ fetch() API
+ Push notifications
+ Web App Manifest
+ on revisit the site browser will install the Site as Webapp ( add to Homescreen )
+ fallback for Service-Workers -> application Cache
+ https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker (examples)
+ https://www.udacity.com/course/offline-web-applications--ud899
+ https://serviceworke.rs/
- - Application Cache
- - Cache Storage
- IndexedDB
- MOBILE
+ add to homescreen
+ app install banner
+ <meta name="theme-color">
- CSS
+ SaSS
+ https://css-tricks.com/authoring-critical-fold-css/
+ will-change
- https://github.com/postcss/postcss-will-change
+ scroll-behavior: smooth
+ https://developers.google.com/web/updates/2016/06/css-containment
- css-containment
- CSSOM
+ http://webkrauts.de/artikel/2015/cssom--cascading-style-sheet-object-model
- Web Animations API
- Request Animation Frame
- Benchmark testing / Profiling
- Blob urls, etc
- render on viewport
- https://github.com/webcomponents/shadydom v1
+ http://blog.aurelia.io/2016/05/23/aurelia-shadow-dom-v1-slots-prerelease/
+ https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom
- https://github.com/webcomponents/shadycss
- https://github.com/GoogleChrome/samples (a repo containing samples tied to new functionality in each release of Google Chrome)
- https://developers.google.com/web/fundamentals/
- https://developers.google.com/web/fundamentals/performance/
- https://github.com/WICG
- prefetch ( <link src="foo.html"> )
- async ( <script src="foo.js" async></scrip> )
- application-shell ( fast init start )
- Improving Scroll Performance with Passive Event Listeners
+ https://developers.google.com/web/updates/2016/06/passive-event-listeners
+ https://www.webreflection.co.uk/blog/2016/04/17/new-dom4-standards
+ https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
+ https://blog.chromium.org/2016/05/new-apis-to-help-developers-improve.html
- Reduce the Scope and Complexity of Style Calculations
+ https://github.com/wilsonpage/fastdom
+ https://developers.google.com/web/fundamentals/performance/rendering/avoid-large-complex-layouts-and-layout-thrashing
+ https://developers.google.com/web/fundamentals/performance/rendering/simplify-paint-complexity-and-reduce-paint-areas
- Javascript-Styleguid
+ https://github.com/airbnb/javascript
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.