diff --git a/rollup/rollup.config.ssr.js b/rollup/rollup.config.ssr.js
index 988554341d3f..6f8922a85462 100644
--- a/rollup/rollup.config.ssr.js
+++ b/rollup/rollup.config.ssr.js
@@ -12,7 +12,7 @@ export default {
nodeResolve({ jsnext: true, module: true }),
commonjs()
],
- external: [ path.resolve( 'src/index.js' ), 'fs', 'magic-string' ],
+ external: [ path.resolve( 'src/index.js' ), 'fs', 'path', 'magic-string' ],
paths: {
[ path.resolve( 'src/index.js' ) ]: '../compiler/svelte.js'
},
diff --git a/src/generators/server-side-rendering/index.js b/src/generators/server-side-rendering/index.js
index 3187622f79ef..d2e8cd961c44 100644
--- a/src/generators/server-side-rendering/index.js
+++ b/src/generators/server-side-rendering/index.js
@@ -7,9 +7,26 @@ import Generator from '../Generator.js';
class SsrGenerator extends Generator {
constructor ( parsed, source, names, visitors ) {
super( parsed, source, names, visitors );
+ this.bindings = [];
this.renderCode = '';
}
+ addBinding ( binding, name ) {
+ const conditions = [ `!( '${binding.name}' in root )`].concat( // TODO handle contextual bindings...
+ this.current.conditions.map( c => `(${c})` )
+ );
+
+ this.bindings.push( deindent`
+ if ( ${conditions.join( '&&' )} ) {
+ tmp = template.components.${name}.data();
+ if ( '${binding.value}' in tmp ) {
+ root.${binding.name} = tmp.${binding.value};
+ settled = false;
+ }
+ }
+ ` );
+ }
+
append ( code ) {
this.renderCode += code;
}
@@ -25,6 +42,7 @@ export default function ssr ( parsed, source, options, names ) {
const builders = {
main: new CodeBuilder(),
+ bindings: new CodeBuilder(),
render: new CodeBuilder(),
renderCss: new CodeBuilder()
};
@@ -32,7 +50,8 @@ export default function ssr ( parsed, source, options, names ) {
// create main render() function
generator.push({
contexts: {},
- indexes: {}
+ indexes: {},
+ conditions: []
});
parsed.html.children.forEach( node => generator.visit( node ) );
@@ -47,6 +66,21 @@ export default function ssr ( parsed, source, options, names ) {
);
});
+ 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}\`;`
);
@@ -102,6 +136,10 @@ export default function ssr ( parsed, source, options, names ) {
${name}.filename = ${JSON.stringify( options.filename )};
+ ${name}.data = function () {
+ return ${templateProperties.data ? `template.data()` : `{}`};
+ };
+
${name}.render = function ( root, options ) {
${builders.render}
};
diff --git a/src/generators/server-side-rendering/visitors/Component.js b/src/generators/server-side-rendering/visitors/Component.js
index 55a7a1139985..b75409e356ec 100644
--- a/src/generators/server-side-rendering/visitors/Component.js
+++ b/src/generators/server-side-rendering/visitors/Component.js
@@ -8,10 +8,19 @@ export default {
}
}
- const props = node.attributes
- .map( attribute => {
- if ( attribute.type !== 'Attribute' ) return;
+ const attributes = [];
+ const bindings = [];
+
+ node.attributes.forEach( attribute => {
+ if ( attribute.type === 'Attribute' ) {
+ attributes.push( attribute );
+ } else if ( attribute.type === 'Binding' ) {
+ bindings.push( attribute );
+ }
+ });
+ const props = attributes
+ .map( attribute => {
let value;
if ( attribute.value === true ) {
@@ -32,9 +41,12 @@ export default {
return `${attribute.name}: ${value}`;
})
- .filter( Boolean )
.join( ', ' );
+ bindings.forEach( binding => {
+ generator.addBinding( binding, node.name );
+ });
+
let open = `\${template.components.${node.name}.render({${props}}`;
if ( node.children.length ) {
diff --git a/src/generators/server-side-rendering/visitors/IfBlock.js b/src/generators/server-side-rendering/visitors/IfBlock.js
index a473965afdc5..dd21ff8b4f10 100644
--- a/src/generators/server-side-rendering/visitors/IfBlock.js
+++ b/src/generators/server-side-rendering/visitors/IfBlock.js
@@ -1,12 +1,19 @@
export default {
enter ( generator, node ) {
const { snippet } = generator.contextualise( node.expression );
+
generator.append( '${ ' + snippet + ' ? `' );
+
+ generator.push({
+ conditions: generator.current.conditions.concat( snippet )
+ });
},
leave ( generator, node ) {
generator.append( '` : `' );
if ( node.else ) node.else.children.forEach( child => generator.visit( child ) );
generator.append( '` }' );
+
+ generator.pop();
}
};
diff --git a/src/server-side-rendering/register.js b/src/server-side-rendering/register.js
index cb17b9a7104e..95c2a63fad12 100644
--- a/src/server-side-rendering/register.js
+++ b/src/server-side-rendering/register.js
@@ -1,10 +1,17 @@
import * as fs from 'fs';
+import * as path from 'path';
import { compile } from '../index.js';
+function capitalise ( name ) {
+ return name[0].toUpperCase() + name.slice( 1 );
+}
+
require.extensions[ '.html' ] = function ( module, filename ) {
const { code } = compile( fs.readFileSync( filename, 'utf-8' ), {
filename,
+ name: capitalise( path.basename( filename ).replace( /\.html$/, '' ) ),
generate: 'ssr'
});
+
return module._compile( code, filename );
};
diff --git a/test/server-side-rendering/component-binding-renamed/Foo.html b/test/server-side-rendering/component-binding-renamed/Foo.html
new file mode 100644
index 000000000000..b0f08ce1d21b
--- /dev/null
+++ b/test/server-side-rendering/component-binding-renamed/Foo.html
@@ -0,0 +1,11 @@
+:foo:
+
+
diff --git a/test/server-side-rendering/component-binding-renamed/_actual.html b/test/server-side-rendering/component-binding-renamed/_actual.html
new file mode 100644
index 000000000000..8009a9607c9b
--- /dev/null
+++ b/test/server-side-rendering/component-binding-renamed/_actual.html
@@ -0,0 +1 @@
+1:foo:1
\ No newline at end of file
diff --git a/test/server-side-rendering/component-binding-renamed/_expected.html b/test/server-side-rendering/component-binding-renamed/_expected.html
new file mode 100644
index 000000000000..6bd7771f1156
--- /dev/null
+++ b/test/server-side-rendering/component-binding-renamed/_expected.html
@@ -0,0 +1 @@
+1:foo:1
diff --git a/test/server-side-rendering/component-binding-renamed/main.html b/test/server-side-rendering/component-binding-renamed/main.html
new file mode 100644
index 000000000000..7445660354f3
--- /dev/null
+++ b/test/server-side-rendering/component-binding-renamed/main.html
@@ -0,0 +1,11 @@
+{{y}}{{y}}
+
+
diff --git a/test/server-side-rendering/component-binding/Foo.html b/test/server-side-rendering/component-binding/Foo.html
new file mode 100644
index 000000000000..b0f08ce1d21b
--- /dev/null
+++ b/test/server-side-rendering/component-binding/Foo.html
@@ -0,0 +1,11 @@
+:foo:
+
+
diff --git a/test/server-side-rendering/component-binding/_actual.html b/test/server-side-rendering/component-binding/_actual.html
new file mode 100644
index 000000000000..8009a9607c9b
--- /dev/null
+++ b/test/server-side-rendering/component-binding/_actual.html
@@ -0,0 +1 @@
+1:foo:1
\ No newline at end of file
diff --git a/test/server-side-rendering/component-binding/_expected.html b/test/server-side-rendering/component-binding/_expected.html
new file mode 100644
index 000000000000..6bd7771f1156
--- /dev/null
+++ b/test/server-side-rendering/component-binding/_expected.html
@@ -0,0 +1 @@
+1:foo:1
diff --git a/test/server-side-rendering/component-binding/main.html b/test/server-side-rendering/component-binding/main.html
new file mode 100644
index 000000000000..d466a1fb11f5
--- /dev/null
+++ b/test/server-side-rendering/component-binding/main.html
@@ -0,0 +1,11 @@
+{{x}}{{x}}
+
+