Bundling and Minification Confusion - javascript

I'm using ASP.NET Web Forms with master pages. There are so many moving parts to this that I cannot figure it out. Different tutorials use different parts of it and omit others, that I cannot determine what is needed and what is fluff.
Different Parts:
Master Pages: In the head section for my CSS I have:
<link href="Content/css" rel="stylesheet" />
<asp:PlaceHolder runat="server">
<%: Scripts.Render("~/bundles/modernizr") %>
</asp:PlaceHolder>
Before closing body tag, I have:
<script src="<%= ResolveUrl("~") %>Scripts/jquery-2.1.1.js"></script>
<script src="<%= ResolveUrl("~") %>Scripts/bootstrap.min.js"></script>
<script src="<%= ResolveUrl("~") %>Scripts/jquery.reject.js"></script>
<script src="<%= ResolveUrl("~") %>Scripts/general.js"></script>
Looks like the min one is not needed, but do I need any of these and instead use
<script src="Scripts/js"></script> ?
Global.asax.cs: this seems simple enough, registering the bundles in Application_Start method.
void Application_Start(object sender, EventArgs e)
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Web.config:
I added the System.Web.Optimization namespace and the Microsoft.AspNet.Web.Optimization.WebForms assembly.
Bundle.config: I have no idea what this is for; many tutorials don't even mention it?
BundleConfig.cs: As well as the standard WebFormsJs, MsAjaxJs and modernizr custom bundles, I have the following for CSS:
bundles.Add(new StyleBundle("~/bundles/css").Include(
"~/Content*"));
This is not working. I was about to add something similar for my JS files but got confused as to why I am doing this at all when according to this tutorial, all I needed for the CSS was:
<link href="Content/css" rel="stylesheet" />
Presumably, all I needed for my JS files was:
<script src="Scripts/js"></script>
In some tutorials I have seen ScriptManager.ScriptResourceMapping.AddDefinition - what is this for?
Here is the current state of my CSS and Scripts folders - I need all the non-minifed versions of these:
http://imgur.com/XwqIOKl
http://imgur.com/q8IdhmB
Can someone help me piece this together? I am running locally with debug set to false.

Below is a list of each of the sections that need to be configured for Bundling and Minification in WebForms.
This is taken from a production code base which is running Bundling and Minification.
Libraries:
Microsoft.AspNet.Web.Optimization
Dependencies:
WebGrease
Microsoft.Web.Infrastructure (depending on version)
Global.asax
void Application_Start(object sender, EventArgs e)
{
BundleConfig.RegisterBundles(BundleTable.Bundles);
//Use this if you want to force/test bundling in debug.
BundleTable.EnableOptimizations = true;
}
BundleConfig class
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/sitejs")
//Add as many JS libraries you would like to the bundle...
.Include("~/Scripts/jquery-3.1.1.js")
.Include("~/Scripts/jquery-migrate-3.0.0.js")
);
bundles.Add(new StyleBundle("~/bundles/sitecss")
//Add as many CSS files that you would like to the bundle...
.Include("~/css/jquery-ui.css")
);
}
}
Master Page:
<!-- At the top of the Master Page -->
<%# Import Namespace="System.Web.Optimization" %>
<!-- Just after the closing `</form>` tag -->
<asp:PlaceHolder runat="server">
<%: Styles.Render("~/bundles/sitecss") %
<%: Scripts.Render("~/bundles/sitejs") %
</asp:PlaceHolder>

Related

Blazor WebAssembly load different scripts for specific Environment

