It's pretty much in the title but to re-iterate: Is there a way to use Visual Studio's built in bundling to grab scripts from an external domain?
If not directly, would there be a way to include js/css files from an external domain within the sln so that bundling would work?
The question stems from the desire to have a domain which contains common javascript libs/snippets that can then be used by several other sites. All sites and files are owned and run by the same company.
Any help would be appreciated.
As Jasen said, a CDN is what you're describing. I know this is old but I found it on a search of the topic so I'm going to submit an example for those who also find it.
Here's a normal BundleConfig entry:
bundles.Add(new ScriptBundle("~/bundles/js").Include(
"~/lib/jquery/jquery.js"));
Here's the overload to ScriptBundle that allows using a CDN:
bundles.Add(new ScriptBundle("~/bundles/js", "https://code.jquery.com/jquery-3.1.0.min.js").Include(
"~/lib/jquery/jquery.js"));
BundleTable.EnableOptimizations = true;
bundles.UseCdn = true;
It's an overload of ScriptBundle, with the second string argument being the CDN URL. You also have to add the two flags following.
Related
I developed a website, which can be used by different customers. As a result, we want to give different CSS styles and images to individual customers.
What we want is to manage CSS and images separately, so we won't need to deploy the site again just because we added some new CSS or images. As the site is under MVC, when accessing URLs such as:
www.mysite.com/customerA/myPage
www.mysite.com/customerB/myPage
we can find the customer id and find the right CSS and image to return.
The problem is that we want to bundle CSS, when the CSS or images are bundled, two issues will occur:
How the bundle detect underlying CSS file change? Is it possible?
Some users may already visited the URL and cached the bundled CSS, how can we disable the cached CSS, so it will get the new version?
The .NET bundling strategy is very intelligent in solving both of your issues. Once you create a bundle - example below:
bundles.Add(new StyleBundle("~/Content/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"));
And render this bundle out on your website, the output looks something like this:
<link href="/Content/css?v=xUfHQEnjwMk9UEexrvHPdvPxJduGrgz0bbI5qy5BGHY1" rel="stylesheet"/>
Notice the ?v=bigTextstring. Anytime a file in your bundle changes, the bundling framework will change the bigTextString after the ?v=. So, for your first question, yes, it will automatically detect file changes. You can get more information about how all of that process works if you visit this SO question. For your second question, the ?v= parameter, when changed, signals the client's browser that this is a different file than you had, you need to download it again.
Tommy has a great answer. I just wanted to elaborate on a few points.
First, as long as the bundle itself hasn't changed (added/removed scripts/styles or changed the location of those files), then you can freely update the files themselves without republishing the whole site. The bundler runs at runtime and looks at the last modified timestamp of the included files. If any of the files has changed, a new bundle will be generated with an updated cache-busting querystring param.
However, since the actual bundle configuration is code-based, if you add/remove items from the bundle or change the location of the file(s), such that you have to update the bundle configuration in BundleConfig.cs then you must republish, or at least also update the project DLL. This is because the code compiled within that DLL has changed.
I have minified CSS and JS files that are auto-generated by Web Essentials, and auto-updated every time I update and save the original files.
What would be the best way to automatically toggle the actual (script/import) references within HTML between original (in Dev/Test) and minified (in Production) files?
This is within an MVC ASP.NET web app.
One idea would be to have server-side tags that render either ".min" or empty string based on an environment variable. But I'm wondering if there's a better, smarter, easier, more efficient way of handling this.
Thanks in advance.
Update:
My style bundle is defined like this:
bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/site{version}.css"));
And I reference it like this:
#Styles.Render("~/Content/css")
However, this renders the following:
<link href="/Content/css?v=" rel="stylesheet"/>
It works fine if I take "{version}" out of bundle definition, but renders an empty "v=" if I include "{version}".
Update 2:
I just realized that due to certain complexities of the application, I can't use the bundling solution. What other options do I have?
Bundling will help you in this instance. You should already be able to see an example in your BundleConfig.cs file in App_Start.
Here is a tutorial on how to conifgure it http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification
From that tutorial, this is how you actually configure the bundles themselves, the files that will be in them, etc. This includes any jquery in the scripts folder into a bundle called ~/bundles/jquery.
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
// Code removed for clarity.
BundleTable.EnableOptimizations = true; // <-- this line overrides the debug check to show you the minified version even in debug mode... remove it for normal .min in debug/un-minned when not in debug behaviour
}
You then reference these from your views using
#Scripts.Render("~/bundles/jquery")
This will then render a script tag with the .min version of the jquery if you're not in debug or leave it out if you are. There needs to be a .min version and an un-minified version in the same scripts folder (which you should have if Web Essentials is creating the .min for you.
You could actually stop using Web Essentials to do the minification if you use ScriptBundles as they will minify the javascript for you when it packages it into the bundle.
For your update
The "~/Scripts/jquery-{version}.js" means match any file in the scripts folder that starts with jquery- and ends with .js and has some version number between. If the files don't have a version number in them, then don't try and use the {version} substitution.
They do it with jquery in this case so that if you upgrade the version of jquery that you are using, you don't have to go back into your BundleConfig and manually change the file name for your jquery reference.
If your file was named site1.3.7.css, then this would probably work.
bundles.Add(new StyleBundle("~/Content/css")
.Include("~/Content/site{version}.css"));
but it sounds more likely that you just need site.css.
bundles.Add(new StyleBundle("~/Content/css")
.Include("~/Content/site.css"));
I'm not sure what you think prevents you from using them but you can link to files in CDNs and minify or not minify. Even just have individual files in a bundle to get the benefit of minification outside of debug without "bundling" them. So there's probably a way.
I've searched SO - found many of the same question, though none of the answers helped.
I've built a bunch of sites and not ran into this issue before.
Essentially, my script bundle results in a 404 for each of the files in my javascript folder.
My structure (at the moment, i've changed it a bunch!) looks like this:
I do this so i can guarantee that ASP.Net doesn't change the order - i can ensure certain scripts are ahead of others. It's how i've always done it and it normally works well.
My bundle script - at the moment - is:
public static void RegisterBundles(BundleCollection bundles)
{
bundles.FileSetOrderList.Clear();
// stlyes
StyleBundle cssBundle = new StyleBundle("~/bundles/css");
cssBundle.IncludeDirectory("~/content/css", "*.css", true);
bundles.Add(cssBundle);
//scripts
ScriptBundle jsBundle = new ScriptBundle("~/bundles/jscript");
jsBundle.IncludeDirectory("~/content/javascript", "*.js", true);
bundles.Add(jsBundle);
}
I have tried a whole bunch of virtual paths.
My CSS loads perfect. My Js - i get a list of 404's; one for each of the */js files.
Any ideas?
My console looks like this - which also shows me that bundles.FileSetOrderList.Clear(); isn't actually clearing its list else i would have jquery before angular (as is my intent)
UPDATE
If i BundleTable.EnableOptimizations = true; in my bundles then it's all bundled, minified and works - though this sucks for development debugging - what on earth is preventing it working in debug mode?!
This post seems to describe the same problem ASP.Net MVC 5 sub-directory bundling issues and is a known issue with version 1.1.1 of the Bundling framework.
If you don't want to have to downgrade or upgrade to a version where this is working, you always have the option of explicitly adding files to the bundle that you want to come first. Let's say you have your files in the same folder.
/javascript/lib/ascript.js
/javascript/lib/ascript2.js
/javascript/lib/jquery.js
/javascript/lib/yscript.js
You can be explicit about the files you want first via Include(), and then still lump the rest together via IncludeDirectory().
bundles.Add(new ScriptBundle("~/bundles/jscript").Include(
"~/javascript/lib/jquery.js",
.IncludeDirectory("~/javascript/lib", "*.js")
The bundling is smart enough to not double include jQuery.js if it has been explicitly added first. Similarly, you can have multiple .IncludeDirectory calls on your various subdirectories if you want to still keep them sub-foldered.
If you set the enable optimization flag to true, it will overwrite the debug=false and bundle it. just use the below code snippet in your bundle.config file to remove bundling in debug mode.
#if !DEBUG
BundleTable.EnableOptimizations = true;
#endif
I think that it is the nested folders. I'm pretty sure the bundles only look in that direct folder. Have you used that folder structure with bundling before and it worked successfully?
As mentioned I kept getting jquery 404 not found.
This isn't a great answer but this is what I settled with until I find a better answer.
My issue was with the following, this worked very happily locally in development.
bundles.Add(new ScriptBundle("~/jquery").Include(new[]
{
"~/scripts/jquery-1.12.0.min.js",
}));
I tried variations and looked at the other options, in the end I changed it to the following for production. Googles CDN has always been reliable, there is other CDN options if you google around.
bundles.Add(new ScriptBundle("~/jquery", "https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"));
We have legacy code to maintain and, to solve a specific customer customization problem, we want to route calls to some files to other files. That is, when the app calls a particular ASPX, it will end up hitting another ASPX.
If you call:
www.foo.com/admin/admin.aspx
It will actually hit:
www.foo.com/customizations/customer1/admin/admin.aspx
This is not a good design but this is legacy code. We just want to solve this.
We are using the System.Web.Routing framework to solve it. This works fine when you set RouteExistingFiles to true, except for static files (CSS, JavaScript and Images).
When I first tried it, it retrieved this error:
There is no build provider register for the extension '.css'.
So I did register a build provider in the web.config file for the .css extension. I used this build provider: PageBuilderProvider because someone recommended it in the internet.
It works! But the CSS is being served with text\html content type.
How do I achieve this?
TL;DR: I want to use routes in ASP.NET Web Forms to make a call for a specific CSS file to actually retrieve another one. A customer needs this for customization.
Try coding a HttpHandler. I had to do something similar but for PDF files, I coded a custom HttpHandler in the end - works very well. You can even set the content type in the HttpHandler code and have a pattern matched path the handler will be used for in the web.config. You can also configure it in web.config not to execute if the path does not point to an existing file e.g. so a 404 is returned without having to code that in the handler itself. I can't post my code (VB.NET) ATM because I'm using a tablet but google search for tutorials. You will also probably need to use the TransmitFile function to actually write out the css file. Is it a web forms project or web site? If its a web site there is a special way of registering the HttpHandler in the web.config.
I am currently working with web optimization bundler that is part of the .net framework that bundles up both my javascript and css in to a single file. This works nicely.
I have run in to a problem with it though. See the following code:
BundleTable.Bundles.Add(new ScriptBundle("mybundle").Include(
"~/Scripts/globalize.js",
"~/Scripts/jquery.validate.js",
string.Format("~/resources.axd")));
This bundles up all the javascript from the files but also I would like to bundle the output from my .axd http handler. This returns javascript. However the javascript never gets included in the bundle. If I run the handler in my browser, no issue, javascript is returned.
I am wondering maybe the bundler does not recognize the .axd extension and therefore does not attempt to request the file. Any ideas if this is the case and the work around?
Correct, you can only include files into bundles, it will not make requests to the axd for you. What you can do is manually hit the axd, and save the file to disk and include that into your bundle.
I just wrote a script bundle for resx - you can find the source here
https://github.com/MrAntix/sandbox-resx-script-bundling
In BundleConfig, add your bundle ...
bundles.Add(
new ResxScriptBundle("~/bundles/local")
.Include<JsResources>("app")
);
It creates a model for each resource like this ...
window.resources=window.resources||{};
window.resources.app = {
"HelloWorld": "Hello World, from JSResources.resx"
};
And you can use it in your JS like this ...
$("h1").append(window.resources.app.HelloWorld);
... for example