Search code examples
javascriptcssvisual-studiovisual-studio-2008intellisense

Add ASP.NET server script to mostly-static .JS / .CSS files without losing IntelliSense?


Using VS2008 and ASP.NET 3.5 (or VS 2010 / .NET 4.0?), how can I include a bit of dynamic ASP.NET server-side code in mostly-static JavaScript and CSS files?

I want to do this to avoid cloning entire JS or CSS files to vary just a small part of them multi-tenant sites. Later, I want to extend the solution to handle localization inside javascript/CSS, dynamic debugging/tracing support, and other cool things you can get by injecting stuff dynamically into JavaScript and CSS.

The hard part is that I don't want to lose all the cool things you get with static files, for example:

  • JS/CSS code coloring and intellisense
  • CSS-class "go to definition" support in the IDE
  • automatic HTTP caching headers based on date of underlying file
  • automatic compression by IIS

The server-side goodness of static files (e.g. headers/compression) can be faked via an HttpHandler, but retaining IDE goodness (intellisense/coloring/etc) has me stumped.

An ideal solution would meet the following requirements:

  1. VS IDE provides JS/CSS intellisense and code coloring. Giving up server-code intellisense is OK since server code is usually simple in these files.
  2. "go to defintion" still works for CSS classes (just like in static CSS files)
  3. send HTTP caching headers, varying by modified date of the underlying file.
  4. support HTTP compression like other static files
  5. support <%= %> and <script runat=server> code blocks
  6. URL paths (at least the ones that HTTP clients see) end with .JS or .CSS (not .ASPX). Optionally, I can use querystring or PathInfo to parameterize (e.g. choosing a locale), although in most cases I'll use vdirs for this. Caching should vary for different querystrings.

So far the best (hacky) solution I've come up with is this:

  • Switch the underlying CSS or JS files to be .ASPX files (e.g. foo.css.aspx or foo.js.aspx). Embed the underlying static content in a STYLE element (for CSS) or a SCRIPT element (for JS). This enables JS/CSS intellisense as well as allowing inline or runat=server code blocks.
  • Write an HttpHandler which:
    • looks at the URL and adds .aspx to know the right underlying ASPX to call
    • uses System.Net.HttpWebRequest to call that URL
    • strips out the containing STYLE or SCRIPT tags, leaving only the CSS or JS
    • adds the appropriate headers (caching, content type, etc.)
    • compresses the response if the client suports compression
  • Map *.CSS and *.JS to my handler.
  • (if IIS6) Ensure .JS and .CSS file extensions are mapped to ASP.NET

I'm already using a modified version of Darick_c's HttpCompression Module which handles almost all of above for me, so modifying it to support the solution above won't be too hard.

But my solution is hacky. I was wondering if anyone has a more lightweight approach for this problem which doesn't lose Visual Studio's static-file goodness.

I know I can also hack up a client-side-only solution where I split all JS and CSS into "vary" and "won't vary" files, but there's a performance and maintenance overhead to this kind of solution that I'd like to avoid. I really want a server-side solution here so I can maintain one file on the server, not N+1 files.

I've not tried VS10/.NET 4.0 yet, but I'm open to a Dev10/.net4 solution if that's the best way to make this scenario work.

Thanks!


Solution

  • I have handled a similar problem by having a master page output a dynamic generated JSON object in the footer of each page.

    I needed to have my js popup login dialog box support localization. So using JSON.NET for serialization, I created a public key/value collection property of the master page that pages could access in order place key/values into such as phrase key/localized phrase pairs. The master page then renders a dynamic JSON object that holds these values so that static js files could reference these dynamic values.

    For the js login box I have the masterpage set the localized values. This made sense because the masterpage also includes the login.js file.