I wanted to get your opinion about managing scripts in ASP .NET MVC. There are 2 problems I am particularly curious about:
Tracking script include dependencies of views
Managing and minifying view scripts
Just like in many projects my views are composed of several partial views and editor templates. I like to keep the scripting relating to these views in the same code entity e.g.
SigningKeysForm partial view should have its own JQuery/JQueryUI scripts.
Which means any view which renders this partial view should include JQuery/JQueryUI script files.
Also another issue is when a view is composed of several such partial views, it means the javascipt in the partial views will be in several locations in the generated html.
My current approach to these problems is exploiting the top down parsing of views in ASP .Net MVC.
For tackling first problem I define a HtmlHelper extension to include a script e.g.
<% Html.RequireScript(Scripts.JQuery); %>
This way in each partial view and view I explicitly call out which scripts are required. The implementation of this method is to create a HashSet on current HttpContext and add the required script there.
In my master page I have another HtmlHelper extension which checks the HttpContext and renders the script include tags e.g:
<%=Html.RenderScriptIncludeTags()%>
This way I can track the requirements of views and render only the required script includes.
For the view scripts I am employing a similar approach. I use a custom Asp .Net user control which instead of rendering its content stores the script content into a buffer on HttpContext e.g:
<mvc:script runat="server">
$(function(){
alert("Hello " + "<%=Model.Name%>");
});
</mvc:script>
Again in the Master view I have a HtmlHelper extension which minifies (if needed) the stored scripts and renders them e.g:
<%=Html.RenderScripts()%>
</body>
I think this works as a solution, but it requires the script includes and scripts to be in the bottom of the master page. This means the script includes are not in the head section.
I want to know if there are better ways to manage the script requirements and in view page scripts with ASP .NET MVC.
Have you thought about using an existing tool that does this sort of thing, like Cassette (previously called Knapsack)?
Cassette automatically sorts, concatenates, minifies, caches and versions all your JavaScript, CoffeeScript, CSS, LESS and HTML templates.
I haven't personally used it (yet), but it looks pretty good, and seems like it should do exactly what you need (and more). Worth noting there is a small cost for commercial use.
EDIT: Now released under MIT licence :)
Telerik has a script registrar utility that does exactly what you are doing.
http://www.telerik.com/help/aspnet-mvc/web-assets-working-with-javascript-web-assets.html
As a bonus, it also does compression.
Yes it renders the scripts at the bottom.
Personally I usually include a few important scripts on the top the usual way and the rest with the scriptregistrar. That way I can have some scripts available during the loading of the page.
The telerik script registrar is part of their MVC suite.
http://www.telerik.com/products/aspnet-mvc.aspx
Related
I have two HTML files: One acts as a template, supplying the navigation, sidebars, etc., and the other has the main content. I'm trying to figure out how best to insert the content into the template. I need persistent URLs, so my plan was to have the content page essentially replace itself with the template, plugging the text back into the resulting page. I'm really new to front-end programming and I'm suspicious that this may be an anti-pattern, so my first question is about whether I'm barking up the right tree. The problem seems universal, and I'm sure there must be a best practice, though I haven't yet seen it discussed. If this is an acceptable way to proceed, then what JavaScript function would allow me to access the HTML of two different pages at the same time?
[EDIT: It's a small page on GitHub]
Do not do this. At current implementation HTML is not designed to be template engine. You can use HTML import but it has not full support in browsers. (compatibility table).
Usually this problem can be solved with:
Use frontend framework. Libraries like angular.js or polymer.js (and so on) usually has support of importing HTML documents in different forms.
Build your application HTML. Task runners like grunt.js usually has plugin that includes HTML.
Use server side technologies to extend your HTML from base layouts
If your application have to be consisted from different HTMLs I recommend you to try polymer. It is polyfill for web components and designed to work in such way by default.
UPD:
About edit to your question. It seems like you just need template engine for HTML. You can google for it. I use nunjucks - javascript port of python's template engine jinja2. It is lightweight, simple and can be compiled right in browser.
Another way is to use special tools for building static web pages. You have mentioned that your page is blog build from simple HTML pages. Try to use pelican. It is the static websites (blogs) generator. It is simple and fast. You can build your HTML even on your local machine and just push your HTML pages to github.
I'm building the ASP.NET MVC application containing widgets - user can define in the administration panel which widgets (which are being in fact partial views) will be used on page. Each widget has references to jquery library which is common for all widgets but also to jsquery plugin file which contains the logic specified for particular widget.
The problem which I found is to load efficiently only the scripts needed on the page (based on the user defined set of widgets) and minify them in one scripts.min.js file.
The build in MVC bundling allows me to define some sets of scripts, by the problem is that I don't know the exact set of widgets and I don't like to list all possible combination, I need to do it dynamically (on server side - from the perspective of performance), based on user choice.
There are Require.js library, but it will do everything on user side, and there will be many requests for each one jquery file and an the end the combination of everything into one file.
Do you have any ideas, how to make this working in efficient way?
I'm developing pure JS + HTML application. To keep the code clean I would like to separate my application into the several html files (i.e. ClientView.html, HistoryView.html etc). Based on user actions one or another view (or several views) would be displayed. Each view is supposed to have an underlying code in a separate JS file.
What I really want to achieve is following:
Develop view as HTML page (do not use any kind of javascript templating)
Views and viewmodels are loaded on the fly (only loaded when needed)
Some way to control dependencies.
I would be very thankful if you advice me a good start for that, as I'm quite new to modern html applications development. I myself is from WPF world, and I've been working with MVVM applications for a very long time, probably I'm wrong trying to bring same experience to javascript development.
I've found several posts about "compiling" html - (HTML "compiler" / merging application), but I don't think that it is what I need.
p.s. In my project I'm very dependent from several features from Twitter Bootsrap (first of all from grid systems)
Use a master page which contains some div to make the layout. Use JQuery to dynamically load various pages and insert into the div in the master page as required.
I'm pretty new to MVC and I can't decide on the best way to store cshtml files and their respective javascript code. Some JS code in my project needs to run globally, but most of it is entirely tied to specic views or partial views.
If I put the javascript in the views, I get a mess of inline uncacheable javascript, if I put it in one central file, I lose modularity.
I heard that in MVC4 there are going to be minification features, is there something I can do with MVC3 that will allow me to choose in the Views which javascripts to include and then group them and minify them automatically? (maybe even in groups?)
Cassette it's essentially the same thing as the upcoming MVC4 bundles.
In your view page, you can reference scripts and stylesheets using Cassette's Bundles helper class.
#{
Bundles.Reference("Scripts/jquery.js");
Bundles.Reference("Scripts/page.js");
Bundles.Reference("Styles/page.css");
}
<!DOCTYPE html>
<html>
...
In addition, Cassette has native support for Less and CoffeScript. It has also support for HTML Templates, if you are interested in client side MVC frameworks like Knockout.js or Backbone.js.
Still you have to choose how to group your content. As the official documentation is suggesting, probably the best choice is to treat bundles as units of deployment.
Keep in mind that a bundle is a unit of deployment. If any asset in a bundle changes, then the entire bundle has to be downloaded again by web browsers. So perhaps group shared code into a bundle and put page scripts into their own bundles.
You can put the javascript in separate files, for each view. Then in the _Layout.cshtml enter a #RenderSectionto the head:
<head>
<script src="#Url.Content("~/Scripts/jquery-1.7.1.js")" type="text/javascript"></script>
#RenderSection("head",false)
</head>
Then in each view, you can put a section that will be rendered into the header:
#section head{
<script src="#Url.Content("~/ViewScripts/Order/New.js")" type="text/javascript"></script>
}
You'll want to use a method like this:
http://www.viget.com/inspire/extending-paul-irishs-comprehensive-dom-ready-execution/
See this post:
Using Rails 3.1, where do you put your "page specific" javascript code?
It is not a best practice to use script in partials (in my point of view)
is suggest you to write partial specific script to separate js and bind events on page load or if partial was loaded via ajax then on success event.
then you can be sure that events are not bound multiple times and view is just a view
#Anders approach is good if you require the scripts to be in the head tag. But I find that most times it is not required if it is page specific JavaScript. You can put your script tags that reference your script files wherever they are required in the View. Automatically bundling and minification will be supported in ASP.NET 4.5. Until that time you can integrate yuicompressor into Visual Studio.
I'd like to have some of the ScriptManager features in the new Asp.net MVC model:
1- Script combining
2- Resolving different paths for external Javascript files
3- Minify and Gzip Compression
Here is what I found, but I'm not sure is the best way for MVC approach. In general what is a good approach to deal with Javascript code in the MVC model?
Maybe you could just create a new 'Scripts' controller with different actions serving different combinations of compressed JS files. Since MVC is designed with a resource oriented approach, i.e. URLs are now at the center of your programming model, why not define simple URIs for your Javascripts too ?
In your views, for example you could reference your files like this :
<script src="http://your_domain/scripts/all"/>
This would call your 'all' action, resulting in all your compressed script files being sent.
Of course you would need to code the combining and compressing for now, or maybe reuse the Scriptmanager internally, I don't know if it's possible.
This is just an idea though, currently I'm referencing individual javascript files directly in my master pages.
Try this:
http://www.codeplex.com/MvcScriptManager
MvcScriptManager is aimed to port certain key features available in AjaxControlToolkit's ToolkitScriptManager into the current ASP.NET MVC Framework. You will be able to use it as a control in your ASP.NET MVC application.
Features
Script combination (or concatenation). Scripts declared with MvcScriptManager will be combined on the fly into a single script file request when the page is rendered.
Script minification (or crunching) in release mode. Minification process is done only once at the first request that references the specific script. Subsequent requests will use the crunched script content in cache (see #5 for detail). Crunching can be enabled/disabled for each script.
Render localized resources for stand-alone script files. Localized strings will be appended to the script if specified.
Support configurable HTTP compression and expiration setting when outputing scripts.
Script caching with file dependency. Script file content is cached so that rendering combined script file will be much more performant. Cache dependency is linked to the physical file therefore any script update in the file system will be reflected in the cache instantly.
Support rendering scripts in debug/release mode based on the running environment.
Resolving different paths for stand-alone script files.
Support multiple MvcScriptManagers on a single page (or master page). Support both Master and Slave rendering mode so that scripts declared with one ScriptManager can be rolled over to another one for rendering.
Support web farm scenario...
Or how about including the ScriptManager itself, as the sole inhabitant of a solitary, once-per-page <form runat="server"> ?
Like this:-
<form runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnableScriptGlobalization="true">
</asp:ScriptManager>
</form>
Works for me.
P.S. You'll need to ensure that this form tag never gets embedded within another form. Nested forms don't work.
Found this researching much the same problem: A Simple ScriptManager for ASP.NET MVC - written after this question was answered so added for reference.
In the first instance I'm going with the brute force solution i.e. stick it all in the master page (especially as one can now pull jQuery from Microsoft's CDN) - then we're going to investigate options for more optimal solutions.
MVC 4 now includes Bundling and Minification helpers. You define all of the scripts that go into your bundle, and MVC will take care of bundling, compression, cache busting, etc.
http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification