Whitespace-Management in cfc

1 Kommentare
Mischa Sameli, Geschäftsführer & Leiter Entwicklung

ColdFusion bietet schon seit langem ein Whitespace-Management an. Das bedeutet, dass bevor eine Seite an den Browser ausgeliefert wird, alle leeren Zeilen, Tabs usw aus dem Quellcode entfernt werden. Dieser Whitespace wird durch den ColdFusion-Code generiert, denn der Code wird ja ausgeführt, aber nicht ausgegeben. Wenn man nun diesen Whitespace entfernt, bleibt einerseits der Code übersichtlich und andererseits kann die Dateigrösse jenachdem deutlich reduziert werden.

Alles Faktoren, die man grundsätzlich vernachlässigen könnte, wenn da nicht nicht unser lieber IE wäre. Der behandelt nämlich Whitespace nach seinen eigenen Regeln, sodass es zu Darstellungsfehlern kommen kann. Nun, wie schon eingangs erwähnt, ColdFusion bietet schon seit langem ein sogenanntes Whitespace-Management. Dies kann beispielsweise Serverweit im ColdFusion-Administrator eingestellt werden. Daneben gibt es auch zwei Tags, die im Prinzip dasselbe machen:

1<cfsilent>
2<cfprocessingdirective suppresswhitespace="yes">
3...
4</cfsilent>

Schön wäre nun, wenn dies einfach so funktionieren täte – tut es aber nicht, und zwar in einem entscheidenden Fall nicht: cfc – ColdFusion-Components.
Ein cfc ist so etwas wie eine Klasse in anderen Programmiersprachen, die wiederum Methoden zur Verfügung stellt. Und damit hat sich ColdFusion ab der MX-Version von einer rein prozeduralen Programmiersprache in Richtung Objekt-Orientierter Sprache gewandelt. Zwar kann immer noch gleich programmiert werden, wie schon in den Vorgängerversionen, aber man hat nun die Möglichkeit, Objekte mit Methoden zu modellieren. Mehr will ich darauf gar nicht eingehen.

Das Problem an diesen Components ist nun, dass sie Mühe haben mit dem Whitespace-Management. Die globale Einstellung im CF-Administrator bleibt hier gänzlich wirkungslos. Auch cfprocessingdirective ist nach meinen Erfahrungen für die Füchse. Funktionieren täte der cfsilent-Tag, aber wenn etwas ausgegeben werden muss, produziere ich bereits wieder Whitespace – also wieder nichts. Zur Veranschaulichung ein Beispiel:

1default:
2<cfinvoke component="content" method="showContent" id="1">
3<!-- damit wird die methode"showContent" der Komponente "content" aufgerufen, und der Inhalt wird direkt ausgegeben -->
4
5content.cfc:
6<cfcomponent>
7
8<cffunction name="showContent" output="true">
9<cfargument name="id" />
10...
11ermittle den Inhalt
12...
13<cfoutput>#thisContent#</cfoutput>

So dieser Code produziert nun massig Whitespace, und der lässt sich einfach nicht unterbinden, denn irgenwann muss ich mit cfoutput etwas ausgeben. Da man aber weiss, dass man mit cfscript ebenfalls Funktionen (oder Methoden) innerhalb von cfc schreiben und verwenden kann, kommt hier der springende Punkt: Alles was innerhalb von cfscript geschrieben wird, produziert keinen Whitespace! Also gehen wir hin, und rufen eine cfscript-Funktion auf, die wiederum die eigentliche Funktion aufruft:

1default:
2
3<cfinvoke component="content" method="showContent" id="1">
4<!-- damit wird die methode"showContent" der Komponente "content" aufgerufen, und der Inhalt wird direkt ausgegeben -->
5
6content.cfc:
7<cfcomponent>
8
9<cffunction name="getContent" output="true">
10<cfargument name="id" />
11...
12ermittle den Inhalt
13...
14<cfoutput>#thisContent#</cfoutput><cfscript>
15function showContent(pid){
16WriteOutput(getContent(pid));
17}
18
</cfscript>

So, das wärs – könnte man meinen. Leider haben wir den Whitespace immer noch drin, denn der wird nun eben einfach in der Funktion getContent() produziert. Deshalb verwenden wir eine weitere Hilfsfunktion: HtmlCompressFormat() So, und das ganze zusammen sieht dann etwa so aus:

1default:
2<cfinvoke component="content" method="showContent" id="1">
3<!-- damit wird die methode"showContent" der Komponente "content" aufgerufen, und der Inhalt wird direkt ausgegeben -->
4
5content.cfc:
6<cfcomponent>
7
8<cffunction name="getContent" output="true">
9<cfargument name="id" />
10...
11ermittle den Inhalt
12...
13<cfoutput>#thisContent#</cfoutput><cfscript>
14function showContent(pid){
15WriteOutput(HtmlCompressFormat(getContent(pid)));
16}
17function HtmlCompressFormat(sInput){
18return reReplace( trim(sInput), "(" & chr( 10 ) & "|" & chr( 13 ) & ")+[[:space:]]{2,}", chr( 13 ), "all" );
19}
20
</cfscript>

Und das war's dann auch. Das sieht jetzt irgendwie wahnsinnig umständlich aus, aber es haben alle die gleichen Probleme und ganz verschiedene Lösungen. Als Beispiel ein Link zu einer Blog-Diskussion