client-side store subscriptions

pull/951/head
Rich Harris 7 years ago
parent 2705532cb0
commit f80ace5fd6

@ -184,15 +184,23 @@ export default function dom(
const debugName = `<${generator.customElement ? generator.tag : name}>`; const debugName = `<${generator.customElement ? generator.tag : name}>`;
// generate initial state object // generate initial state object
const globals = Array.from(generator.expectedProperties).filter(prop => globalWhitelist.has(prop)); const expectedProperties = Array.from(generator.expectedProperties);
const globals = expectedProperties.filter(prop => globalWhitelist.has(prop));
const storeProps = options.store ? expectedProperties.filter(prop => prop[0] === '$') : [];
const initialState = []; const initialState = [];
if (globals.length > 0) { if (globals.length > 0) {
initialState.push(`{ ${globals.map(prop => `${prop} : ${prop}`).join(', ')} }`); initialState.push(`{ ${globals.map(prop => `${prop} : ${prop}`).join(', ')} }`);
} }
if (storeProps.length > 0) {
initialState.push(`this.store._init([${storeProps.map(prop => `"${prop.slice(1)}"`)}])`);
}
if (templateProperties.data) { if (templateProperties.data) {
initialState.push(`%data()`); initialState.push(`%data()`);
} else if (globals.length === 0) { } else if (globals.length === 0 && storeProps.length === 0) {
initialState.push('{}'); initialState.push('{}');
} }
@ -205,6 +213,7 @@ export default function dom(
@init(this, options); @init(this, options);
${generator.usesRefs && `this.refs = {};`} ${generator.usesRefs && `this.refs = {};`}
this._state = @assign(${initialState.join(', ')}); this._state = @assign(${initialState.join(', ')});
${storeProps.length > 0 && `this.store._add(this, [${storeProps.map(prop => `"${prop.slice(1)}"`)}]);`}
${generator.metaBindings} ${generator.metaBindings}
${computations.length && `this._recompute({ ${Array.from(computationDeps).map(dep => `${dep}: 1`).join(', ')} }, this._state);`} ${computations.length && `this._recompute({ ${Array.from(computationDeps).map(dep => `${dep}: 1`).join(', ')} }, this._state);`}
${options.dev && ${options.dev &&
@ -215,7 +224,11 @@ export default function dom(
${generator.bindingGroups.length && ${generator.bindingGroups.length &&
`this._bindingGroups = [${Array(generator.bindingGroups.length).fill('[]').join(', ')}];`} `this._bindingGroups = [${Array(generator.bindingGroups.length).fill('[]').join(', ')}];`}
${templateProperties.ondestroy && `this._handlers.destroy = [%ondestroy]`} ${(templateProperties.ondestroy || storeProps.length) && (
`this._handlers.destroy = [${
[templateProperties.ondestroy && `%ondestroy`, storeProps.length && `@removeFromStore`].filter(Boolean).join(', ')
}]`
)}
${generator.slots.size && `this._slotted = options.slots || {};`} ${generator.slots.size && `this._slotted = options.slots || {};`}

@ -56,6 +56,7 @@ export interface CompileOptions {
legacy?: boolean; legacy?: boolean;
customElement?: CustomElementOptions | true; customElement?: CustomElementOptions | true;
css?: boolean; css?: boolean;
store?: boolean;
onerror?: (error: Error) => void; onerror?: (error: Error) => void;
onwarn?: (warning: Warning) => void; onwarn?: (warning: Warning) => void;

@ -65,12 +65,13 @@ export function get(key) {
} }
export function init(component, options) { export function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() }; component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject(); component._handlers = blankObject();
component._root = options._root || component; component._root = options._root || component;
component._bind = options._bind; component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
} }
export function observe(key, callback, options) { export function observe(key, callback, options) {
@ -187,6 +188,10 @@ export function _unmount() {
this._fragment.u(); this._fragment.u();
} }
export function removeFromStore() {
this.store._remove(this);
}
export var proto = { export var proto = {
destroy: destroy, destroy: destroy,
get: get, get: get,

@ -63,6 +63,7 @@ describe("runtime", () => {
compileOptions.shared = shared; compileOptions.shared = shared;
compileOptions.hydratable = hydrate; compileOptions.hydratable = hydrate;
compileOptions.dev = config.dev; compileOptions.dev = config.dev;
compileOptions.store = !!config.store;
// check that no ES2015+ syntax slipped in // check that no ES2015+ syntax slipped in
if (!config.allowES2015) { if (!config.allowES2015) {
@ -88,7 +89,7 @@ describe("runtime", () => {
} }
} catch (err) { } catch (err) {
failed.add(dir); failed.add(dir);
showOutput(cwd, { shared }, svelte); // eslint-disable-line no-console showOutput(cwd, { shared, store: !!compileOptions.store }, svelte); // eslint-disable-line no-console
throw err; throw err;
} }
} }
@ -134,7 +135,7 @@ describe("runtime", () => {
try { try {
SvelteComponent = require(`./samples/${dir}/main.html`); SvelteComponent = require(`./samples/${dir}/main.html`);
} catch (err) { } catch (err) {
showOutput(cwd, { shared, hydratable: hydrate }, svelte); // eslint-disable-line no-console showOutput(cwd, { shared, hydratable: hydrate, store: !!compileOptions.store }, svelte); // eslint-disable-line no-console
throw err; throw err;
} }
@ -154,7 +155,8 @@ describe("runtime", () => {
const options = Object.assign({}, { const options = Object.assign({}, {
target, target,
hydrate, hydrate,
data: config.data data: config.data,
store: config.store
}, config.options || {}); }, config.options || {});
const component = new SvelteComponent(options); const component = new SvelteComponent(options);
@ -188,12 +190,12 @@ describe("runtime", () => {
config.error(assert, err); config.error(assert, err);
} else { } else {
failed.add(dir); failed.add(dir);
showOutput(cwd, { shared, hydratable: hydrate }, svelte); // eslint-disable-line no-console showOutput(cwd, { shared, hydratable: hydrate, store: !!compileOptions.store }, svelte); // eslint-disable-line no-console
throw err; throw err;
} }
} }
if (config.show) showOutput(cwd, { shared, hydratable: hydrate }, svelte); if (config.show) showOutput(cwd, { shared, hydratable: hydrate, store: !!compileOptions.store }, svelte);
}); });
} }

@ -0,0 +1,19 @@
import Store from '../../../../store.js';
const store = new Store({
name: 'world'
});
export default {
solo: true,
store,
html: `<h1>Hello world!</h1>`,
test(assert, component, target) {
store.set({ name: 'everybody' });
assert.htmlEqual(target.innerHTML, `<h1>Hello everybody!</h1>`);
}
};

@ -0,0 +1 @@
<h1>Hello {{$name}}!</h1>
Loading…
Cancel
Save