simplify SSR codegen

pull/559/head
Rich-Harris 8 years ago
parent 3efb5ab993
commit 43091431d1

@ -19,9 +19,7 @@ class DomGenerator extends Generator {
this.readonly = new Set(); this.readonly = new Set();
// initial values for e.g. window.innerWidth, if there's a <:Window> meta tag // initial values for e.g. window.innerWidth, if there's a <:Window> meta tag
this.builders = { this.metaBindings = [];
metaBindings: new CodeBuilder()
};
} }
helper ( name ) { helper ( name ) {
@ -91,11 +89,13 @@ export default function dom ( parsed, source, options ) {
if ( typeof newState !== 'object' ) { if ( typeof newState !== 'object' ) {
throw new Error( 'Component .set was called without an object of data key-values to update.' ); throw new Error( 'Component .set was called without an object of data key-values to update.' );
} }
`);
Array.from( generator.readonly ).forEach( prop => { ${
builders._set.addLine( `if ( '${prop}' in newState && !this._updatingReadonlyProperty ) throw new Error( "Cannot set read-only property '${prop}'" );` ); Array.from( generator.readonly ).map( prop =>
}); `if ( '${prop}' in newState && !this._updatingReadonlyProperty ) throw new Error( "Cannot set read-only property '${prop}'" );`
)
}
`);
} }
// TODO is the `if ( this._fragment )` condition necessary? // TODO is the `if ( this._fragment )` condition necessary?
@ -170,7 +170,7 @@ export default function dom ( parsed, source, options ) {
${options.dev && `if ( !options.target && !options._root ) throw new Error( "'target' is a required option" );`} ${options.dev && `if ( !options.target && !options._root ) throw new Error( "'target' is a required option" );`}
${generator.usesRefs && `this.refs = {};`} ${generator.usesRefs && `this.refs = {};`}
this._state = ${templateProperties.data ? `${generator.helper( 'assign' )}( ${generator.alias( 'template' )}.data(), options.data )` : `options.data || {}`}; this._state = ${templateProperties.data ? `${generator.helper( 'assign' )}( ${generator.alias( 'template' )}.data(), options.data )` : `options.data || {}`};
${generator.builders.metaBindings} ${generator.metaBindings}
${computations.length && `${generator.alias( 'recompute' )}( this._state, this._state, {}, true );`} ${computations.length && `${generator.alias( 'recompute' )}( this._state, this._state, {}, true );`}
${options.dev && Array.from( generator.expectedProperties ).map( prop => `if ( !( '${prop}' in this._state ) ) console.warn( "Component was created without expected data property '${prop}'" );`)} ${options.dev && Array.from( generator.expectedProperties ).map( prop => `if ( !( '${prop}' in this._state ) ) console.warn( "Component was created without expected data property '${prop}'" );`)}
${generator.bindingGroups.length && `this._bindingGroups = [ ${Array( generator.bindingGroups.length ).fill( '[]' ).join( ', ' )} ];`} ${generator.bindingGroups.length && `this._bindingGroups = [ ${Array( generator.bindingGroups.length ).fill( '[]' ).join( ', ' )} ];`}

@ -84,7 +84,7 @@ export default function visitWindow ( generator, block, node ) {
events[ associatedEvent ].push( `${attribute.value.name}: this.${attribute.name}` ); events[ associatedEvent ].push( `${attribute.value.name}: this.${attribute.name}` );
// add initial value // add initial value
generator.builders.metaBindings.addLine( generator.metaBindings.push(
`this._state.${attribute.value.name} = window.${attribute.name};` `this._state.${attribute.value.name} = window.${attribute.name};`
); );
} }
@ -166,7 +166,7 @@ export default function visitWindow ( generator, block, node ) {
` ); ` );
// add initial value // add initial value
generator.builders.metaBindings.addLine( generator.metaBindings.push(
`this._state.${bindings.online} = navigator.onLine;` `this._state.${bindings.online} = navigator.onLine;`
); );

