diff --git a/src/generators/Generator.js b/src/generators/Generator.js
index 469b271f85..a14668494a 100644
--- a/src/generators/Generator.js
+++ b/src/generators/Generator.js
@@ -35,6 +35,12 @@ export default class Generator {
this.cssId = parsed.css ? `svelte-${parsed.hash}` : '';
this.usesRefs = false;
+ // allow compiler to deconflict user's `import { get } from 'whatever'` and
+ // Svelte's builtin `import { get, ... } from 'svelte/shared.js'`;
+ this.importedNames = {};
+
+ this.aliases = {};
+
this._callbacks = {};
}
@@ -47,6 +53,20 @@ export default class Generator {
});
}
+ alias ( name ) {
+ if ( !( name in this.aliases ) ) {
+ let alias = name;
+ let i = 1;
+ while ( alias in this.importedNames ) {
+ alias = `${name}$${i++}`;
+ }
+
+ this.aliases[ name ] = alias;
+ }
+
+ return this.aliases[ name ];
+ }
+
contextualise ( expression, isEventHandler ) {
this.addSourcemapLocations( expression );
@@ -58,6 +78,8 @@ export default class Generator {
let scope = annotateWithScopes( expression );
+ const self = this;
+
walk( expression, {
enter ( node, parent, key ) {
if ( node._scope ) {
@@ -70,7 +92,7 @@ export default class Generator {
if ( scope.has( name ) ) return;
if ( parent && parent.type === 'CallExpression' && node === parent.callee && helpers[ name ] ) {
- code.prependRight( node.start, `template.helpers.` );
+ code.prependRight( node.start, `${self.alias( 'template' )}.helpers.` );
}
else if ( name === 'event' && isEventHandler ) {
@@ -249,6 +271,9 @@ export default class Generator {
imports.push( node );
this.code.remove( a, b );
+ node.specifiers.forEach( specifier => {
+ this.importedNames[ specifier.local.name ] = true;
+ });
}
}
@@ -260,21 +285,33 @@ export default class Generator {
// export is last property, we can just return it
this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `return ` );
} else {
- // TODO ensure `template` isn't already declared
- this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `var template = ` );
+ // we need to avoid a conflict with anything on the top-level scope of the component
+ // however, determining which things these are is tricky, so we instead just avoid conflicts with any identifiers anywhere
+ const identifiers = new Set();
+ walk( js, {
+ enter ( node ) {
+ if ( node.type === 'Identifier' ) {
+ identifiers.add( node.name );
+ }
+ }
+ });
+ let template = 'template';
+ for ( let i = 1; identifiers.has( template ); template = `template$${i++}` );
+
+ this.code.overwrite( defaultExport.start, defaultExport.declaration.start, `var ${template} = ` );
let i = defaultExport.start;
while ( /\s/.test( source[ i - 1 ] ) ) i--;
const indentation = source.slice( i, defaultExport.start );
- this.code.appendLeft( finalNode.end, `\n\n${indentation}return template;` );
+ this.code.appendLeft( finalNode.end, `\n\n${indentation}return ${template};` );
}
defaultExport.declaration.properties.forEach( prop => {
templateProperties[ prop.key.name ] = prop;
});
- this.code.prependRight( js.content.start, 'var template = (function () {' );
+ this.code.prependRight( js.content.start, `var ${this.alias( 'template' )} = (function () {` );
} else {
this.code.prependRight( js.content.start, '(function () {' );
}
diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js
index c0541b8959..4d386affd3 100644
--- a/src/generators/dom/index.js
+++ b/src/generators/dom/index.js
@@ -14,11 +14,6 @@ class DomGenerator extends Generator {
this.renderers = [];
this.uses = {};
- // allow compiler to deconflict user's `import { get } from 'whatever'` and
- // Svelte's builtin `import { get, ... } from 'svelte/shared.js'`;
- this.importedNames = {};
- this.aliases = {};
-
this.importedComponents = {};
}
@@ -143,20 +138,6 @@ class DomGenerator extends Generator {
return this.alias( name );
}
-
- alias ( name ) {
- if ( !( name in this.aliases ) ) {
- let alias = name;
- let i = 1;
- while ( alias in this.importedNames ) {
- alias = `${name}$${i++}`;
- }
-
- this.aliases[ name ] = alias;
- }
-
- return this.aliases[ name ];
- }
}
export default function dom ( parsed, source, options, names ) {
@@ -180,12 +161,6 @@ export default function dom ( parsed, source, options, names ) {
templateProperties.ondestroy = templateProperties.onteardown;
}
- generator.imports.forEach( node => {
- node.specifiers.forEach( specifier => {
- generator.importedNames[ specifier.local.name ] = true;
- });
- });
-
let namespace = null;
if ( templateProperties.namespace ) {
const ns = templateProperties.namespace.value.value;
@@ -261,7 +236,7 @@ export default function dom ( parsed, source, options, names ) {
computations.forEach( ({ key, deps }) => {
builder.addBlock( deindent`
if ( isInitial || ${deps.map( dep => `( '${dep}' in newState && typeof state.${dep} === 'object' || state.${dep} !== oldState.${dep} )` ).join( ' || ' )} ) {
- state.${key} = newState.${key} = template.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );
+ state.${key} = newState.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );
}
` );
});
@@ -338,9 +313,9 @@ export default function dom ( parsed, source, options, names ) {
if ( templateProperties.oncreate ) {
builders.init.addBlock( deindent`
if ( options._root ) {
- options._root._renderHooks.push({ fn: template.oncreate, context: this });
+ options._root._renderHooks.push({ fn: ${generator.alias( 'template' )}.oncreate, context: this });
} else {
- template.oncreate.call( this );
+ ${generator.alias( 'template' )}.oncreate.call( this );
}
` );
}
@@ -351,7 +326,7 @@ export default function dom ( parsed, source, options, names ) {
if ( generator.usesRefs ) constructorBlock.addLine( `this.refs = {};` );
constructorBlock.addLine(
- `this._state = ${templateProperties.data ? `Object.assign( template.data(), options.data )` : `options.data || {}`};`
+ `this._state = ${templateProperties.data ? `Object.assign( ${generator.alias( 'template' )}.data(), options.data )` : `options.data || {}`};`
);
if ( templateProperties.computed ) {
@@ -399,11 +374,11 @@ export default function dom ( parsed, source, options, names ) {
const sharedPath = options.shared === true ? 'svelte/shared.js' : options.shared;
if ( sharedPath ) {
- const base = templateProperties.methods ? `{}, template.methods` : `{}`;
+ const base = templateProperties.methods ? `{}, ${generator.alias( 'template' )}.methods` : `{}`;
builders.main.addBlock( `${name}.prototype = Object.assign( ${base}, ${generator.helper( 'proto' )} );` );
} else {
if ( templateProperties.methods ) {
- builders.main.addBlock( `${name}.prototype = template.methods;` );
+ builders.main.addBlock( `${name}.prototype = ${generator.alias( 'template' )}.methods;` );
}
[ 'get', 'fire', 'observe', 'on', 'set', '_flush' ].forEach( methodName => {
@@ -418,7 +393,7 @@ export default function dom ( parsed, source, options, names ) {
};
${name}.prototype.teardown = ${name}.prototype.destroy = function destroy ( detach ) {
- this.fire( 'destroy' );${templateProperties.ondestroy ? `\ntemplate.ondestroy.call( this );` : ``}
+ this.fire( 'destroy' );${templateProperties.ondestroy ? `\n${generator.alias( 'template' )}.ondestroy.call( this );` : ``}
this._fragment.teardown( detach !== false );
this._fragment = null;
diff --git a/src/generators/dom/visitors/Component.js b/src/generators/dom/visitors/Component.js
index 7165a8a7c2..f6fae1392e 100644
--- a/src/generators/dom/visitors/Component.js
+++ b/src/generators/dom/visitors/Component.js
@@ -106,7 +106,7 @@ export default {
componentInitProperties.push(`data: ${name}_initialData`);
}
- const expression = node.name === ':Self' ? generator.name : generator.importedComponents[ node.name ] || `template.components.${node.name}`;
+ const expression = node.name === ':Self' ? generator.name : generator.importedComponents[ node.name ] || `${generator.alias( 'template' )}.components.${node.name}`;
local.init.addBlockAtStart( deindent`
${statements.join( '\n\n' )}
diff --git a/src/generators/dom/visitors/attributes/addElementAttributes.js b/src/generators/dom/visitors/attributes/addElementAttributes.js
index f355354ab2..191e612a0e 100644
--- a/src/generators/dom/visitors/attributes/addElementAttributes.js
+++ b/src/generators/dom/visitors/attributes/addElementAttributes.js
@@ -182,7 +182,7 @@ export default function addElementAttributes ( generator, node, local ) {
if ( name in generator.events ) {
local.init.addBlock( deindent`
- var ${handlerName} = template.events.${name}.call( component, ${local.name}, function ( event ) {
+ var ${handlerName} = ${generator.alias( 'template' )}.events.${name}.call( component, ${local.name}, function ( event ) {
${handlerBody}
});
` );
diff --git a/src/generators/server-side-rendering/index.js b/src/generators/server-side-rendering/index.js
index efe0d13ea7..0a4fd2afa0 100644
--- a/src/generators/server-side-rendering/index.js
+++ b/src/generators/server-side-rendering/index.js
@@ -60,12 +60,12 @@ export default function ssr ( parsed, source, options, names ) {
parsed.html.children.forEach( node => generator.visit( node ) );
builders.render.addLine(
- templateProperties.data ? `root = Object.assign( template.data(), root || {} );` : `root = root || {};`
+ templateProperties.data ? `root = Object.assign( ${generator.alias( 'template' )}.data(), root || {} );` : `root = root || {};`
);
computations.forEach( ({ key, deps }) => {
builders.render.addLine(
- `root.${key} = template.computed.${key}( ${deps.map( dep => `root.${dep}` ).join( ', ' )} );`
+ `root.${key} = ${generator.alias( 'template' )}.computed.${key}( ${deps.map( dep => `root.${dep}` ).join( ', ' )} );`
);
});
@@ -118,7 +118,7 @@ export default function ssr ( parsed, source, options, names ) {
` );
templateProperties.components.value.properties.forEach( prop => {
- builders.renderCss.addLine( `addComponent( template.components.${prop.key.name} );` );
+ builders.renderCss.addLine( `addComponent( ${generator.alias( 'template' )}.components.${prop.key.name} );` );
});
}
@@ -140,7 +140,7 @@ export default function ssr ( parsed, source, options, names ) {
${name}.filename = ${JSON.stringify( options.filename )};
${name}.data = function () {
- return ${templateProperties.data ? `template.data()` : `{}`};
+ return ${templateProperties.data ? `${generator.alias( 'template' )}.data()` : `{}`};
};
${name}.render = function ( root, options ) {
diff --git a/src/generators/server-side-rendering/visitors/Component.js b/src/generators/server-side-rendering/visitors/Component.js
index 895792a7d0..0a13ade27c 100644
--- a/src/generators/server-side-rendering/visitors/Component.js
+++ b/src/generators/server-side-rendering/visitors/Component.js
@@ -50,7 +50,7 @@ export default {
}))
.join( ', ' );
- const expression = node.name === ':Self' ? generator.name : `template.components.${node.name}`;
+ const expression = node.name === ':Self' ? generator.name : `${generator.alias( 'template' )}.components.${node.name}`;
bindings.forEach( binding => {
generator.addBinding( binding, expression );
diff --git a/test/generator/samples/deconflict-template-1/_config.js b/test/generator/samples/deconflict-template-1/_config.js
new file mode 100644
index 0000000000..c7ca7bec26
--- /dev/null
+++ b/test/generator/samples/deconflict-template-1/_config.js
@@ -0,0 +1,3 @@
+export default {
+ html: `template`
+};
diff --git a/test/generator/samples/deconflict-template-1/main.html b/test/generator/samples/deconflict-template-1/main.html
new file mode 100644
index 0000000000..f716419dc4
--- /dev/null
+++ b/test/generator/samples/deconflict-template-1/main.html
@@ -0,0 +1,13 @@
+{{value}}
+
+
diff --git a/test/generator/samples/deconflict-template-1/module.js b/test/generator/samples/deconflict-template-1/module.js
new file mode 100644
index 0000000000..aa68a2e4ce
--- /dev/null
+++ b/test/generator/samples/deconflict-template-1/module.js
@@ -0,0 +1 @@
+export default 'template';
diff --git a/test/generator/samples/deconflict-template-2/_config.js b/test/generator/samples/deconflict-template-2/_config.js
new file mode 100644
index 0000000000..c7ca7bec26
--- /dev/null
+++ b/test/generator/samples/deconflict-template-2/_config.js
@@ -0,0 +1,3 @@
+export default {
+ html: `template`
+};
diff --git a/test/generator/samples/deconflict-template-2/main.html b/test/generator/samples/deconflict-template-2/main.html
new file mode 100644
index 0000000000..34994a335b
--- /dev/null
+++ b/test/generator/samples/deconflict-template-2/main.html
@@ -0,0 +1,15 @@
+{{value}}
+
+