Repository: sveltejs/svelte (JavaScript)
Date: 2017-05-03 18:32:25+00:00
Task type: Bug Fix

Issue:
Document state should determine whether the CSS has been added
Svelte components add their stylesheets to ```document.head``` once per component type. Whether the stylesheet has already been added is currently determined by a private variable ```added_css``` inside the component module. While in most cases, this flag should be accurate, this is not always the case in the REPL (see [svelte.technology#93](https://github.com/sveltejs/svelte.technology/issues/93)) and possibly other environments as well. I believe it is more correct to attach some kind of identifier to the style element and then query the document.head element to determine whether it already exists. In my opinion, the accuracy of this approach is well worth the performance hit.


Issue discussion:

Solution patch:
diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js
--- a/src/generators/dom/index.js
+++ b/src/generators/dom/index.js
@@ -117,13 +117,11 @@ export default function dom ( parsed, source, options ) {
 
 	if ( generator.css && options.css !== false ) {
 		builders.main.addBlock( deindent`
-			var ${generator.alias( 'added_css' )} = false;
 			function ${generator.alias( 'add_css' )} () {
 				var style = ${generator.helper( 'createElement' )}( 'style' );
+				style.id = ${JSON.stringify( generator.cssId + '-style' )};
 				style.textContent = ${JSON.stringify( generator.css )};
 				${generator.helper( 'appendNode' )}( style, document.head );
-
-				${generator.alias( 'added_css' )} = true;
 			}
 		` );
 	}
@@ -135,7 +133,7 @@ export default function dom ( parsed, source, options ) {
 	builders.init.addLine( `this._torndown = false;` );
 
 	if ( parsed.css && options.css !== false ) {
-		builders.init.addLine( `if ( !${generator.alias( 'added_css' )} ) ${generator.alias( 'add_css' )}();` );
+		builders.init.addLine( `if ( !document.getElementById( ${JSON.stringify( generator.cssId + '-style' )} ) ) ${generator.alias( 'add_css' )}();` );
 	}
 
 	if ( generator.hasComponents || generator.hasIntroTransitions ) {


Test patch:
diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js
--- a/test/js/samples/collapses-text-around-comments/expected.js
+++ b/test/js/samples/collapses-text-around-comments/expected.js
@@ -8,13 +8,11 @@ var template = (function () {
 	};
 }());
 
-var added_css = false;
 function add_css () {
 	var style = createElement( 'style' );
+	style.id = "svelte-3842350206-style";
 	style.textContent = "\n\tp[svelte-3842350206], [svelte-3842350206] p {\n\t\tcolor: red;\n\t}\n";
 	appendNode( style, document.head );
-
-	added_css = true;
 }
 
 function create_main_fragment ( state, component ) {
@@ -59,7 +57,7 @@ function SvelteComponent ( options ) {
 	this._yield = options._yield;
 
 	this._torndown = false;
-	if ( !added_css ) add_css();
+	if ( !document.getElementById( "svelte-3842350206-style" ) ) add_css();
 
 	this._fragment = create_main_fragment( this._state, this );
 	if ( options.target ) this._fragment.mount( options.target, null );
@@ -85,4 +83,4 @@ SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = functio
 	this._torndown = true;
 };
 
-export default SvelteComponent;
\ No newline at end of file
+export default SvelteComponent;