I have a Durandal 2 app based on ASP.NET MVC 5 and Web API, with the initial Index.cshtml (on HomeController) being served through the MVC router. From then on it's all regular html views being handled by the Durandal router.
Anyway, I'm trying to use gulp-useref to concatenate all css and js files. I've got everything working and gulp-useref drops the newly concatenated files and an index.cshtml with the updated script and stylesheet references in a dist folder.
Of course, for the application to work I need the updated index.cshtml back in Views/Home/. I have created a "copy" task with gulp that does just that; it overwrites the original index.cshtml and fixes the paths to the concatenated js and css files.
That works as well, but since useref removes the html comments that mark the spot where it should insert the references to the concatenated files, the process is not repeatable.
Let me illustrate with some code.
In my Index.cshtml I have:
<html>
<head></head>
<body>
<!-- build:js js/lib.js-->
<script src="/bower_components/numeral/languages.js"></script>
<script src="/scripts/bootstrap.js"></script>
<script src="/scripts/typeahead.js"></script>
<script src="/scripts/knockout-bootstrap.js"></script>
<script src="/scripts/knockout-extenders.js"></script>
<!-- endbuild -->
</body>
</html>
This is where gulp-useref will place the updated script reference so it will end up looking like this:
<html>
<head></head>
<body>
<script src="/js/lib.js"></script>
</body>
</html>
As you can see, useref removes the html comments so if I overwrite the original index.cshtml with this file, useref will not know where to place the updated script tag. And if I don't overwrite the original index.cshtml, the application will not be using the concatenated files.
I'm new to gulp so I might be going at this in the completely wrong way, but how can I make sure that my /Views/Home/index.cshtml uses the concatenated files in an automated manner?
Or, alternatively, is there a better approach for what I'm trying to do, namely, get everything ready for deployment?
Here are my relevant gulp tasks, for reference:
gulp.task("optimize-for-deployment", function () {
var assets = $.useref.assets({ searchPath: "./" });
var cssFilter = $.filter("**/*.css");
var jsFilter = $.filter("**/*.js");
return gulp
.src(config.index)
.pipe($.plumber())
.pipe(assets)
.pipe(cssFilter)
.pipe($.csso())
.pipe(cssFilter.restore())
.pipe(jsFilter)
.pipe($.uglify())
.pipe(jsFilter.restore())
.pipe(assets.restore())
.pipe($.useref())
.pipe(gulp.dest(config.appDist));
});
// copy the updated index.cshtml to Views/Home/
gulp.task("copy-for-deployment", ["optimize-for-deployment"], function () {
return gulp.src(config.appDist + "index.cshtml")
.pipe($.replacePath(/js\/lib.js/, "/app/dist/js/lib.js"))
.pipe($.replacePath(/style\/app.css/, "/app/dist/style/app.css"))
.pipe(gulp.dest(config.indexLocation));
});
Don't know if this is 'better' approach or the best solution but you could use something like a template for your index file. So you would have an Index-template.cshtml with al your html comments which you use to create your Index.cshtml every time in your gulp tasks.
This way you can overwrite your Index.cshtml and keep your template with al your html comments.
I am new to .net mvc and trying to do the exact thing Sergi. If you modified the default view location scheme to include your dist folder (How to change default view location scheme in ASP.NET MVC?), would .net know to include the dist folder and compile those .cshtml files?
Related
I have an angular2 app running on top of .NET project. We access the app at http://example.com/index/app.
But immediately after the angular2 app starts running and appearing, our URL is rewrited in the browser as: http://example.com/#/dashboard for example.
Trying to go directly to http://example.com/index/app/#/dashboard redirects or more precisely rewrite our url to http://example.com/#/dashboard an displays the app.
How can I prevent this behavior to constantly have the full URI? http://example.com/index/app/#/dashboard Angular2 part being only the after # one.
Your base path is wrong. You have to add
<base href="~/index/app" />
to your html (index.html, index.cshtml, or _Layout.cshtml, depending on the way you have done it) document. Remove the ~ if you are not using Razor views.
Update based on comments
You'll have to define a section within your _Layout.cshtml which will render it on a per view basis.
in _Layout.cshtml:
<head>
...
#RenderSection("base", required: false)
</head>
in your Views/Index/App.cshtml:
#section base {
<base href="~/index/app"/>
}
What is the difference of both statements concerning the section Scripts and script-tag? NOT the content inside the scripts that does not interest me.
#section Scripts {
#Scripts.Render(Bundles.Scripts.Validation)
}
vs
<script src="#Url.Content("~/Scripts/Validation.js")"></script>
The first one renders the <script> tag where you have #RenderSection("Scripts") in your layout.
This is preferred when you don't have to include a script for all pages.
Also #Scripts.Render will minify and bundle your scripts. Usually this is used at the end of body tag so that Views can get the scripts after the DOM is rendered.
The second one remains where you use the <script> tag.
If you use it in Layout, the script is included in all pages (e.g. jQuery).
Let's take an example
<!-- HTML in Layout, before Scrip -->
#RenderBody()
<script src="#Url.Content("~/Scripts/jquery.min.js")"></script>
#RenderSection("Scripts")
<!-- HTML after Script -->
Here, if the script make use of jQuery you want to included with section because jQuery is included before section.
If you include with <script> in your view you will give an error, that jQuery is missing, because is included before jQuery.
You might want to define sections in you _layout.cshtml file for specific content. It is generally believed that styles belong to <head> and scripts belong before </body>. Your mileage may vary.
If you just output <script> it will go with all the content and not where you might want it to be.
And if script inside view depends on something (jquery) and in your layout you have
#renderBody()
<script src=jquery.js></script>
#renderSection("scripts",required:false)
then you are screwed (-:
I have a very simple MVC project, and in my _Layout.cshtml I have some js includes like so:
<script src="~/scripts/jquery-2.0.3.min.js"></script>
<script src="~/scripts/easing.js"></script>
<script src="~/scripts/bootstrap.js"></script>
However, when it renders, it renders on the page like (note the tilde on the first one):
<script src="~/scripts/jquery-2.0.3.min.js"></script>
<script src="/scripts/easing.js"></script>
<script src="/scripts/bootstrap.js"></script>
I can't seem to get it to render properly, and it doesn't matter which script tag is first, that's the one it adds/keeps the tilde on. I've resorted to including the jquery script twice, the first one will have a tilde but the second one will get included, but I don't like that solution at all.
I'm working with VS 2012, it's a .NET 4.5 MVC application. From my searches it seems this was a known issue for Razor v1, but the solutions they provide don't seem to apply here.
You should be using #Url.Content() helper (We're not in ASP.NET any more, toto).
<script src="#Url.Content("~/Scripts/jquery-2.0.3.min.js")"></script>
<!-- etc. -->
Another option is to use the Microsoft.AspNet.Web.Optimization package and create bundles:
**BundleConfig.cs
public void RegisterBundles(BundleCollection bundles)
{
// ...
bundles.Add(new ScriptBundle("~/js/site").Include(
"~/Scripts/jquery-2.0.3.min.js",
"~/Scripts/easing.js",
"~/Scripts/bootstrap.js"
));
// ...
}
Then in your page use:
#Scripts.Render("~/js/site")
Either stick the references in a bundle and use #Scripts.Render("~/bundlename") or use
<script src="#Url.Content("~/scripts/jquery-2.0.3.min.js")"></script>
Problem/Question
I want to include the rendered HTML from my views in the Jasmine test suites that run on my CI build so I can verify the Knockout bindings are not broken and the interaction with the view-model works as expected. Is there an established method for doing this?
My current setup:
I have a application that is using MVC with Razor views, Web-API and Knockout.js with the MVVM pattern. I want to add testing for the ever growing amount of JavaScript in the project. I started by adding tests using Jasmine. In my tests I created JSON objects to mock the data that would normally be provide by my Web-API calls. I added the execution of the tests to by CI build.
So far so good, except I felt this wasn't a good integration test. If someone modified the structure of the data for a Web-API call the code may fail in production. But the test would still pass because it is using static mock data. The same was true if the view was changed. The knockout binding could very well break and the tests wouldn't indicate that at all.
I was able to solve the problem of the static data. There may be a better solution, but what I did was create an executable that serializes the same data that the Web-API method would return. It saves that data to a .js file. I added the executable as a build step. I can then just load those .js files in my tests and use that data. If the object that is being serialized by the Web-API/executable changes, the tests fail and my CI build goes red.
Back to my problem:
The point of my question is that I have not found a good solution for the problem of how to make my CI ensure the Knockout binding on my views stay in sync with the view-model? My thought is to somehow render my razor view to an HTML file. Then use that in the test for the Knockout binding. I haven’t found a good method to do this though.
I have included some samples of how my tests are currently setup. Testing the Knockout binding for this simple examples probably isn't necessary. My real world view-models have much more logic that is dependent on the data and the binding though. I would like to be able to test that.
I’m also open to any evidence that my whole approach is flawed and there is a better way to ensure all the pieces work together.
Data that is written to .js file (JSON would normaly come from Web-API call)
var customerData = { "ID": "123", "FirstName": "John", ... more data... }
Jasmine test:
describe("domain.myViewModel.test", function () {
var vm;
beforeEach(function () {
vm = new myViewModel(customerData);
});
it("should should have some data", function () {
//assert something
});
}
HTML File to load tests
<!DOCTYPE html>
<html>
<head>
<title>Jasmine Test Runner</title>
<!-- include jasmine files here... -->
<link href="/TestRunner/jasmine-1.3.1/jasmine.css" rel="stylesheet" type="text/css">
<script src="/TestRunner/jasmine-1.3.1/jasmine.js" type="text/javascript"></script>
<script src="/TestRunner/jasmine-1.3.1/jasmine-html.js" type="text/javascript"></script>
<script src="/TestRunner/jasmine.junit_reporter.js" type="text/javascript"></script>
<!-- include source files here... -->
<script src="/jsscripts/views/productclass/domain.myViewModel.js" type="text/javascript"></script>
<!-- include test js files here... -->
<script src="/DataScripts/customerData.js" type="text/javascript"></script>
<script src="/Tests/domain.myViewModel.test.js" type="text/javascript"></script>
<!-- include jasmine.js files here... -->
<script src="/TestRunner/executeJasmine.js" type="text/javascript"></script>
</head>
<body>
// I want the HTML from by views here
// So I can test the bindings and interactions work as expected
</body>
</html>
A simple question (I hope):
We have a set structure within our projects for Assets, that being /Assets/img/, /Assets/css/ and /Assets/js/
I've been reading Brad Wilson's excellent article on Unobtrusive AJAX, in which he mentions the files required, FTA:
In addition to setting the flag, you will also need to include two script files: jQuery (~/Scripts/jquery-1.4.1.js) and the MVC plugin for unobtrusive Ajax with jQuery (~/Scripts/jquery.unobtrusive-ajax.js).
Is anyone aware of a way of informing MVC to look in a folder other than /Scripts/ for these files - I don't want to add a whole folder in the root of the project just for these 2 files.
UPDATE
Oh dear, end of the day brain-rot obviously. Sorry all!
Many thanks
In your view, you can use whatever path you want to set up for your scripts:
<script src="#Url.Content("~/Scripts/jquery-1.4.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
I have mine pointed to the Scripts folder as that is what was set up by default, but you can change that to your specific path.
the way that I have seen it done is to create an extension method on the HtmlHelper class for including javascript.
public static string Script(this HtmlHelper helper, string filename)
{
if(!filename.EndsWith(".js")) filename += ".js";
var path = string.Format("<script src='/Assets/js/{0}' type="text/javascript"></script>", filename);
return path;
}
then in your master page you can add this block to the header
<%= Html.Script("jquery-1.4.1") %>
<%= Html.Script("jquery.unobtrusive-ajax.min") %>