diff --git a/src/generators/server-side-rendering/index.ts b/src/generators/server-side-rendering/index.ts index 2accc2bc7e..c6741cb958 100644 --- a/src/generators/server-side-rendering/index.ts +++ b/src/generators/server-side-rendering/index.ts @@ -73,16 +73,22 @@ export default function ssr( generator.stylesheet.render(options.filename, true); // generate initial state object - // TODO this doesn't work, because expectedProperties isn't populated - 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 = []; if (globals.length > 0) { initialState.push(`{ ${globals.map(prop => `${prop} : ${prop}`).join(', ')} }`); } + if (storeProps.length > 0) { + initialState.push(`options.store._init([${storeProps.map(prop => `"${prop.slice(1)}"`)}])`); + } + if (templateProperties.data) { initialState.push(`%data()`); - } else if (globals.length === 0) { + } else if (globals.length === 0 && storeProps.length === 0) { initialState.push('{}'); } @@ -99,7 +105,7 @@ export default function ssr( return ${templateProperties.data ? `%data()` : `{}`}; }; - ${name}.render = function(state, options) { + ${name}.render = function(state, options = {}) { state = Object.assign(${initialState.join(', ')}); ${computations.map( diff --git a/src/generators/server-side-rendering/visitors/Component.ts b/src/generators/server-side-rendering/visitors/Component.ts index b582dc13d9..74c7e239e4 100644 --- a/src/generators/server-side-rendering/visitors/Component.ts +++ b/src/generators/server-side-rendering/visitors/Component.ts @@ -79,6 +79,11 @@ export default function visitComponent( let open = `\${${expression}.render({${props}}`; + const options = []; + if (generator.options.store) { + options.push(`store: options.store`); + } + if (node.children.length) { const appendTarget: AppendTarget = { slots: { default: '' }, @@ -95,11 +100,15 @@ export default function visitComponent( .map(name => `${name}: () => \`${appendTarget.slots[name]}\``) .join(', '); - open += `, { slotted: { ${slotted} } }`; + options.push(`slotted: { ${slotted} }`); generator.appendTargets.pop(); } + if (options.length) { + open += `, { ${options.join(', ')} }`; + } + generator.append(open); generator.append(')}'); } diff --git a/src/server-side-rendering/register.js b/src/server-side-rendering/register.js index 254c1e4419..bb4ea61e7b 100644 --- a/src/server-side-rendering/register.js +++ b/src/server-side-rendering/register.js @@ -2,16 +2,22 @@ import * as fs from 'fs'; import * as path from 'path'; import { compile } from '../index.ts'; +const compileOptions = {}; + function capitalise(name) { return name[0].toUpperCase() + name.slice(1); } export default function register(options) { const { extensions } = options; + if (extensions) { _deregister('.html'); extensions.forEach(_register); } + + // TODO make this the default and remove in v2 + if ('store' in options) compileOptions.store = options.store; } function _deregister(extension) { @@ -20,13 +26,15 @@ function _deregister(extension) { function _register(extension) { require.extensions[extension] = function(module, filename) { - const {code} = compile(fs.readFileSync(filename, 'utf-8'), { + const options = Object.assign({}, compileOptions, { filename, name: capitalise(path.basename(filename) .replace(new RegExp(`${extension.replace('.', '\\.')}$`), '')), - generate: 'ssr', + generate: 'ssr' }); + const {code} = compile(fs.readFileSync(filename, 'utf-8'), options); + return module._compile(code, filename); }; } diff --git a/test/js/samples/ssr-no-oncreate-etc/expected-bundle.js b/test/js/samples/ssr-no-oncreate-etc/expected-bundle.js index 9a466e06ae..1dfa59b423 100644 --- a/test/js/samples/ssr-no-oncreate-etc/expected-bundle.js +++ b/test/js/samples/ssr-no-oncreate-etc/expected-bundle.js @@ -4,7 +4,7 @@ SvelteComponent.data = function() { return {}; }; -SvelteComponent.render = function(state, options) { +SvelteComponent.render = function(state, options = {}) { state = Object.assign({}, state); return ``.trim(); diff --git a/test/js/samples/ssr-no-oncreate-etc/expected.js b/test/js/samples/ssr-no-oncreate-etc/expected.js index 51c10c7656..c64b3877ab 100644 --- a/test/js/samples/ssr-no-oncreate-etc/expected.js +++ b/test/js/samples/ssr-no-oncreate-etc/expected.js @@ -6,7 +6,7 @@ SvelteComponent.data = function() { return {}; }; -SvelteComponent.render = function(state, options) { +SvelteComponent.render = function(state, options = {}) { state = Object.assign({}, state); return ``.trim(); diff --git a/test/server-side-rendering/index.js b/test/server-side-rendering/index.js index a9bf847b29..b6bd109c0e 100644 --- a/test/server-side-rendering/index.js +++ b/test/server-side-rendering/index.js @@ -22,7 +22,8 @@ function tryToReadFile(file) { describe("ssr", () => { before(() => { require("../../ssr/register")({ - extensions: ['.svelte', '.html'] + extensions: ['.svelte', '.html'], + store: true }); return setupHtmlEqual(); @@ -98,9 +99,15 @@ describe("ssr", () => { delete require.cache[resolved]; }); + require("../../ssr/register")({ + store: !!config.store + }); + try { const component = require(`../runtime/samples/${dir}/main.html`); - const html = component.render(config.data); + const html = component.render(config.data, { + store: config.store + }); if (config.html) { assert.htmlEqual(html, config.html);