I'm currently working on a .NET Standard 2.1 Blazor WebAssembly application. I try to include or exclude JavaScript files in my index.html according to an environment variable.
The Blazor WebAssembly App is NOT Asp.NET Core hosted.
In .NET Core there are usually Environment Tag Helpers like in the following example:
<environment include="Development">
<script src="js/app.js"></script>
<script src="js/helpers.js"></script>
</environment>
<environment exclude="Development">
<script src="js/site.min.js"></script>
</environment>
As already discussed in this question Blazor WebAssembly Environment Variables, the Environment Tag Helpers are server side code and thus don't work in Blazor WASm.
Now I try to find a good solution to include/exclude JavaScript files according to the Environment variable in Blazor WebAssembly.
The first idea was, similar like for CSS, to create a component called <Scripts> to load the different script files on the index.html like this:
#using Microsoft.AspNetCore.Components.WebAssembly.Hosting
#inject IWebAssemblyHostEnvironment hostEnv
#*Check the environment value*#
#if (hostEnv.IsDevelopment())
{
<script src="js/app.js"></script>
<script src="js/helpers.js"></script>
}
else
{
<script src="js/site.min.js"></script>
}
#code {}
Unfortunately this doesn't work, because the <script> Element is not allowed to be used in a Blazor component (.razor file).
The following error occurs: The script element allows authors to include dynamic script and data blocks in their documents. The element does not represent content for the user. ... Script tags should not be placed inside components because they cannot be updated dynamically. To fix this, move the script tag to the 'index.html' file or another static location. ... https://go.microsoft.com/fwlink/?linkid=872131
How do you load different scripts according to the Environment Variable i.e. Development, Production or Staging in Blazor Webassembly?
Do you know how to solve this problem?
I wanted to add Tailwind CDN script tag just during development. I ended up using the solution below:
index.html
<script src="_framework/blazor.webassembly.js"></script>
<script>
// If localhost, add tailwind CDN (or any other script that you want)
if (window.location.hostname == 'localhost') {
var customScript = document.createElement('script');
customScript.setAttribute('src', 'https://cdn.tailwindcss.com');
document.head.appendChild(customScript);
}
</script>
Simply copy your index.html code in a .cshtml (named BlazorApp.cshtml in the following sample) in your server project and fallback to this page.
public void Configure(IApplicationBuilder app)
{
...
app.UseEndpoints(endpoints =>
{
...
endpoints.MapFallbackToPage("/BlazorApp");
}
}
And update the code with <environment> tags for your conveniance.
Please check the solution in this answer (same question as you linked above) and that seems to work.
Basically the workaround is to use this in a new component called Head.razor as per the solution:
#inject IWebAssemblyHostEnvironment hostEnv
#if (hostEnv.IsDevelopment())
{
<title>BlazorWasmApp - In Debug</title>
<link href="css/debug.css" rel="stylesheet" />
}
else
{
<title>BlazorWasmApp - Not Debug</title>
<link href="css/live.css" rel="stylesheet" />
}
New Head.razor component:
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
//Add the Head to root components
builder.RootComponents.Add<Head>("head");
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}

Include static files in a reusable Razor Class Library

I am trying to make a reusable class library (RCL) that I can use in several ASP.NET Core MVC projects. So far so good… until I try to include the required JavaScript in the RCL. There is little-to-no documentation about this topic. My best shot was to try this example.
But when I do, I get the following error when I build the library:
This is the project file and the structure of the library:
Any help is appreciated.
Now that I have some spare time I will answer my own question. Maybe it will useful for someone.
Finally I solved this problem using EmmbededResources without the EmbeddedFilesManifest as ianbusko pointed out in Github.
First I created an extension for the IApplicationBuilder class:
namespace Dashboard.Lib.Extensions
{
public static class IApplicationBuilderExtension
{
public static void UseDashboardScripts(this IApplicationBuilder builder)
{
var embeddedProvider = new EmbeddedFileProvider(typeof(Areas.Dashboard.ViewComponents.DashboardViewComponent)
.GetTypeInfo().Assembly, "Dashboard.Lib.Scripts");
builder.UseStaticFiles(new StaticFileOptions()
{
FileProvider = embeddedProvider,
RequestPath = new PathString("/Scripts")
});
}
}
}
Then I added the javascript files to the project file:
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<GenerateEmbeddedFilesManifest>false</GenerateEmbeddedFilesManifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.3" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="2.1.1" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Scripts/**/**/**/*" Pack="true" />
</ItemGroup>
In the RCL view the javascript is included as follows:
#section Scripts{
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script type="text/javascript" src="~/Scripts/pagination.js"></script>
<script type="text/javascript" src="~/Scripts/checkdigit-validator.js"></script>
<script type="text/javascript" src="~/Scripts/rut-validation.js"></script>
}
Finally in the Statup.cs in the main MVC project you just have to include the following:
app.UseStaticFiles();
app.UseDashboardScripts();

