diff --git a/register.js b/register.js index 4d971867b8..cbd4a387ac 100644 --- a/register.js +++ b/register.js @@ -33,6 +33,7 @@ function registerExtension(extension) { const options = Object.assign({}, compileOptions, { filename, name: capitalise(name), + generate: 'ssr', format: 'cjs' }); diff --git a/src/compile/index.ts b/src/compile/index.ts index a35fa8193d..ec1243b10d 100644 --- a/src/compile/index.ts +++ b/src/compile/index.ts @@ -73,10 +73,11 @@ export default function compile(source: string, options: CompileOptions = {}) { return { ast, stats: stats.render(null), js: null, css: null }; } - const dom = renderDOM(component, options); - const ssr = renderSSR(component, options); + const js = options.generate === 'ssr' + ? renderSSR(component, options) + : renderDOM(component, options); - return component.generate(`${dom}\n\n${ssr}`, options, { + return component.generate(`${js}`, options, { banner: `/* ${component.file ? `${component.file} ` : ``}generated by Svelte v${"__VERSION__"} */`, name: component.name, format: options.format || 'esm' diff --git a/src/compile/render-ssr/handlers/InlineComponent.ts b/src/compile/render-ssr/handlers/InlineComponent.ts index 7f693d5519..f5dccf01f0 100644 --- a/src/compile/render-ssr/handlers/InlineComponent.ts +++ b/src/compile/render-ssr/handlers/InlineComponent.ts @@ -16,9 +16,9 @@ export default function(node, renderer, options) { } const bindingProps = node.bindings.map(binding => { - const { name } = getObject(binding.value.node); - const tail = binding.value.node.type === 'MemberExpression' - ? get_tail_snippet(binding.value.node) + const { name } = getObject(binding.expression.node); + const tail = binding.expression.node.type === 'MemberExpression' + ? get_tail_snippet(binding.expression.node) : ''; return `${quoteNameIfNecessary(binding.name)}: ctx${quotePropIfNecessary(name)}${tail}`; @@ -65,7 +65,7 @@ export default function(node, renderer, options) { ? node.component.name : node.name === 'svelte:component' ? `((${node.expression.snippet}) || @missingComponent)` - : `%components-${node.name}` + : `ctx.${node.name}` ); node.bindings.forEach(binding => { @@ -84,7 +84,7 @@ export default function(node, renderer, options) { `${expression}.data` ); - const { name } = getObject(binding.value.node); + const { name } = getObject(binding.expression.node); renderer.bindings.push(deindent` if (${conditions.reverse().join('&&')}) { @@ -97,7 +97,7 @@ export default function(node, renderer, options) { `); }); - let open = `\${@validateSsrComponent(${expression}, '${node.name}')._render(__result, ${props}`; + let open = `\${@validateSsrComponent(${expression}, '${node.name}').$$render($$result, ${props}`; const component_options = []; diff --git a/src/compile/render-ssr/index.ts b/src/compile/render-ssr/index.ts index 7aacddbc1d..95f028574d 100644 --- a/src/compile/render-ssr/index.ts +++ b/src/compile/render-ssr/index.ts @@ -12,13 +12,7 @@ export default function ssr( ) { const renderer = new Renderer(); - return deindent` - function $render($$props) { - throw new Error('TODO'); - } - `; - - const { computations, name, templateProperties } = component; + const { name } = component; // create main render() function renderer.render(trim(component.fragment.children), Object.assign({ @@ -29,49 +23,20 @@ export default function ssr( { code: null, map: null } : component.stylesheet.render(options.filename, true); - // generate initial state object const expectedProperties = Array.from(component.expectedProperties); - const globals = expectedProperties.filter(prop => globalWhitelist.has(prop)); - const storeProps = expectedProperties.filter(prop => prop[0] === '$'); - - const initialState = []; - if (globals.length > 0) { - initialState.push(`{ ${globals.map(prop => `${prop} : ${prop}`).join(', ')} }`); - } - - if (storeProps.length > 0) { - const initialize = `_init([${storeProps.map(prop => `"${prop.slice(1)}"`)}])` - initialState.push(`options.store.${initialize}`); - } - - if (templateProperties.data) { - initialState.push(`%data()`); - } else if (globals.length === 0 && storeProps.length === 0) { - initialState.push('{}'); - } - - initialState.push('ctx'); - - let js = null; - if (component.javascript) { - // TODO - } - const debugName = `<${component.customElement ? component.tag : name}>`; // TODO concatenate CSS maps return (deindent` - ${js} - - var ${name} = {}; + function #define($$props) { + ${component.javascript} - ${options.filename && `${name}.filename = ${stringify(options.filename)}`}; + return { ${component.declarations.join(', ')} }; + } - ${name}.data = function() { - return ${templateProperties.data ? `%data()` : `{}`}; - }; + var ${name} = {}; - ${name}.render = function(state, options = {}) { + ${name}.render = function(props = {}, options = {}) { var components = new Set(); function addComponent(component) { @@ -79,7 +44,7 @@ export default function ssr( } var result = { head: '', addComponent }; - var html = ${name}._render(result, state, options); + var html = ${name}.$$render(result, props, options); var cssCode = Array.from(components).map(c => c.css && c.css.code).filter(Boolean).join('\\n'); @@ -93,21 +58,10 @@ export default function ssr( }; } - ${name}._render = function(__result, ctx, options) { - ${templateProperties.store && `options.store = %store();`} - __result.addComponent(${name}); + ${name}.$$render = function($$result, ${component.javascript ? 'props' : 'ctx'}, options) { + ${component.javascript && `const ctx = #define(props);`} - ${options.dev && storeProps.length > 0 && !templateProperties.store && deindent` - if (!options.store) { - throw new Error("${debugName} references store properties, but no store was provided"); - } - `} - - ctx = Object.assign(${initialState.join(', ')}); - - ${computations.map( - ({ key }) => `ctx.${key} = %computed-${key}(ctx);` - )} + $$result.addComponent(${name}); ${renderer.bindings.length && deindent` @@ -130,8 +84,6 @@ export default function ssr( }; var warned = false; - - ${templateProperties.preload && `${name}.preload = %preload;`} `).trim(); } diff --git a/src/compile/wrapModule.ts b/src/compile/wrapModule.ts index 8063fc193e..dfbd262030 100644 --- a/src/compile/wrapModule.ts +++ b/src/compile/wrapModule.ts @@ -65,7 +65,6 @@ function esm( ${code} export default ${name}; - export { $render }; ${module_exports.length > 0 && `export { ${module_exports.map(e => e.name === e.as ? e.name : `${e.name} as ${e.as}`).join(', ')} };`}`; } @@ -106,7 +105,7 @@ function cjs( return `const ${lhs} = require("${node.source.value}");` }); - const exports = [`exports.default = ${name};`, `exports.$render = $render;`].concat( + const exports = [`exports.default = ${name};`].concat( module_exports.map(x => `exports.${x.as} = ${x.name};`) ); diff --git a/src/internal/ssr.js b/src/internal/ssr.js index 4f44c5a252..7464f14a31 100644 --- a/src/internal/ssr.js +++ b/src/internal/ssr.js @@ -44,11 +44,11 @@ export function each(items, assign, fn) { } export const missingComponent = { - _render: () => '' + $$render: () => '' }; export function validateSsrComponent(component, name) { - if (!component || !component._render) { + if (!component || !component.$$render) { if (name === 'svelte:component') name += ' this={...}'; throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules`); }