Update: Full Source code is available at BitBucket
Many times I have a Javascript file that contains a link and in order to be more generic I would prefer writing something like ~/image.png rather than /image.png or /myapp/image.png.
Also when one of my Views in an MVC project interacts with 3rd party components and services (like Google Maps, UserVoice etc.) contains a lot of Javascript code along with html/server-side code. The minute that this page reaches a stable version I tend to put the javascript code in a separate file to keep things cleaner. But if that code depends on my Model and is being rendered by Razor I can’t do that. That means this code must stay on that view and I may end up with duplicating it to other pages with similar functionality.
Struggling with the above I ran into a very good Nuget Package called RazorEngine and thought to create something using that to be able to have more flexibility in my Javascript Code.
And the name of this is RazorJS.
Let’s see a few examples:
Javascript Code in an external file
The JS File
The Razor Code
The Rendered HTML
Javascript Code with Model dependency
The JavaScript File
The Code
The HTML
What about performance?
The JS files are being cached just like Razor files with a CacheDependency so if a file changes the Razor template is being updated instantly. Every file is compiled just like Razor Pages and is being compiled the first time is requested or when a change is detected.
So the time to render each file the second time (and every time after) is really really small.
Known Issues
- For now the Nuget package doesn’t have a dependency to RazorEngine because it needs a later version to perform better which isn’t yet available. Once RazorEngine 2.2 is released I will update the package.
- For now the only method available to call is Href and the only property is only two properties are Model and Url. Please let me know other methods or properties that could be useful when writing Javascript.
That’s all for now! You can find it at the Nuget Feed!
Cheers!
Fatal on said
How about passing the UrlHelper object through so that you could do @Url.Action(action, controller,....)
djsolid on said
Yes, that's also supported!
Scott Wade on said
This looks very promising and something I have been wishing for... I'm NuGet'ing right now and will try...
Thx!
djsolid on said
Thanks Scott! Please let me know if you have any feedback!
Thanigainathan Siranjeevi on said
Hi,
Can you please enable this for WebForm view engine too ?
djsolid on said
I 'm afraid that it's not possible for the time being. It will be, when Razor Syntax is also included at WebForms.
Shukhrat on said
Hi,
is there a typo in package snippet on second screenshot? (RazorJSInlcude instead of RazorJSInclude) :)
Thx!
Sham on said
Awesome, just what I needed (yeah, there is a typo in the library :)).
However, i found that if I use Glimpse an error is raised. Without glimpse it works perfectly.
Excellent work.
djsolid on said
Indeed there was a typo!
Just update the package and fixed it.
@Sham, Now it's also working with Glimpse!
Sham on said
Thanks, amazing library. I am just getting into MVC and you have made my life easier. Not being a web developer by day, any chance of a write up on how you created the RazorJS? What did developers do before the RazorJS.
Once again, excellent work.
sandeep on said
Thanks for sharing that info, still i am new for that technology. Then please give me an idea from beginning level.
Chris on said
One problem I see with this is that you lose the ability to cache these script files in the browser.
Would a better solution not be to simply output a hidden DOM element with data-* attributes that contain the values you'd be injecting into the script in your example (e.g. the current date, the model values, etc...?
Then you can still let the browser cache the JavaScript file and use jQuery to look up the data-* values you need from the hidden DOM element.
Am I missing a scenario where that wouldn't work?
Zote on said
Is it possible to add google clojure or another kind of compilation/minification of renerated js?
Any way, it's a great project! My team and I will starting using it very soon.
Peter on said
These Javascript files are not Javascript files anymore; you should follow Microsoft's example, name the files .cjs for example and add a entry to the web server config to not serve .cjs files.
As it is now, the end user can directly request the .js file, and have access to it's source code, possibly creating security holes.
Apart from security holes, the format used in the file is not JS format anymore, so continuing the .js extension can cause confusion.
ramin on said
Wonderful article. Thanks for sharing
Sam on said
Hi djsolid,
I got the error below, can you please tell me how to fix it?
Thanks,
----------------
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: Could not load type 'RazorJS.RazorJSHandler'.
Source Error:
Line 59: </pages>
Line 60: <httpHandlers>
Line 61: <add path="razorjs.axd" verb="GET" type="RazorJS.RazorJSHandler" />
Line 62: </httpHandlers>
Line 63: </system.web>
djsolid on said
Hello Sam,
I think that you haven't added as a reference the dlls of the package or you removed it by accident.
Check that RazorJS.dll and RazorEngine.dll are added as a reference inside your web project.
Sam on said
hi djsolid,
the reference were there, anyway tried on another clean project worked fine.
thanks for the cool package.
cheers,
ahmed on said
please can y help me in aproblem i want code c# for "work offline" button for browser
y can send me in ahmed_essam_saad@hotmail.com
please
MJ Richardson on said
Exposing the ViewBag property would also be useful.
Have you considered open-sourcing this?
Roman on said
Hi John. Thank you for your tool.
What about Ajax support with AjaxOptions and InsertionMode.
also I have an exception if use @Html.RazorJSInclude "Empty path name is not legal."
Could you help please? Or if you like I'm ready to take part of your project.
djsolid on said
Thank you all for your comments! Soon there will be an update and also I will upload the project to Codeplex!
Cheers!
Swemail on said
Great tool. Have one question, I use a separate assembly for my models, can I point to a model in a separate assembly in the 'from @Href(..) statement?
Swemail on said
Great tool. Have one question, I use a separate assembly for my models, can I point to a model in a separate assembly in the 'from @Href(..) statement?
Alex on said
Pretty nice !
I just missed the ability to pass a model dedicated to javascript
(because in my cases, it will not be the same as the view, i'll just need some parameters)
So I added the following extension methods :
public static IHtmlString RazorJSInline<TModel>(this HtmlHelper html, string filename, TModel model)
{
return html.Raw(new RazorJSFileParser(filename).InlineScript(model));
}
Actually, i still try to make it works with dynamic objects but am not so much familiar with it.
I'll dig more soon :)
Anyway, thanks for this tool :)
Denis on said
Hi,
First of all, thanks a lot for your great tool, I've been expecting something like this for a long time.
However, I faced a problem: it seems that there is an issue with the scripts used via RazorJS when the solution is deployed to Azure.
I made a small investigation and it seems that the problem appears in RazorEngine when running template service; in your code you check if template is compiled and then run with no compilation process, but looks like on Azure the compiled templates are not saved and for a second time the Engine throws an error. Sorry, didn't have enough time to find more, but I believe it's interesting.
Dominik on said
Hey,
I have just found this tool yesterday, and it helped me to reduce the number of inline scripts in my views. But as Denis said, I also get the error after deploying to azure. On the second load of the page I get an 500 error from server. The problem is as Denis described it.
The problem doesn't occur with inline adding of scripts, but that's kind of a reason why I wanted to use it in the first place ^^
djsolid on said
Hello, and thank you for reporting your issues.
Since the full source is available here ( https://bitbucket.org/djsolid/razorjs/ ) can you please create an issue there? I will take a look as soon as possible.
John
AndyB on said
Works well. I use it, primarily, for localising javascript and for adding comments that I don't want the user to see (use Razor comments).
There is problem. I can't see scripts delivered by razorjs in Firebug.
It would be nice if the path could be something like /something/something/my.js instead of /razorjs.axd?fn=/something/my.js
This should fix the Firebog issue and hide how the script was generated from the end user.
Still a bit of a newbie at Razor, so not sure how to accomplish this (if at all)
Angelo on said
I'm running into an issue... When the browser hits razorjs.axd sometimes it can't find the requested file and returns a 404. Other times it works just fine. I can't find a pattern. The code doesn't change but one time I run my MVC app and the browser doesn't get the JS file then if I rebuild it once or twice, it works.
Any ideas? I've tried this in IE, FF and Chrome but it's not a browser issue.
Angelo on said
Sorry, it's not coming back with a 404, it's coming back with a blank file. Again, this is intermittent. It won't work when I build 1-3 times, then I build again and it works fine for several more builds.
I don't know if RazorJS is doing any internal caching but perhaps that's the issue?
Patrick Neborg on said
I am experience the same issue as Angelo. Without this working consistently I will need to abandon using RazorJS.
EagleEye on said
I'm trying to use this in a MVC3 project and I've installed RazorJs and tried the first example above and the script file renders correctly into the html but the razor is still being interpreted as strings. Am I doing something wrong? We are looking to use this throughout our companies medical websites.
EagleEye on said
Scatch my last comment I got it working now for some reason. And now that I re-read what I wrote it's to vague to decipher any problem anyways. But thank you for this... it really cleaned up my views A LOT.
Pavel on said
I installed the package today and tried use it. But I failed to use @Html.RazorJSInlcude("") and @Html.RazorJSInclude("")
I searched for them both in the RazorEngine.dll and System.Web.Razor.dll assemblies via Reflector but failed to find mentioned methods. What I do wrong?
Joel on said
Nice plugin! I noticed that if you have custom routes.MapRoutes, the Url mapping is messed up. Is this a known issue or something new? If you want some example code, email me and I'll post it.
wizmagister on said
I've done a simple thing: renamed the external JS file to "cshtml" and put my code into a <script> block. I can then use @Razor syntax.
Instead of referencing a JS, simply add "Html.Partial()" ...
yurivan on said
hi, I was testing with visual studio mvc 4 in 11 and gave me the following error Could not load type 'System.Web.Razor.Parser.MarkupParser' from assembly 'System.Web.Razor, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = 31bf3856ad364e35 'and not to be exactly should I update the source code version 4 also mvc?
Shimon on said
Very good Extenstion...
Thanks...
I try to move my js code to files and get error about the follow components:
ViewBag, Json, Html.Raw, etc...
It will be very usefull if all this classes, intaces will be support..
thanks again
Brij on said
Excellent plugin !!!
Hope, It'll support Viewbag and Session soon. Right now I'm using Session or Viewbag by passing in place of model in js file. See following for more details:
http://goo.gl/hKQxK