How and where to add JQuery in Module project in DotnetNuke(DNN)?

I am beginner in DotnetNuke. I am creating a project which provide a Module that can be add in DotnetNuke based website.
I have configured www.dnndev.me in my IIS server and created project in DesktopModule folder of it. I can create, build and add my module to www.dnndev.me successfully but I don't know where to add JQuery in Solution Explorer of my module project.
1- Where should I add my JS and CSS files? I have tried by adding a folders "Assets", "Assets/CSS", "Assets/JS" and put my files there in my solution explorer.
2- How to include JS/CSS files in ascx page?
I have tired by following
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="View.ascx.cs" Inherits="CustomerDemo.Modules.CustomerDemo.View" %>
<dnn:DnnCssInclude runat="server" FilePath="~/DesktopModules/CustomerDemo/Assets/JS/fullcalendar.min.js" />
<dnn:DnnCssInclude runat="server" FilePath="~/DesktopModules/CustomerDemo/Assets/JS/jquery-ui-timepicker-addon.js" />
By above way .js shows in my source of webpage but it doesn't call. But if I try by following way, it works
<script type="text/javascript">
$(document).ready(function () { $.getScript("http://www.dnndev.me/DesktopModules/CustomerDemo/Assets/JS//jquery-ui-timepicker-addon.js?_=1483026285109", function () {
if ($('.mmdd').length > 0) {
$(".mmdd ").datetimepicker();
}
});
});
</script>
Can anybody please suggest me how and where to place .js and '.css' files and how to include them in project?
I am using: Visual Studio 2015 & DotnetNuke 8 Commnunity
File path confusion:
This is my physical location of folder when I open by Right Click--> Open with folder explorer
F:\websites\dnndev.me\DesktopModules\CustomerDemo\CustomerDemo\Assets
But when I drag CSS or JS file from file explorer to ascx design page, it use this location: "~\DesktopModules\CustomerDemo\Assets\file.css"
you can see that the physical path has 2 folder of CustomerDemo and the file dragged from solution explorer having path with only 1 CustomerDemo folder.
I don't understand this mechanism. Which one should I use? Can somebody clear my mind for this?
I have tried this way as one of the suggestion but it looks like I am missing something
Use the DnnJsInclude control of the Client Resource Management for registering scripts instead of the DnnCssInclude.
In your .ascx:
<%# Register TagPrefix="dnn" Namespace="DotNetNuke.Web.Client.ClientResourceManagement" Assembly="DotNetNuke.Web.Client" %>
<dnn:DnnJsInclude runat="server" FilePath="~/DesktopModules/CustomerDemo/Assets/JS/fullcalendar.min.js" />
OR in your code behind, you could instead use the ClientResourceManager API:
protected void Page_PreRender(object sender, EventArgs e)
{
ClientResourceManager.RegisterScript(this.Page, base.ControlPath + "/Assets/JS/fullcalendar.min.js", 100);
ClientResourceManager.RegisterScript(this.Page, base.ControlPath + "/Assets/JS/jquery-ui-timepicker-addon.js", 100);
ClientResourceManager.RegisterStyleSheet(this.Page, base.ControlPath + "/Assets/CSS/module.css", 100);
}

ASP.NET WebForms Routing Javascript Error

