From 30abda37bd51929ba32c6df7c3c525d6bdc82cfa Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Wed, 3 May 2017 21:02:17 -0400 Subject: [PATCH] simplify SSR codegen --- src/generators/dom/index.js | 16 +- .../dom/visitors/Element/meta/Window.js | 4 +- src/generators/server-side-rendering/index.js | 147 +++++++----------- .../samples/computed-collapsed-if/expected.js | 1 - .../samples/comment/_actual.html | 2 +- .../component-data-dynamic/_actual.html | 6 +- .../component-data-static/_actual.html | 2 +- .../samples/computed/_actual.html | 2 +- .../empty-elements-closed/_actual.html | 2 +- .../samples/import-non-component/_actual.html | 2 +- .../samples/styles-nested/_actual.html | 8 +- 11 files changed, 79 insertions(+), 113 deletions(-) diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index b7c671910b..478806b5eb 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -19,9 +19,7 @@ class DomGenerator extends Generator { this.readonly = new Set(); // initial values for e.g. window.innerWidth, if there's a <:Window> meta tag - this.builders = { - metaBindings: new CodeBuilder() - }; + this.metaBindings = []; } helper ( name ) { @@ -91,11 +89,13 @@ export default function dom ( parsed, source, options ) { if ( typeof newState !== 'object' ) { 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? @@ -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" );`} ${generator.usesRefs && `this.refs = {};`} 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 );`} ${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( ', ' )} ];`} diff --git a/src/generators/dom/visitors/Element/meta/Window.js b/src/generators/dom/visitors/Element/meta/Window.js index c89f11c47c..01f1bbf4ca 100644 --- a/src/generators/dom/visitors/Element/meta/Window.js +++ b/src/generators/dom/visitors/Element/meta/Window.js @@ -84,7 +84,7 @@ export default function visitWindow ( generator, block, node ) { events[ associatedEvent ].push( `${attribute.value.name}: this.${attribute.name}` ); // add initial value - generator.builders.metaBindings.addLine( + generator.metaBindings.push( `this._state.${attribute.value.name} = window.${attribute.name};` ); } @@ -166,7 +166,7 @@ export default function visitWindow ( generator, block, node ) { ` ); // add initial value - generator.builders.metaBindings.addLine( + generator.metaBindings.push( `this._state.${bindings.online} = navigator.onLine;` ); diff --git a/src/generators/server-side-rendering/index.js b/src/generators/server-side-rendering/index.js index 02e4e39bf2..2b3be31bbd 100644 --- a/src/generators/server-side-rendering/index.js +++ b/src/generators/server-side-rendering/index.js @@ -1,5 +1,4 @@ import deindent from '../../utils/deindent.js'; -import CodeBuilder from '../../utils/CodeBuilder.js'; import Generator from '../Generator.js'; import Block from './Block.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 builders = { - main: new CodeBuilder(), - bindings: new CodeBuilder(), - render: new CodeBuilder(), - renderCss: new CodeBuilder() - }; - // create main render() function const mainBlock = new Block({ generator, @@ -43,84 +35,9 @@ export default function ssr ( parsed, source, options ) { visit( generator, mainBlock, node ); }); - builders.render.addLine( - templateProperties.data ? `state = Object.assign( ${generator.alias( 'template' )}.data(), state || {} );` : `state = state || {};` - ); - - computations.forEach( ({ key, deps }) => { - builders.render.addLine( - `state.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );` - ); - }); - - if ( generator.bindings.length ) { - const bindings = generator.bindings.join( '\n\n' ); - - builders.render.addBlock( deindent` - var settled = false; - var tmp; - - while ( !settled ) { - settled = true; - - ${bindings} - } - ` ); - } - - builders.render.addBlock( - `return \`${generator.renderCode}\`;` - ); - - // create renderCss() function - builders.renderCss.addBlock( - `var components = [];` - ); - - if ( generator.css ) { - builders.renderCss.addBlock( deindent` - components.push({ - filename: ${name}.filename, - css: ${JSON.stringify( generator.css )}, - map: null // TODO - }); - ` ); - } - - if ( templateProperties.components ) { - builders.renderCss.addBlock( deindent` - var seen = {}; - - function addComponent ( component ) { - var result = component.renderCss(); - result.components.forEach( x => { - if ( seen[ x.filename ] ) return; - seen[ x.filename ] = true; - components.push( x ); - }); - } - ` ); - - templateProperties.components.value.properties.forEach( prop => { - const { name } = prop.key; - const expression = generator.importedComponents.get( name ) || `${generator.alias( 'template' )}.components.${name}`; - builders.renderCss.addLine( `addComponent( ${expression} );` ); - }); - } - - builders.renderCss.addBlock( deindent` - return { - css: components.map( x => x.css ).join( '\\n' ), - map: null, - components - }; - ` ); + const result = deindent` + ${hasJs && `[✂${parsed.js.content.start}-${parsed.js.content.end}✂]`} - 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 )}; @@ -130,11 +47,63 @@ export default function ssr ( parsed, source, options ) { }; ${name}.render = function ( state, options ) { - ${builders.render} + ${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( ', ' )} );` + )} + + ${generator.bindings.length && deindent` + var settled = false; + var tmp; + + while ( !settled ) { + settled = true; + + ${generator.bindings.join( '\n\n' )} + } + `} + + return \`${generator.renderCode}\`; }; ${name}.renderCss = function () { - ${builders.renderCss} + var components = []; + + ${generator.css && deindent` + components.push({ + filename: ${name}.filename, + css: ${JSON.stringify( generator.css )}, + map: null // TODO + }); + `} + + ${templateProperties.components && deindent` + var seen = {}; + + function addComponent ( component ) { + var result = component.renderCss(); + result.components.forEach( x => { + if ( seen[ x.filename ] ) return; + seen[ x.filename ] = true; + components.push( x ); + }); + } + + ${ + templateProperties.components.value.properties.map( prop => { + const { name } = prop.key; + const expression = generator.importedComponents.get( name ) || `${generator.alias( 'template' )}.components.${name}`; + return `addComponent( ${expression} );`; + }) + } + `} + + return { + css: components.map( x => x.css ).join( '\\n' ), + map: null, + components + }; }; var escaped = { @@ -148,9 +117,7 @@ export default function ssr ( parsed, source, options ) { function __escape ( html ) { return String( html ).replace( /["'&<>]/g, match => escaped[ match ] ); } - ` ); - - const result = builders.main.toString(); + `; return generator.generate( result, options, { name, format } ); } diff --git a/test/js/samples/computed-collapsed-if/expected.js b/test/js/samples/computed-collapsed-if/expected.js index 1a6b8b82a6..df9295d28b 100644 --- a/test/js/samples/computed-collapsed-if/expected.js +++ b/test/js/samples/computed-collapsed-if/expected.js @@ -29,7 +29,6 @@ function create_main_fragment ( state, component ) { function SvelteComponent ( options ) { options = options || {}; this._state = options.data || {}; - recompute( this._state, this._state, {}, true ); this._observers = { diff --git a/test/server-side-rendering/samples/comment/_actual.html b/test/server-side-rendering/samples/comment/_actual.html index e5c61a4b0e..0dfdacc02b 100644 --- a/test/server-side-rendering/samples/comment/_actual.html +++ b/test/server-side-rendering/samples/comment/_actual.html @@ -1,3 +1,3 @@

before

-

after

\ No newline at end of file +

after

\ No newline at end of file diff --git a/test/server-side-rendering/samples/component-data-dynamic/_actual.html b/test/server-side-rendering/samples/component-data-dynamic/_actual.html index 6aedef46ee..d27b63e162 100644 --- a/test/server-side-rendering/samples/component-data-dynamic/_actual.html +++ b/test/server-side-rendering/samples/component-data-dynamic/_actual.html @@ -1,4 +1,4 @@

foo: lol

-

baz: 42 (number)

-

qux: this is a piece of string

-

quux: core

\ No newline at end of file +

baz: 42 (number)

+

qux: this is a piece of string

+

quux: core

\ No newline at end of file diff --git a/test/server-side-rendering/samples/component-data-static/_actual.html b/test/server-side-rendering/samples/component-data-static/_actual.html index 15a2100d4a..442c858e4d 100644 --- a/test/server-side-rendering/samples/component-data-static/_actual.html +++ b/test/server-side-rendering/samples/component-data-static/_actual.html @@ -1,2 +1,2 @@

foo: bar

-

baz: 42 (number)

\ No newline at end of file +

baz: 42 (number)

\ No newline at end of file diff --git a/test/server-side-rendering/samples/computed/_actual.html b/test/server-side-rendering/samples/computed/_actual.html index 099eebe604..6386593ee9 100644 --- a/test/server-side-rendering/samples/computed/_actual.html +++ b/test/server-side-rendering/samples/computed/_actual.html @@ -1,2 +1,2 @@

1 + 2 = 3

-

3 * 3 = 9

\ No newline at end of file +

3 * 3 = 9

\ No newline at end of file diff --git a/test/server-side-rendering/samples/empty-elements-closed/_actual.html b/test/server-side-rendering/samples/empty-elements-closed/_actual.html index 643f5b6b49..cb9b2cdcad 100644 --- a/test/server-side-rendering/samples/empty-elements-closed/_actual.html +++ b/test/server-side-rendering/samples/empty-elements-closed/_actual.html @@ -1,2 +1,2 @@ -

\ No newline at end of file +

\ No newline at end of file diff --git a/test/server-side-rendering/samples/import-non-component/_actual.html b/test/server-side-rendering/samples/import-non-component/_actual.html index 893a7b890b..25e562b3df 100644 --- a/test/server-side-rendering/samples/import-non-component/_actual.html +++ b/test/server-side-rendering/samples/import-non-component/_actual.html @@ -1,2 +1,2 @@
i got 99 problems
-
the answer is 42
\ No newline at end of file +
the answer is 42
\ No newline at end of file diff --git a/test/server-side-rendering/samples/styles-nested/_actual.html b/test/server-side-rendering/samples/styles-nested/_actual.html index 1962e54454..4b5e1430c8 100644 --- a/test/server-side-rendering/samples/styles-nested/_actual.html +++ b/test/server-side-rendering/samples/styles-nested/_actual.html @@ -1,5 +1,5 @@
red
-
green: foo
-
blue: foo
-
green: bar
-
blue: bar
\ No newline at end of file +
green: foo
+
blue: foo
+
green: bar
+
blue: bar
\ No newline at end of file