@ -1,5 +1,4 @@
import deindent from '../../utils/deindent.js'; import deindent from '../../utils/deindent.js';
import CodeBuilder from '../../utils/CodeBuilder.js';
import Generator from '../Generator.js'; import Generator from '../Generator.js';
import Block from './Block.js'; import Block from './Block.js';
import visit from './visit.js'; import visit from './visit.js';
@ -24,13 +23,6 @@ export default function ssr ( parsed, source, options ) {
const { computations, hasJs, templateProperties } = generator.parseJs( true ); const { computations, hasJs, templateProperties } = generator.parseJs( true );
const builders = {
main: new CodeBuilder(),
bindings: new CodeBuilder(),
render: new CodeBuilder(),
renderCss: new CodeBuilder()
};
// create main render() function // create main render() function
const mainBlock = new Block({ const mainBlock = new Block({
generator, generator,
@ -43,52 +35,50 @@ export default function ssr ( parsed, source, options ) {
visit( generator, mainBlock, node ); visit( generator, mainBlock, node );
}); });
builders.render.addLine( const result = deindent`
templateProperties.data ? `state = Object.assign( ${generator.alias( 'template' )}.data(), state || {} );` : `state = state || {};` ${hasJs && `[✂${parsed.js.content.start}-${parsed.js.content.end}✂]`}
);
computations.forEach( ({ key, deps }) => { var ${name} = {};
builders.render.addLine(
`state.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );` ${name}.filename = ${JSON.stringify( options.filename )};
);
}); ${name}.data = function () {
return ${templateProperties.data ? `${generator.alias( 'template' )}.data()` : `{}`};
};
if ( generator.bindings.length ) { ${name}.render = function ( state, options ) {
const bindings = generator.bindings.join( '\n\n' ); ${templateProperties.data ? `state = Object.assign( ${generator.alias( 'template' )}.data(), state || {} );` : `state = state || {};`}
${computations.map( ({ key, deps }) =>
`state.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );`
)}
builders.render.addBlock( deindent` ${generator.bindings.length && deindent`
var settled = false; var settled = false;
var tmp; var tmp;
while ( !settled ) { while ( !settled ) {
settled = true; settled = true;
${bindings} ${generator.bindings.join( '\n\n' )}
}
` );
} }
`}
builders.render.addBlock( return \`${generator.renderCode}\`;
`return \`${generator.renderCode}\`;` };
);
// create renderCss() function ${name}.renderCss = function () {
builders.renderCss.addBlock( var components = [];
`var components = [];`
);
if ( generator.css ) { ${generator.css && deindent`
builders.renderCss.addBlock( deindent`
components.push({ components.push({
filename: ${name}.filename, filename: ${name}.filename,
css: ${JSON.stringify( generator.css )}, css: ${JSON.stringify( generator.css )},
map: null // TODO map: null // TODO
}); });
` ); `}
}
if ( templateProperties.components ) { ${templateProperties.components && deindent`
builders.renderCss.addBlock( deindent`
var seen = {}; var seen = {};
function addComponent ( component ) { function addComponent ( component ) {
@ -99,42 +89,21 @@ export default function ssr ( parsed, source, options ) {
components.push( x ); components.push( x );
}); });
} }
` );
templateProperties.components.value.properties.forEach( prop => { ${
templateProperties.components.value.properties.map( prop => {
const { name } = prop.key; const { name } = prop.key;
const expression = generator.importedComponents.get( name ) || `${generator.alias( 'template' )}.components.${name}`; const expression = generator.importedComponents.get( name ) || `${generator.alias( 'template' )}.components.${name}`;
builders.renderCss.addLine( `addComponent( ${expression} );` ); return `addComponent( ${expression} );`;
}); })
} }
`}
builders.renderCss.addBlock( deindent`
return { return {
css: components.map( x => x.css ).join( '\\n' ), css: components.map( x => x.css ).join( '\\n' ),
map: null, map: null,
components components
}; };
` );
if ( hasJs ) {
builders.main.addBlock( `[✂${parsed.js.content.start}-${parsed.js.content.end}✂]` );
}
builders.main.addBlock( deindent`
var ${name} = {};
${name}.filename = ${JSON.stringify( options.filename )};
${name}.data = function () {
return ${templateProperties.data ? `${generator.alias( 'template' )}.data()` : `{}`};
};
${name}.render = function ( state, options ) {
${builders.render}
};
${name}.renderCss = function () {
${builders.renderCss}
}; };
var escaped = { var escaped = {
@ -148,9 +117,7 @@ export default function ssr ( parsed, source, options ) {
function __escape ( html ) { function __escape ( html ) {
return String( html ).replace( /["'&<>]/g, match => escaped[ match ] ); return String( html ).replace( /["'&<>]/g, match => escaped[ match ] );
} }
` ); `;
const result = builders.main.toString();
return generator.generate( result, options, { name, format } ); return generator.generate( result, options, { name, format } );
} }

@ -29,7 +29,6 @@ function create_main_fragment ( state, component ) {
function SvelteComponent ( options ) { function SvelteComponent ( options ) {
options = options || {}; options = options || {};
this._state = options.data || {}; this._state = options.data || {};
recompute( this._state, this._state, {}, true ); recompute( this._state, this._state, {}, true );
this._observers = { this._observers = {

@ -1,3 +1,3 @@
<p>before</p> <p>before</p>
<p>after</p> <p>after</p>

@ -1,4 +1,4 @@
<div><p>foo: lol</p> <div><p>foo: lol</p>
<p>baz: 42 (number)</p> <p>baz: 42 (number)</p>
<p>qux: this is a piece of string</p> <p>qux: this is a piece of string</p>
<p>quux: core</p></div> <p>quux: core</p></div>

@ -1,2 +1,2 @@
<div><p>foo: bar</p> <div><p>foo: bar</p>
<p>baz: 42 (number)</p></div> <p>baz: 42 (number)</p></div>

@ -1,2 +1,2 @@
<p>1 + 2 = 3</p> <p>1 + 2 = 3</p>
<p>3 * 3 = 9</p> <p>3 * 3 = 9</p>

@ -1,2 +1,2 @@
<div>i got 99 problems</div> <div>i got 99 problems</div>
<div>the answer is 42</div> <div>the answer is 42</div>

@ -1,5 +1,5 @@
<div svelte-4188175681>red</div> <div svelte-4188175681>red</div>
<div svelte-146600313>green: foo</div> <div svelte-146600313>green: foo</div>
<div svelte-1506185237>blue: foo</div> <div svelte-1506185237>blue: foo</div>
<div svelte-146600313>green: bar</div> <div svelte-146600313>green: bar</div>
<div svelte-1506185237>blue: bar</div> <div svelte-1506185237>blue: bar</div>
Loading…
Cancel
Save