I have some problems with JavaScript using ASP.NET 4.0 WebForms Routing.
My code:
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
void RegisterRoutes(RouteCollection routes)
{
routes.Ignore("{resource}.axd/{*pathInfo}");
routes.MapPageRoute("GoodInfo", "catalog/good/{good}", "~/GoodInfo.aspx");
routes.MapPageRoute("GoodGroup", "catalog/group/{group}", "~/default.aspx");
}
With no routing everything is ok. But when I use it I got an error on hte page (in Firebug)
Error: jQuery is not defined
on this line:
jQuery(document).ready(function () {
HideBlocks();
});
So my JavaScript does not work on the page that was routed.
I added this line routes.Ignore("{resource}.axd/{*pathInfo}"); but it didn't helped me.
I have solved my problem! The solution consists of 2 parts.
Firstly I changed my scripts definition from
<script type="text/javascript" src="../scripts/something.js"></script>
to
<script type="text/javascript" src="/../scripts/something.js"></script>
Thanks MilkyWayJoe fot that solution.
Secondly I added Ignore Routing
routes.Ignore("catalog/good/{resource}.axd/{*pathInfo}");
instead of:
routes.Ignore("{resource}.axd/{*pathInfo}");
So my web resources have no more routes on pages like http://mysite.com/catalog/good/41
Also I have script events on the page like http://mysite.com/catalog/good/41/event/seq/1. To catch all parameters I add to my route rules this
routes.Ignore("catalog/good/{good}/{*query1}");
routes.Ignore("catalog/good/{good}/{query1}/{*query2}");
routes.Ignore("catalog/good/{good}/{query1}/{query2}/{*query3}");
routes.Ignore("catalog/good/{good}/{query1}/{query2}/{query3}/{*query4}");
And don't forget that your Ignore declarations must be placed before MapPageRoute declarations:
routes.Ignore("catalog/good/{resource}.axd/{*pathInfo}");
routes.MapPageRoute("GoodInfo", "catalog/good/{good}", "~/GoodInfo.aspx");`enter code here`
If you look at the generated source of your page, is the jQuery library included?
If you are including jQuery via a resource, double check that it is included and that it is before that line that errors.

Linking JavaScript Libraries in User Controls

