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

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

@ -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'

@ -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 = [];

@ -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();
}

@ -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};`)
);

@ -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`);
}

Loading…
Cancel
Save