pull/1839/head
Rich Harris 7 years ago
parent 0e879524f4
commit 2f627b26b3

@ -33,6 +33,7 @@ function registerExtension(extension) {
const options = Object.assign({}, compileOptions, { const options = Object.assign({}, compileOptions, {
filename, filename,
name: capitalise(name), name: capitalise(name),
generate: 'ssr',
format: 'cjs' format: 'cjs'
}); });

@ -73,10 +73,11 @@ export default function compile(source: string, options: CompileOptions = {}) {
return { ast, stats: stats.render(null), js: null, css: null }; return { ast, stats: stats.render(null), js: null, css: null };
} }
const dom = renderDOM(component, options); const js = options.generate === 'ssr'
const ssr = renderSSR(component, options); ? 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__"} */`, banner: `/* ${component.file ? `${component.file} ` : ``}generated by Svelte v${"__VERSION__"} */`,
name: component.name, name: component.name,
format: options.format || 'esm' format: options.format || 'esm'

@ -16,9 +16,9 @@ export default function(node, renderer, options) {
} }
const bindingProps = node.bindings.map(binding => { const bindingProps = node.bindings.map(binding => {
const { name } = getObject(binding.value.node); const { name } = getObject(binding.expression.node);
const tail = binding.value.node.type === 'MemberExpression' const tail = binding.expression.node.type === 'MemberExpression'
? get_tail_snippet(binding.value.node) ? get_tail_snippet(binding.expression.node)
: ''; : '';
return `${quoteNameIfNecessary(binding.name)}: ctx${quotePropIfNecessary(name)}${tail}`; return `${quoteNameIfNecessary(binding.name)}: ctx${quotePropIfNecessary(name)}${tail}`;
@ -65,7 +65,7 @@ export default function(node, renderer, options) {
? node.component.name ? node.component.name
: node.name === 'svelte:component' : node.name === 'svelte:component'
? `((${node.expression.snippet}) || @missingComponent)` ? `((${node.expression.snippet}) || @missingComponent)`
: `%components-${node.name}` : `ctx.${node.name}`
); );
node.bindings.forEach(binding => { node.bindings.forEach(binding => {
@ -84,7 +84,7 @@ export default function(node, renderer, options) {
`${expression}.data` `${expression}.data`
); );
const { name } = getObject(binding.value.node); const { name } = getObject(binding.expression.node);
renderer.bindings.push(deindent` renderer.bindings.push(deindent`
if (${conditions.reverse().join('&&')}) { 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 = []; const component_options = [];

@ -12,13 +12,7 @@ export default function ssr(
) { ) {
const renderer = new Renderer(); const renderer = new Renderer();
return deindent` const { name } = component;
function $render($$props) {
throw new Error('TODO');
}
`;
const { computations, name, templateProperties } = component;
// create main render() function // create main render() function
renderer.render(trim(component.fragment.children), Object.assign({ renderer.render(trim(component.fragment.children), Object.assign({
@ -29,49 +23,20 @@ export default function ssr(
{ code: null, map: null } : { code: null, map: null } :
component.stylesheet.render(options.filename, true); component.stylesheet.render(options.filename, true);
// generate initial state object
const expectedProperties = Array.from(component.expectedProperties); 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}>`; const debugName = `<${component.customElement ? component.tag : name}>`;
// TODO concatenate CSS maps // TODO concatenate CSS maps
return (deindent` return (deindent`
${js} function #define($$props) {
${component.javascript}
var ${name} = {};
${options.filename && `${name}.filename = ${stringify(options.filename)}`}; return { ${component.declarations.join(', ')} };
}
${name}.data = function() { var ${name} = {};
return ${templateProperties.data ? `%data()` : `{}`};
};
${name}.render = function(state, options = {}) { ${name}.render = function(props = {}, options = {}) {
var components = new Set(); var components = new Set();
function addComponent(component) { function addComponent(component) {
@ -79,7 +44,7 @@ export default function ssr(
} }
var result = { head: '', addComponent }; 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'); 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) { ${name}.$$render = function($$result, ${component.javascript ? 'props' : 'ctx'}, options) {
${templateProperties.store && `options.store = %store();`} ${component.javascript && `const ctx = #define(props);`}
__result.addComponent(${name});
${options.dev && storeProps.length > 0 && !templateProperties.store && deindent` $$result.addComponent(${name});
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);`
)}
${renderer.bindings.length && ${renderer.bindings.length &&
deindent` deindent`
@ -130,8 +84,6 @@ export default function ssr(
}; };
var warned = false; var warned = false;
${templateProperties.preload && `${name}.preload = %preload;`}
`).trim(); `).trim();
} }

@ -65,7 +65,6 @@ function esm(
${code} ${code}
export default ${name}; 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(', ')} };`}`; ${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}");` 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};`) module_exports.map(x => `exports.${x.as} = ${x.name};`)
); );

@ -44,11 +44,11 @@ export function each(items, assign, fn) {
} }
export const missingComponent = { export const missingComponent = {
_render: () => '' $$render: () => ''
}; };
export function validateSsrComponent(component, name) { export function validateSsrComponent(component, name) {
if (!component || !component._render) { if (!component || !component.$$render) {
if (name === 'svelte:component') name += ' this={...}'; 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`); 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`);
} }

Loading…
Cancel
Save