I have been using ASP.NET MVC for six months or so and have been checking out the Nerd Dinner example created by those Microsoft guys. One thing I noticed they did when enabling AJAX to RSVP for a dinner, is put the JavaScript references in the User Control being used for RSVPing.
(FILE: RSVPStatus.ascx)
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.Dinner>" %>
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
This doesn't seem right to me, as there is a really good chance I would be using these same libraries elsewhere, like logon authentication. Plus if I change script versions, I need to hunt down all the references to the libraries.
So I ask if my thinking is correct and these references should actually be in a more central location like the master page?
Please let me know what the best practice is for this and pro's and cons if any.
I would definitely advise against putting them inside partials for exactly the reason you mention. There is a high chance that one view could pull in two partials that both have references to the same js file. You've also got the performance hit of loading js before loading the rest of the html.
I don't know about best practice but I choose to include any common js files inside the masterpage and then define a separate ContentPlaceHolder for some additional js files that are specific to a particular or small number of views.
Here's an example master page - it's pretty self explanatory.
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<head runat="server">
... BLAH ...
<asp:ContentPlaceHolder ID="AdditionalHead" runat="server" />
... BLAH ...
<%= Html.CSSBlock("/styles/site.css") %>
<%= Html.CSSBlock("/styles/ie6.css", 6) %>
<%= Html.CSSBlock("/styles/ie7.css", 7) %>
<asp:ContentPlaceHolder ID="AdditionalCSS" runat="server" />
</head>
<body>
... BLAH ...
<%= Html.JSBlock("/scripts/jquery-1.3.2.js", "/scripts/jquery-1.3.2.min.js") %>
<%= Html.JSBlock("/scripts/global.js", "/scripts/global.min.js") %>
<asp:ContentPlaceHolder ID="AdditionalJS" runat="server" />
</body>
Html.CSSBlock & Html.JSBlock are obviously my own extensions but again, they are self explanatory in what they do.
Then in say a SignUp.aspx view I would have
<asp:Content ID="signUpContent" ContentPlaceHolderID="AdditionalJS" runat="server">
<%= Html.JSBlock("/scripts/pages/account.signup.js", "/scripts/pages/account.signup.min.js") %>
</asp:Content>
HTHs,
Charles
Ps. I would agree with Andrew in saying that any common JS that is defined directly inside the master page should be concatenated and minified.
EDIT: My implementation of .JSBlock(a, b) as requested
public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName)
{
return html.JSBlock(fileName, string.Empty);
}
public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName, string releaseFileName)
{
if (string.IsNullOrEmpty(fileName))
throw new ArgumentNullException("fileName");
string jsTag = string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>",
html.MEDebugReleaseString(fileName, releaseFileName));
return MvcHtmlString.Create(jsTag);
}
And then where the magic happens...
public static MvcHtmlString MEDebugReleaseString(this HtmlHelper html, string debugString, string releaseString)
{
string toReturn = debugString;
#if DEBUG
#else
if (!string.IsNullOrEmpty(releaseString))
toReturn = releaseString;
#endif
return MvcHtmlString.Create(toReturn);
}
In my website, www.trailbehind.com, we have a set of javascript files that belong on all pages. And then some pages include additional libraries.
For the JS files that all pages uses (there are a couple dozen files), we concatenate them and minify them on build.
There is a flag in our settings file that says whether to use the concatenated javascript or the separate files on build. This is critical so that you can debug the javascript on dev, but use the small, single-file javascript on production.
Here is our python code to combine and minify:
import os
import thetrailbehind.lib.jsmin as jsmin
JS_FILES = [ 'lib/json2.js',
'lib/markermanager.js',
'lib/labeledmarker.js',
'lib/rsh/rsh.js',
'lib/showdown.js',
'lib/yui.js',
'lib/dragzoom.js',
'gen/attribute_data.js',
'gen/national-parks.js',
'Widgets/CommentsWidget.js',
'Widgets/Search.js',
'Widgets/MenuWidget.js',
'Widgets/PhotoWidget.js',
'Widgets/ReportList.js',
'Widgets/help.js',
'attributes.js',
'rsh.js',
'map.js',
'mapcontrols.js',
'markers.js',
'amazon.js',
'plan_trip.js',
'init.js',]
def concat(files, base_path, all_file, all_file_min):
if os.path.exists(base_path + all_file):
lasttime = os.path.getmtime(base_path + all_file)
else:
lasttime = 0
out_of_date = False
for file in files:
if os.path.getmtime(base_path + file) > lasttime:
out_of_date = True
break
if out_of_date:
outfile = open(base_path + all_file, 'w')
for file in files:
outfile.write(open(base_path + file).read())
outfile.write("\n")
outfile.close()
alljs = open(base_path + all_file)
allminjs = open(base_path + all_file_min, "w+")
jsmin.JavascriptMinify().minify(alljs, allminjs)
alljs.close()
allminjs.close()
def main():
concat(JS_FILES, '/home/wibge/thetrailbehind/media/javascript/', 'gen/all.js', 'gen/all.min.js')
if __name__ == "__main__":
main()
And here is the Django/HTML template where we switch:
{% if use_all_js %}
script type=text/javascript src=/site_media/javascript/gen/all.min.js>
{% else %}
script type="text/javascript" src="/site_media/javascript/rsh.js">
script type="text/javascript" src="/site_media/javascript/amazon.js">
script type="text/javascript" src="/site_media/javascript/map.js">
A BUNCH OF SEPARATE INCLUDES...etc
{% endif %}

Categories

Resources