the ability of computer systems or software to exchange and make use of information.
Stencil is a compiler that generates Web Components (more specifically, Custom Elements)
Svelte compiles your code to tiny, framework-less vanilla JS — your app starts fast and stays fast
A `react` App running two `todo-mvc`s built with `stencil` and `svelte`
- react-app
- node_modules
- stencil-todo-mvc
- svelte-todo-mvc
// ...
import { defineCustomElements } from 'stencil-todo-mvc/dist/esm/loader';
// customElements.define('todo-mvc', TodoMVC)
defineCustomElements(window);
class App extends React.Component {
render() {
return (
<div className="App">
<todo-mvc message={'Hi Stencil'} />
</div>
);
}
}
- stencil-todo-mvc
- dist
- loader.js (305 bytes)
- runtime.js (34.64 kb)
- todo-mvc.entry.js (1.63 kb)
- // browser polyfills loaded on demand
- // ...
import { a as patchEsm, b as bootstrapLazy } from './runtime.js';
// bundle manifest information
const defineCustomElements = (win, options) => {
return patchEsm().then(() => {
bootstrapLazy([["todo-mvc",[[1,"todo-mvc",{"message":[1],"todos":[32],"todoText":[32]}]]]], options);
});
};
export { defineCustomElements };
import { r as registerInstance, h } from './runtime.js';
class TodoMVC {
constructor(hostRef) {
registerInstance(this, hostRef);
this.message = '';
this.todos = [];
this.todoText = '';
this.addNewTODO = () => {
this.todos = [
...this.todos,
{
text: this.todoText,
completed: false,
id: Date.now()
}
];
this.todoText = '';
};
this.toggleDone = (id) => {
this.todos = this.todos.map(todo => {
if (todo.id === id) {
return Object.assign({}, todo, { completed: !todo.completed });
}
return todo;
});
};
this.delete = (id) => {
this.todos = this.todos.filter(todo => todo.id !== id);
console.log(this.todos);
};
}
render() {
return (h("div", null, h("h2", null, "message from \u269B\uFE0F: ", this.message), h("ul", null, this.todos.map(todo => {
return (h("li", null, h("label", null, h("input", { type: "checkbox", checked: todo.completed, onChange: () => { this.toggleDone(todo.id); } }), h("span", { class: todo.completed ? 'done' : '' }, todo.text)), h("button", { onClick: () => { this.delete(todo.id); } }, "Delete")));
})), h("div", null, h("input", { type: "text", ref: (el) => { this.input = el; }, onInput: (e) => { this.todoText = e.target.value; }, value: this.todoText }), h("button", { onClick: this.addNewTODO }, "Add"))));
}
}
export { TodoMVC as todo_mvc };
// ...
import SvelteTodoMVC from 'svelte-todo-mvc/public/bundle.js';
class App extends React.Component {
mountSvelteTodoMVC = (ref) => {
new SvelteTodoMVC({
target: ref,
props: {
message: 'Hi Svelte',
}
})
}
render() {
return (
<div className="App">
<div ref={this.mountSvelteTodoMVC}></div>
</div>
);
}
}
- bundle.js (15.9 Kb, 560 locs)
- runtime (~8 kb, 300 locs)
- todo-mvc (~7 kb, 260 locs)
<script>
let count = 0;
function handleClick() {
// event handler code goes here
count += 1;
}
</script>
<div>
Clicked {count} {count === 1 ? 'time' : 'times'}
</div>
<button on:click={handleClick}>Click</button>
import {
SvelteComponent,
} from "svelte/internal";
function create_fragment(ctx) {
// render logic here
// ...
}
function instance($$self, $$props, $$invalidate) {
let count = 0;
function handleClick() {
// event handler code goes here
$$invalidate('count', count += 1);
}
return {
count,
handleClick
};
}
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, instance, create_fragment, safe_not_equal, []);
}
}
export default App;
import {
SvelteComponent,
append,
detach,
element,
init,
insert,
listen,
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
function create_fragment(ctx) {
var div, t0, t1, t2, t3_value = ctx.count === 1 ? 'time' : 'times',
t3, t4, button, dispose;
return {
c() {
div = element("div");
t0 = text("Clicked ");
t1 = text(ctx.count);
t2 = space();
t3 = text(t3_value);
t4 = space();
button = element("button");
button.textContent = "Click";
dispose = listen(button, "click", ctx.handleClick);
},
m(target, anchor) {
insert(target, div, anchor);
append(div, t0);
append(div, t1);
append(div, t2);
append(div, t3);
insert(target, t4, anchor);
insert(target, button, anchor);
},
p(changed, ctx) {
if (changed.count) {
set_data(t1, ctx.count);
}
if ((changed.count) && t3_value !== (t3_value = ctx.count === 1 ? 'time' : 'times')) {
set_data(t3, t3_value);
}
},
i: noop,
o: noop,
d(detaching) {
if (detaching) {
detach(div);
detach(t4);
detach(button);
}
dispose();
}
};
}
import { Component, h, State, Prop } from '@stencil/core';
type TODO = {
text: string,
completed: boolean,
id: number,
}
@Component({
tag: 'todo-mvc',
shadow: true
})
export class TodoMVC {
@Prop() message: string = '';
@State() todos: TODO[] = [];
@State() todoText: string = '';
addNewTODO = () => {
this.todos = [
...this.todos,
{
text: this.todoText,
completed: false,
id: Date.now()
}
]
this.todoText = '';
}
toggleDone = (id) => {
this.todos = this.todos.map(todo => {
if (todo.id === id) {
return {...todo, completed: !todo.completed};
}
return todo;
});
}
delete = (id) => {
this.todos = this.todos.filter(todo => todo.id !== id);
}
render() {
return (
<div>
<h2>message:{this.message}</h2>
<ul>
{
this.todos.map(todo => {
return (
<li>
<label>
<input type="checkbox" checked={todo.completed} onChange={() => { this.toggleDone(todo.id); }} />
<span class={todo.completed ? 'done' : ''}>{todo.text}</span>
</label>
<button onClick={() => { this.delete(todo.id); }}>Delete</button>
</li>
)
})
}
</ul>
<div>
<input type="text" onInput={(e) => {this.todoText = (e.target as HTMLInputElement).value;}} value={this.todoText} />
<button onClick={this.addNewTODO}>Add</button>
</div>
</div>
);
}
}
<script>
import todos from './store';
let newTODO = '';
export let message = '';
</script>
<style>
.done {
text-decoration: line-through;
}
</style>
<h2>message: {message}</h2>
<ul>
{#each $todos as todo}
<li>
<label>
<input type=checkbox on:input={()=> { todos.toggleTODO(todo.id) }} checked={todo.done} />
<span class={todo.done ? 'done' : ''}>{todo.text}</span>
</label>
<button on:click={()=>{todos.deleteTODO(todo.id)}}>delete</button>
</li>
{/each}
</ul>
<div>
<input type=text bind:value={newTODO}/>
<button on:click={()=> {todos.addNewTodo(newTODO); newTODO = ''}}>Add</button>
</div>
import {
writable
} from 'svelte/store';
const todos = writable([]);
export default {
subscribe: todos.subscribe,
addNewTodo: (text) => {
todos.update(todos => {
return [
...todos,
{
text: text,
done: false,
id: Date.now()
}
]
})
},
deleteTODO: (id) => {
todos.update(todos => todos.filter(todo => todo.id !== id));
},
toggleTODO: (id) => {
todos.update(todos => todos.map(todo => {
if (todo.id === id) {
return { ...todo,
done: !todo.done
}
}
return todo;
}))
}
}
Virtual DOM
Instructions compiled to component code
Out-of-box TypeScript support
p.svelte-ouwt3e
What I like
What I dislike
What I like
What I dislike