apprun 4.0.0 → 6.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +235 -12
- package/LICENSE +1 -1
- package/README.md +225 -110
- package/apprun.d.ts +240 -34
- package/cli/app.js +29 -0
- package/cli/colors.js +69 -0
- package/cli/index.html +13 -0
- package/cli/index.js +96 -0
- package/dist/apprun-code.js +2 -0
- package/dist/apprun-code.js.map +1 -0
- package/dist/apprun-dev-tools.js +1 -1
- package/dist/apprun-dev-tools.js.map +1 -1
- package/dist/apprun-html.esm.js +34 -0
- package/dist/apprun-html.esm.js.map +1 -0
- package/dist/apprun-html.js +2 -1
- package/dist/apprun-html.js.LICENSE.txt +11 -0
- package/dist/apprun-html.js.map +1 -1
- package/dist/apprun-play.js +2 -0
- package/dist/apprun-play.js.map +1 -0
- package/dist/apprun.esm.js +2 -0
- package/dist/apprun.esm.js.map +1 -0
- package/dist/apprun.js +1 -1
- package/dist/apprun.js.map +1 -1
- package/dist/createState.js +2 -0
- package/dist/createState.js.map +1 -0
- package/esm/add-components.js +90 -0
- package/esm/add-components.js.map +1 -0
- package/esm/app.js +209 -0
- package/esm/app.js.map +1 -0
- package/esm/apprun-code.js +170 -0
- package/esm/apprun-code.js.map +1 -0
- package/esm/apprun-dev-tools-tests.js +95 -0
- package/esm/apprun-dev-tools-tests.js.map +1 -0
- package/esm/apprun-dev-tools.js +281 -0
- package/esm/apprun-dev-tools.js.map +1 -0
- package/esm/apprun-html.js +24 -0
- package/esm/apprun-html.js.map +1 -0
- package/esm/apprun-play.js +248 -0
- package/esm/apprun-play.js.map +1 -0
- package/esm/apprun.js +220 -0
- package/esm/apprun.js.map +1 -0
- package/esm/component.js +413 -0
- package/esm/component.js.map +1 -0
- package/esm/createState.js +9 -0
- package/esm/createState.js.map +1 -0
- package/esm/decorator.js +88 -0
- package/esm/decorator.js.map +1 -0
- package/esm/directive.js +306 -0
- package/esm/directive.js.map +1 -0
- package/esm/router.js +345 -0
- package/esm/router.js.map +1 -0
- package/esm/type-utils.js +90 -0
- package/esm/type-utils.js.map +1 -0
- package/esm/types.js +58 -0
- package/esm/types.js.map +1 -0
- package/esm/vdom-lit-html.js +65 -0
- package/esm/vdom-lit-html.js.map +1 -0
- package/esm/vdom-my-prop-attr.js +227 -0
- package/esm/vdom-my-prop-attr.js.map +1 -0
- package/esm/vdom-my.js +293 -0
- package/esm/vdom-my.js.map +1 -0
- package/esm/vdom-to-html.js +54 -0
- package/esm/vdom-to-html.js.map +1 -0
- package/esm/vdom.js +28 -0
- package/esm/vdom.js.map +1 -0
- package/esm/version.js +15 -0
- package/esm/version.js.map +1 -0
- package/esm/web-component.js +155 -0
- package/esm/web-component.js.map +1 -0
- package/jsx-runtime.js +2 -0
- package/jsx-runtime.js.map +1 -0
- package/package.json +90 -41
- package/.travis.yml +0 -10
- package/.vscode/launch.json +0 -19
- package/BACKERS.md +0 -3
- package/apprun-cli.js +0 -177
- package/cli-templates/_gitignore +0 -6
- package/cli-templates/component.ts_ +0 -16
- package/cli-templates/index.html +0 -11
- package/cli-templates/karma.conf.js +0 -24
- package/cli-templates/main.ts_ +0 -13
- package/cli-templates/readme.md +0 -7
- package/cli-templates/spa_index.html +0 -14
- package/cli-templates/spa_main.ts_ +0 -47
- package/cli-templates/spec.ts_ +0 -11
- package/cli-templates/tsconfig.json +0 -12
- package/cli-templates/webpack.config.js +0 -23
- package/demo-html/app.js +0 -2
- package/demo-html/app.js.map +0 -1
- package/demo-html/counter-c.html +0 -29
- package/demo-html/counter-wc-event.html +0 -29
- package/demo-html/counter-wc.html +0 -29
- package/demo-html/counter.html +0 -26
- package/demo-html/index.html +0 -14
- package/demo-html/main.tsx +0 -31
- package/docs/README.md +0 -326
- package/docs/index.html +0 -23
- package/index.html +0 -85
- package/logo.png +0 -0
- package/src/app.ts +0 -69
- package/src/apprun-dev-tools.tsx +0 -67
- package/src/apprun-html.ts +0 -13
- package/src/apprun.ts +0 -53
- package/src/component.ts +0 -189
- package/src/createComponent.tsx +0 -38
- package/src/decorator.ts +0 -36
- package/src/router.ts +0 -19
- package/src/types.ts +0 -9
- package/src/vdom-html.ts +0 -17
- package/src/vdom-my.ts +0 -191
- package/src/vdom-to-html.tsx +0 -45
- package/src/vdom.ts +0 -7
- package/src/web-component.ts +0 -29
- package/tests/app-rx.spec_ +0 -41
- package/tests/app.spec.ts +0 -122
- package/tests/application.spec.tsx +0 -23
- package/tests/component.spec.tsx +0 -296
- package/tests/custom-element.spec.tsx +0 -19
- package/tests/data-attr.spec.tsx +0 -42
- package/tests/decorator.spec.tsx +0 -104
- package/tests/fragment.spec.tsx +0 -79
- package/tests/hyperscript.spec.ts +0 -43
- package/tests/node-test.js +0 -7
- package/tests/router.spec.ts +0 -69
- package/tests/stateful-component.spec.tsx +0 -248
- package/tests/typed.spec.tsx +0 -63
- package/tests/vdom-html.spec.ts +0 -35
- package/tests/vdom-jsx.spec.tsx +0 -131
- package/tests/vdom-my.spec.tsx +0 -195
- package/tests/view-engine.spec.js +0 -59
- package/tsconfig.json +0 -11
- package/tslint.json +0 -124
- package/typescriptreact.json +0 -87
- package/viewEngine.js +0 -54
- package/webpack.config.js +0 -30
package/demo-html/main.tsx
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import app, { Component } from '../src/apprun';
|
|
3
|
-
declare var customElements;
|
|
4
|
-
class MyApp extends Component {
|
|
5
|
-
// state = 0/
|
|
6
|
-
|
|
7
|
-
view = (state) => {
|
|
8
|
-
return <div><h1>{state}</h1></div>
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
update = {
|
|
12
|
-
'-1': (state) => state - 1,
|
|
13
|
-
'+1': (state) => state + 1
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
children;
|
|
17
|
-
rendered = state => {
|
|
18
|
-
this.children.forEach(el => {
|
|
19
|
-
this.element.firstElementChild.appendChild(el)
|
|
20
|
-
});
|
|
21
|
-
this.element.setAttribute('num', state);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
constructor({ num, children } ) {
|
|
25
|
-
super();
|
|
26
|
-
this.children = children;
|
|
27
|
-
this.state = parseInt(num);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
app.webComponent('my-app', MyApp);
|
package/docs/README.md
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
# Building Applications with AppRun
|
|
2
|
-
|
|
3
|
-
AppRun is a 3K library for building applications using the [elm architecture](https://guide.elm-lang.org/architecture) and event publication and subscription.
|
|
4
|
-
|
|
5
|
-
## Architecture
|
|
6
|
-
|
|
7
|
-
According to the elm architecture, there are three separated parts in an application.
|
|
8
|
-
|
|
9
|
-
* Model — the data model of your application state
|
|
10
|
-
* Update — a set of functions to update the state
|
|
11
|
-
* View — a function to display the state as HTML
|
|
12
|
-
|
|
13
|
-
The 15 lines of code below is a simple counter application demonstrates the architecture using AppRun.
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
const state = 0;
|
|
17
|
-
|
|
18
|
-
const view = state => {
|
|
19
|
-
return `<div>
|
|
20
|
-
<h1>${state}</h1>
|
|
21
|
-
<button onclick='app.run("-1")'>-1</button>
|
|
22
|
-
<button onclick='app.run("+1")'>+1</button>
|
|
23
|
-
</div>`;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const update = {
|
|
27
|
-
'+1': state => state + 1,
|
|
28
|
-
'-1': state => state - 1
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
app.start('my-app', state, view, update);
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### The Model
|
|
35
|
-
|
|
36
|
-
The model can be any data structure, a number, an array, or an object that reflects the state of the application. In the counter example, it is a number.
|
|
37
|
-
```
|
|
38
|
-
const state = 0;
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### The Update
|
|
42
|
-
|
|
43
|
-
The update contains functions that take existing state and create new states.
|
|
44
|
-
```
|
|
45
|
-
const update = {
|
|
46
|
-
'+1': state => state + 1,
|
|
47
|
-
'-1': state => state - 1
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### The View
|
|
52
|
-
|
|
53
|
-
The view generates HTML based on the state. AppRun parses the HTML string into virtual dom. It then calculates the differences against the web page element and renders the changes.
|
|
54
|
-
|
|
55
|
-
```
|
|
56
|
-
const view = state => {
|
|
57
|
-
return `<div>
|
|
58
|
-
<h1>${state}</h1>
|
|
59
|
-
<button onclick='app.run("-1")'>-1</button>
|
|
60
|
-
<button onclick='app.run("+1")'>+1</button>
|
|
61
|
-
</div>`;
|
|
62
|
-
};
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Trigger the Update
|
|
66
|
-
|
|
67
|
-
AppRun exposes a global object named _app_ that is accessible globally to trigger the Update by calling _app.run_ function.
|
|
68
|
-
```
|
|
69
|
-
app.run('+1');
|
|
70
|
-
```
|
|
71
|
-
The web page programming is event driven. Connecting web events to AppRun events, you can trigger update functions from user input, click, navigation and etc.
|
|
72
|
-
|
|
73
|
-
E.g. call _app.run_ in HTML markup directly:
|
|
74
|
-
```
|
|
75
|
-
<button id="inc" onclick="app.run('+1')">+1</button>
|
|
76
|
-
```
|
|
77
|
-
Or in JavaScript:
|
|
78
|
-
```
|
|
79
|
-
document.getElementById('inc').addEventListener('click',
|
|
80
|
-
() => app.run('+1'));
|
|
81
|
-
```
|
|
82
|
-
Or with JSX:
|
|
83
|
-
```
|
|
84
|
-
<button onclick={()=>app.run("+1")}>+1</button>
|
|
85
|
-
```
|
|
86
|
-
Or even with jQuery:
|
|
87
|
-
```
|
|
88
|
-
$('#inc').on('click', ()=>app.run('+1'));
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
Finally, _app.start_ function from AppRun ties State, View and Update together to an element and starts the application.
|
|
92
|
-
```
|
|
93
|
-
const element = document.getElementById('my-app');
|
|
94
|
-
app.start(element, State, view, update);
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
To summarize above, the two functions from AppRun (_app.run_ and _app.start_) are all you need to make an application of elm architecture.
|
|
98
|
-
|
|
99
|
-
Try the counter example online: [Simple Counter](https://jsfiddle.net/ap1kgyeb/4).
|
|
100
|
-
|
|
101
|
-
## Event PubSubs
|
|
102
|
-
|
|
103
|
-
At the core, AppRun is an event publication and subscription system, which is also known as event emitter. It is a commonly used pattern in JavaScript programming.
|
|
104
|
-
|
|
105
|
-
AppRun has two important functions: _app.run_ and _app.on_. _app.run_ fires events.
|
|
106
|
-
_app.on_ handles events. E.g. :
|
|
107
|
-
|
|
108
|
-
Module A subscribes to an event _print_:
|
|
109
|
-
```
|
|
110
|
-
import app from 'apprun';
|
|
111
|
-
export () => app.on('print', e => console.log(e));
|
|
112
|
-
```
|
|
113
|
-
Module B publishes the event _print_:
|
|
114
|
-
```
|
|
115
|
-
import app from 'apprun';
|
|
116
|
-
export () => app.run('print', {});
|
|
117
|
-
```
|
|
118
|
-
Main Module:
|
|
119
|
-
```
|
|
120
|
-
import a from './A';
|
|
121
|
-
import b from './B';
|
|
122
|
-
a();
|
|
123
|
-
b();
|
|
124
|
-
```
|
|
125
|
-
Module A and Module B only have to know the event system, not other modules, so they are only dependent on the event system, not other modules. Therefore modules are decoupled. Thus makes it easier to modify, extend and swap modules.
|
|
126
|
-
|
|
127
|
-
The most significant benefit of such event system is decoupling. In traditional MVC architecture, the model, view and controller are coupled, which makes it difficult to test and maintain. In result, there are many architecture patterns have been developed to solve the coupling problem, such as Model-View-Presenter, Presentation Model, and Model-View-ViewModel. AppRun solved the coupling problem by using event publication and subscription. Model, View and Controller/Update don't know each.
|
|
128
|
-
|
|
129
|
-
AppRun applications have an event cycle like below:
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
Web events => AppRun Events => Update => (new state) => View => (HTML)
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
Behind scene AppRun events trigger update functions; the update functions create new states; AppRun then let view function turn the new state into HTML or virtual DOM. Finally AppRun renders the HTML or virtual DOM to web page element.
|
|
136
|
-
|
|
137
|
-
## State Management
|
|
138
|
-
|
|
139
|
-
During the event cycle, AppRun manages application states. It passes current state into the update functions. It takes the new state from the update functions and passes into the view function. Therefore it can maintain the history of all states, which enables the time travel / undo-redo feature.
|
|
140
|
-
|
|
141
|
-
In leverage the time travel / undo-redo feature, the update functions must make sure current state immutable and always create a new state.
|
|
142
|
-
|
|
143
|
-
See the multiple counter example that has undo-redo online: [Multiple counters](https://jsfiddle.net/ap1kgyeb/6)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
## Virtual DOM
|
|
147
|
-
|
|
148
|
-
When applications get complex, we start to think performance and build system.
|
|
149
|
-
|
|
150
|
-
In the simple counter example above, the View creates HTML string out of the state.
|
|
151
|
-
Although HTML string is easy to understand and useful for trying out ideas, it takes
|
|
152
|
-
time to parse it into virtual dom at run time, which may cause performance issue.
|
|
153
|
-
It also has some problems that have been documented by the Facebook React team:
|
|
154
|
-
[Why not template literals](http://facebook.github.io/jsx/#why-not-template-literals).
|
|
155
|
-
|
|
156
|
-
Using JSX, the JSX compiler compiles the JSX into functions at compile time. The View function creates virtual dom in runtime directly without parsing HTML, which gives
|
|
157
|
-
better performance. Therefore, we recommend using JSX in production.
|
|
158
|
-
|
|
159
|
-
To compile and build production code, we recommend using TypeScript and webpack. See CLI section below.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
## Component
|
|
163
|
-
|
|
164
|
-
Another thing to consider when applications get complex is to divide and organize code into components.
|
|
165
|
-
|
|
166
|
-
A component in AppRun is a mini elm architecture, which means inside a component, there are model, view and update. Let's use _AppRun CLI_ to generate a component.
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
apprun -c Counter
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
It generates a Counter component:
|
|
173
|
-
```
|
|
174
|
-
import app, {Component} from 'apprun';
|
|
175
|
-
|
|
176
|
-
export default class CounterComponent extends Component {
|
|
177
|
-
state = 'Counter';
|
|
178
|
-
view = state => {
|
|
179
|
-
return <div>
|
|
180
|
-
<h1>{state}</h1>
|
|
181
|
-
</div>
|
|
182
|
-
}
|
|
183
|
-
update = {
|
|
184
|
-
'#Counter': state => state,
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
To use the Counter component, create an instance of it and then mount the instance to an element.
|
|
190
|
-
|
|
191
|
-
```
|
|
192
|
-
import Counter from './Counter';
|
|
193
|
-
const element = document.getElementById('my-app');
|
|
194
|
-
new Counter().mount(element);
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
Notice the update has a '#Counter' function. It is a route. See Routing section below.
|
|
198
|
-
|
|
199
|
-
### Pure Function Component
|
|
200
|
-
|
|
201
|
-
Pure Function Component is fully supported. Make sure the function name is capitalized.
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
const Counter = ({num, idx}) => (
|
|
205
|
-
<div>
|
|
206
|
-
<h1>{num}</h1>
|
|
207
|
-
<button onclick={() => app.run("-1", idx)}>-1</button>
|
|
208
|
-
<button onclick={() => app.run("+1", idx)}>+1</button>
|
|
209
|
-
<button onclick={() => app.run("remove-counter", idx)}>x</button>
|
|
210
|
-
</div>
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
const CounterList = ({counters}) => counters.map((num, idx) =>
|
|
214
|
-
<Counter num={num} idx={idx} />
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
const view = state => {
|
|
218
|
-
console.log(state);
|
|
219
|
-
return (
|
|
220
|
-
<div>
|
|
221
|
-
<div>
|
|
222
|
-
<button onclick={() => app.run("add-counter")}>add counter</button>
|
|
223
|
-
<button onclick={() => app.run("remove-counter", state.length-1)} disabled={state.length <= 0}>remove counter</button>
|
|
224
|
-
</div>
|
|
225
|
-
<br/>
|
|
226
|
-
<CounterList counters={state} />
|
|
227
|
-
</div>);
|
|
228
|
-
};
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### Child Stateful Component
|
|
232
|
-
|
|
233
|
-
(Working in progress)
|
|
234
|
-
|
|
235
|
-
```
|
|
236
|
-
class TestComponent extends Component {
|
|
237
|
-
state = '';
|
|
238
|
-
view = state => <div>{state}</div>
|
|
239
|
-
update = { }
|
|
240
|
-
constructor({ id }) {
|
|
241
|
-
super();
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
class MainComponent extends Component {
|
|
246
|
-
view = state => {
|
|
247
|
-
return <div>
|
|
248
|
-
<TestComponent id = 'c1' />
|
|
249
|
-
<TestComponent id = 'c2' />
|
|
250
|
-
<TestComponent id = 'c3'/>
|
|
251
|
-
</div>
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
new MainComponent().start('my-app');
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Update function Decorator
|
|
259
|
-
|
|
260
|
-
In AppRun, there are two decorators to make the update functions easier to write and read in component. _@update_ and _@on_. _@update_ is for class functions. _@on_ is for class properties.
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
class TestComponent extends Component {
|
|
264
|
-
view = state => state
|
|
265
|
-
|
|
266
|
-
// function decorator
|
|
267
|
-
@update('hi, #hi')
|
|
268
|
-
f2(state, val) {
|
|
269
|
-
return val;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// property decorator
|
|
273
|
-
@on('hi2, #hi2')
|
|
274
|
-
f2 = (state, val) => val
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
## Routing
|
|
279
|
-
|
|
280
|
-
Because AppRun can connect web page events to AppRun Event, handling routing becomes much easier. AppRun detects the hash changes in URL and calls update functions by matching the hash. E.g., when URL in the browser address bar becomes http://..../#Counter, The #Couter update function of the component will run.
|
|
281
|
-
|
|
282
|
-
Each component defines its route in an update function. The URL changes trigger and run the update function. It can avoid a lot of code for registering and matching routes like in the other frameworks and libraries.
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
## CLI
|
|
286
|
-
|
|
287
|
-
AppRun includes a cli. To install AppRun CLI:
|
|
288
|
-
|
|
289
|
-
```
|
|
290
|
-
npm install apprun -g
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
AppRun CLI can:
|
|
294
|
-
|
|
295
|
-
* Initialize a TypeScript and webpack configured project
|
|
296
|
-
* Initialize git repository
|
|
297
|
-
* Add Jest unit test
|
|
298
|
-
* Generate component
|
|
299
|
-
* Generate SPA application
|
|
300
|
-
|
|
301
|
-
Let's initialize a SPA project.
|
|
302
|
-
|
|
303
|
-
```
|
|
304
|
-
apprun -i --spa
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
The apprun -i command installs apprun, webpack, webpack-dev-server and typescript. It also generates files: tsconfig.json, webpack.config.js, index.html and main.tsx.
|
|
308
|
-
|
|
309
|
-
The apprun --spa command generates files: index.html, main.tsx and three components: Home, About and Contact.
|
|
310
|
-
|
|
311
|
-
After the command finishes execution, you can start the application and then navigate to https://localhost:8080 in a browser.
|
|
312
|
-
|
|
313
|
-
```
|
|
314
|
-
npm start
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
## Performance
|
|
318
|
-
|
|
319
|
-
AppRun itself is lightweight. It is about 3K gzipped. More important is that applications built with AppRun have less line of code, smaller js file, and better performance.
|
|
320
|
-
See a comparison from [A Real-World Comparison of Front-End Frameworks with Benchmarks](https://medium.freecodecamp.org/a-real-world-comparison-of-front-end-frameworks-with-benchmarks-e1cb62fd526c).
|
|
321
|
-
|
|
322
|
-
AppRun has also joined the [js-framework-benchmark](https://github.com/krausest/js-framework-benchmark) project. You can see its [performance results](https://rawgit.com/krausest/js-framework-benchmark/master/webdriver-ts-results/table.html) compared to other frameworks and libraries.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
AppRun makes your applications clean, precious, declarative and has no ceremony.
|
|
326
|
-
Please give it a try and send pull requests.
|
package/docs/index.html
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
|
7
|
-
<title>AppRun</title>
|
|
8
|
-
<link rel="stylesheet" href="https://unpkg.com/docute@3/dist/docute.css">
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<div id="app"></div>
|
|
12
|
-
<script src="https://unpkg.com/docute@3/dist/docute.js"></script>
|
|
13
|
-
<script>
|
|
14
|
-
docute.init({
|
|
15
|
-
// sidebar: false,
|
|
16
|
-
nav: [
|
|
17
|
-
{title: 'Home', path: '/'},
|
|
18
|
-
{title: 'Github', path: 'https://github.com/yysun/apprun'}
|
|
19
|
-
]
|
|
20
|
-
})
|
|
21
|
-
</script>
|
|
22
|
-
</body>
|
|
23
|
-
</html>
|
package/index.html
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
|
6
|
-
<title>AppRun Examples</title>
|
|
7
|
-
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
|
8
|
-
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
|
9
|
-
<link rel="stylesheet" type="text/css" href="demo/styles.css">
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<!-- navbar -->
|
|
13
|
-
<nav class="navbar navbar-default">
|
|
14
|
-
<div class="container">
|
|
15
|
-
<div class="navbar-header">
|
|
16
|
-
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
|
17
|
-
<span class="sr-only">Toggle navigation</span>
|
|
18
|
-
<span class="icon-bar"></span>
|
|
19
|
-
<span class="icon-bar"></span>
|
|
20
|
-
<span class="icon-bar"></span>
|
|
21
|
-
</button>
|
|
22
|
-
<a class="navbar-brand" href="#">AppRun</a>
|
|
23
|
-
</div>
|
|
24
|
-
<div id="navbar" class="navbar-collapse collapse">
|
|
25
|
-
<ul class="nav navbar-nav">
|
|
26
|
-
<!--<li class="active"><a href="#">Home</a></li>-->
|
|
27
|
-
<li class="dropdown">
|
|
28
|
-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Hello
|
|
29
|
-
<span class="caret"></span></a>
|
|
30
|
-
<ul class="dropdown-menu">
|
|
31
|
-
<li><a href="#hello">Hello World</a></li>
|
|
32
|
-
<li><a href="#hello-pushstate">Hello World - Push State</a></li>
|
|
33
|
-
<li><a href="#hello-delayed">Hello World - Delayed</a></li>
|
|
34
|
-
<li><a href="#hello-directive">Hello World - Directive</a></li>
|
|
35
|
-
</ul>
|
|
36
|
-
</li>
|
|
37
|
-
<li class="dropdown">
|
|
38
|
-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Counter
|
|
39
|
-
<span class="caret"></span></a>
|
|
40
|
-
<ul class="dropdown-menu">
|
|
41
|
-
<li><a href="#counter">Simple Counter</a></li>
|
|
42
|
-
<li><a href="#counters">Multiple Counters</a></li>
|
|
43
|
-
</ul>
|
|
44
|
-
</li>
|
|
45
|
-
<li><a href="#blade">Blade</a></li>
|
|
46
|
-
<li><a href="#dragdrop">Drag</a></li>
|
|
47
|
-
<li><a href="#todo">Todo</a></li>
|
|
48
|
-
<li><a href="#multi-selection">Type-ahead</a></li>
|
|
49
|
-
<li><a href="#benchmark">Benchmark</a></li>
|
|
50
|
-
|
|
51
|
-
<li class="dropdown">
|
|
52
|
-
<a class="dropdown-toggle" data-toggle="dropdown" href="#">More
|
|
53
|
-
<span class="caret"></span></a>
|
|
54
|
-
<ul class="dropdown-menu">
|
|
55
|
-
<li><a href="https://yysun.github.io/apprun-hn">Hacker News Reader</a></li>
|
|
56
|
-
<li><a href="https://github.com/gothinkster/apprun-realworld-example-app">RealWorld Example App</a></li>
|
|
57
|
-
<li><a href="https://github.com/yysun/apprun-ssr">Server-Side Rendering</a></li>
|
|
58
|
-
<li><a href="https://github.com/yysun/apprun-multilingual">Multilingual Example</a></li>
|
|
59
|
-
<li><a href="https://github.com/yysun/apprun-firebase-authentication">Firebase Authentication</a></li>
|
|
60
|
-
<li><a href="https://github.com/yysun/apprun-dynamic-components">Dynamic Module Import</a></li>
|
|
61
|
-
<li><a href="https://github.com/yysun/apprun-hot-module-reload">Hot Module Reload with Webpack</a></li>
|
|
62
|
-
<li><a href="https://github.com/yysun/apprun-parcel-bundler">Use Parcel</a></li>
|
|
63
|
-
</ul>
|
|
64
|
-
</li>
|
|
65
|
-
</ul>
|
|
66
|
-
<ul class="nav navbar-nav navbar-right">
|
|
67
|
-
<li><a href="https://github.com/yysun/apprun">Github</a></li>
|
|
68
|
-
</ul>
|
|
69
|
-
</div><!--/.nav-collapse -->
|
|
70
|
-
</div>
|
|
71
|
-
</nav>
|
|
72
|
-
|
|
73
|
-
<div class="container">
|
|
74
|
-
<div id="my-app"></div>
|
|
75
|
-
</div> <!-- /container -->
|
|
76
|
-
|
|
77
|
-
<script src="https://code.jquery.com/jquery-3.1.1.min.js"
|
|
78
|
-
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
|
|
79
|
-
|
|
80
|
-
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
|
|
81
|
-
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
|
82
|
-
|
|
83
|
-
<script src="demo/app.js"></script>
|
|
84
|
-
</body>
|
|
85
|
-
</html>
|
package/logo.png
DELETED
|
Binary file
|
package/src/app.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
export class App {
|
|
2
|
-
|
|
3
|
-
private _events: Object;
|
|
4
|
-
|
|
5
|
-
public start;
|
|
6
|
-
public createElement;
|
|
7
|
-
public render;
|
|
8
|
-
public Fragment;
|
|
9
|
-
public webComponent;
|
|
10
|
-
|
|
11
|
-
constructor() {
|
|
12
|
-
this._events = {};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
on(name: string, fn: (...args) => void, options: any = {}) {
|
|
16
|
-
this._events[name] = this._events[name] || [];
|
|
17
|
-
this._events[name].push({ fn: fn, options: options });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
off(name: string, fn: (...args) => void) {
|
|
21
|
-
let subscribers = this._events[name];
|
|
22
|
-
if (subscribers) {
|
|
23
|
-
subscribers = subscribers.filter((sub) => sub.fn !== fn);
|
|
24
|
-
if (subscribers.length) this._events[name] = subscribers;
|
|
25
|
-
else delete this._events[name]
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
run(name: string, ...args) {
|
|
30
|
-
let subscribers = this._events[name];
|
|
31
|
-
console.assert(!!subscribers, 'No subscriber for event: ' + name);
|
|
32
|
-
if (subscribers) {
|
|
33
|
-
subscribers = subscribers.filter((sub) => {
|
|
34
|
-
const { fn, options } = sub;
|
|
35
|
-
if (options.delay) {
|
|
36
|
-
this.delay(name, fn, args, options);
|
|
37
|
-
} else {
|
|
38
|
-
fn.apply(this, args);
|
|
39
|
-
}
|
|
40
|
-
return !sub.options.once;
|
|
41
|
-
});
|
|
42
|
-
if (subscribers.length) this._events[name] = subscribers;
|
|
43
|
-
else delete this._events[name]
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
once(name: string, fn, options: any = {}) {
|
|
48
|
-
this.on(name, fn, { ...options, once: true });
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private delay(name, fn, args, options) {
|
|
52
|
-
if (options._t) clearTimeout(options._t);
|
|
53
|
-
options._t = setTimeout(() => {
|
|
54
|
-
clearTimeout(options._t);
|
|
55
|
-
fn.apply(this, args);
|
|
56
|
-
}, options.delay);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let app: App;
|
|
61
|
-
declare var global;
|
|
62
|
-
const root = global || window;
|
|
63
|
-
if (root['app'] && root['app']['start']) {
|
|
64
|
-
app = root['app'];
|
|
65
|
-
} else {
|
|
66
|
-
app = new App();
|
|
67
|
-
root['app'] = app;
|
|
68
|
-
}
|
|
69
|
-
export default app;
|
package/src/apprun-dev-tools.tsx
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import app from './app';
|
|
2
|
-
import toHTML from './vdom-to-html';
|
|
3
|
-
|
|
4
|
-
const log = p => console.log(p);
|
|
5
|
-
let debug = false;
|
|
6
|
-
|
|
7
|
-
window['_debug'] = (on) => {
|
|
8
|
-
on ? !debug && app.on('debug', log) : debug && app.off('debug', log);
|
|
9
|
-
debug = on;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function newWin(html) {
|
|
13
|
-
const newWin = window.open('', '_apprun_debug', 'toolbar=0');
|
|
14
|
-
newWin.document.write(`<html>
|
|
15
|
-
<title>AppRun Analyzer | ${document.location.href}</title>
|
|
16
|
-
<style>
|
|
17
|
-
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI" }
|
|
18
|
-
li { margin-left: 30px; }
|
|
19
|
-
</style>
|
|
20
|
-
<body>
|
|
21
|
-
<div id="main">${html}</div>
|
|
22
|
-
</script>
|
|
23
|
-
</body>
|
|
24
|
-
</html>`);
|
|
25
|
-
newWin.document.close();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const Events = ({ events }) => <ul>
|
|
29
|
-
{events && events
|
|
30
|
-
.sort(((a, b) => a.name > b.name ? 1 : -1))
|
|
31
|
-
.map(event => <li>
|
|
32
|
-
{event.name}
|
|
33
|
-
</li>)}
|
|
34
|
-
</ul>;
|
|
35
|
-
|
|
36
|
-
const Components = ({ components }) => <ul>
|
|
37
|
-
{components.map(component => <li>
|
|
38
|
-
<div>{component.constructor.name}</div>
|
|
39
|
-
<Events events={component['_actions']} />
|
|
40
|
-
</li>)}
|
|
41
|
-
</ul>;
|
|
42
|
-
|
|
43
|
-
const view = state => <ul>
|
|
44
|
-
{Object.keys(state).map(name =><li>
|
|
45
|
-
<div>#{name}</div>
|
|
46
|
-
<Components components={state[name]} />
|
|
47
|
-
</li>)}
|
|
48
|
-
</ul>
|
|
49
|
-
|
|
50
|
-
window['_components'] = (print) => {
|
|
51
|
-
const o = { components: {} };
|
|
52
|
-
app.run('get-components', o);
|
|
53
|
-
const { components } = o;
|
|
54
|
-
if (print) {
|
|
55
|
-
const vdom = view(components);
|
|
56
|
-
newWin(toHTML(vdom));
|
|
57
|
-
} else {
|
|
58
|
-
Object.keys(components).forEach(el => {
|
|
59
|
-
const element = typeof el === 'string' ? document.getElementById(el) : el;
|
|
60
|
-
const comps = components[el].map(component => ({
|
|
61
|
-
component,
|
|
62
|
-
events: component['_actions'].sort(((a, b) => a.name > b.name ? 1 : -1)).map(e => e.name),
|
|
63
|
-
}));
|
|
64
|
-
console.log(element, comps);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
package/src/apprun-html.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import app, { Component, View, Action, Update, on, update } from './apprun'
|
|
2
|
-
import { createElement, render, Fragment } from './vdom-html';
|
|
3
|
-
|
|
4
|
-
app.createElement = createElement;
|
|
5
|
-
app.render = render;
|
|
6
|
-
app.Fragment = Fragment;
|
|
7
|
-
|
|
8
|
-
export default app;
|
|
9
|
-
export { Component, View, Action, Update, on, update };
|
|
10
|
-
|
|
11
|
-
if (typeof window === 'object') {
|
|
12
|
-
window['Component'] = Component;
|
|
13
|
-
}
|
package/src/apprun.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import app from './app';
|
|
2
|
-
import { createElement, render, Fragment } from './vdom';
|
|
3
|
-
import { Component } from './component';
|
|
4
|
-
import { VNode, View, Action, Update } from './types';
|
|
5
|
-
import { on, update } from './decorator';
|
|
6
|
-
import route from './router';
|
|
7
|
-
import webComponent from './web-component';
|
|
8
|
-
|
|
9
|
-
export interface IApp {
|
|
10
|
-
start<T>(element?: Element | string, model?: T, view?: View<T>, update?: Update<T>,
|
|
11
|
-
options?: { history?, rendered?: (state: T) => void}): Component<T>;
|
|
12
|
-
on(name: string, fn: (...args: any[]) => void, options?: any): void;
|
|
13
|
-
off(name: string, fn: (...args: any[]) => void): void;
|
|
14
|
-
run(name: string, ...args: any[]): void;
|
|
15
|
-
createElement(tag: string | Function, props, ...children): VNode | VNode[];
|
|
16
|
-
render(element: HTMLElement, node: VNode): void;
|
|
17
|
-
Fragment(props, ...children): any[];
|
|
18
|
-
webComponent(name: string, componentClass, options?): void;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
app.createElement = createElement;
|
|
22
|
-
app.render = render;
|
|
23
|
-
app.Fragment = Fragment;
|
|
24
|
-
app.webComponent = webComponent;
|
|
25
|
-
|
|
26
|
-
app.start = <T>(element?: HTMLElement | string, model?: T, view?: View<T>, update?: Update<T>,
|
|
27
|
-
options?: { history?, rendered?: (state: T) => void }) : Component<T> => {
|
|
28
|
-
const opts = Object.assign(options || {}, { render: true, global_event: true });
|
|
29
|
-
const component = new Component<T>(model, view, update);
|
|
30
|
-
if (options && options.rendered) component.rendered = options.rendered;
|
|
31
|
-
component.mount(element, opts);
|
|
32
|
-
return component;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
if (!app['route']) {
|
|
36
|
-
app['route'] = route;
|
|
37
|
-
app.on('//', _ => { });
|
|
38
|
-
app.on('#', _ => { });
|
|
39
|
-
app.on('route', url => route(url));
|
|
40
|
-
if (typeof document === 'object') {
|
|
41
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
42
|
-
window.onpopstate = () => route(location.hash);
|
|
43
|
-
route(location.hash);
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type StatelessComponent<T={}> = (args: T) => string | VNode | void;
|
|
49
|
-
export { Component, View, Action, Update, on, update };
|
|
50
|
-
export { update as event };
|
|
51
|
-
export default app as IApp;
|
|
52
|
-
|
|
53
|
-
app.on('debug', _ => 0);
|