How to instruct Ajax Minifier to remove console.log from javascript - minify

I have lines in my js files like this
console.log('FunctionName()');
The default Ajax Minifier settings do not remove these lines from the .min.js output.
I noticed in this discussion a conversation about Kill switches.
Looking at the Kill Switch page here. I noticed there is this switch:
/// <summary>
/// remove "debug" statements
/// </summary>
StripDebugStatements = 0x0000000000800000,
I am not using the command line, I am referencing the DLL. This is how I have implemented it.
CodeSettings jsSettings = new CodeSettings()
{
KillSwitch = 800000,
};
and then later the actual minifier method.
string fileMinified = minifier.MinifyJavaScript(fileSource, jsSettings);
How can i remove console.log()?

Make you calls to console.Log from methods in "Debug" namespace ( http://ajaxmin.codeplex.com/wikipage?title=Preprocessor )
Sample:
var Debug = {};
Debug.myTrace = function(message){
console.log(message);
};
///#DEBUG
someDebugOnlyCode();
///#ENDDEBUG
All calls to Debug.myTrace will be removed during minification ("debug" namespace), as well as call to someDebugOnlyCode (inside DEBUG/ENDDEBUG comments).

Related

AngularJs Dynamic/Multiple HTML Templates

I'm working on an AngularJs/MVC app with Web API etc. which is using a CDN. I have managed to whitelist two URLs for Angular to use, a local CDN and a live CDN (web app hosted in Azure).
I can successfully ng-include a template from my local CDN domain, but the problem arises when I push the site to a UAT / Live environment, I cant be using a template on Localhost.
I need a way to be able to dynamically get the base url for the templates. The location on the server will always be the same, eg: rooturl/html/templates. I just need to be able to change the rooturl depending on the environment.
I was thinking if there was some way to store a global variable, possibly on the $rootScope somewhere that I can get to when using the templates and then set that to the url via Web API which will get return a config setting.
For example on my dev machine the var could be http://Localhost:52920/ but on my uat server it could be https://uat-cdn.com/
Any help would be greatly appreciated as I don't want to store Js, css, fonts etc on the CDN but not the HTML as it feels nasty.
Thanks I'm advance!
I think it's good practice to keep environment and global config stuff outside of Angular altogether, so it's not part of the normal build process and is harder to accidentally blow away during a deploy. One way is to include a script file containing just a single global variable:
var config = {
myBaseUrl: '/templates/',
otherStuff: 'whatever'
}
...and expose it to Angular via a service:
angular.module('myApp')
.factory('config', function () {
var config = window.config ? window.config : {}; // (or throw an error if it's not found)
// set defaults here if useful
config.myBaseUrl = config.myBaseUrl || 'defaultBaseUrlValue';
// etc
return config;
}
...so it's now injectable as a dependency anywhere you need it:
.controller('fooController', function (config, $scope), {
$scope.myBaseUrl = config.myBaseUrl;
}
Functionally speaking, this is not terribly different from dumping a global variable into $rootScope but I feel like it's a cleaner separation of app from environment.
If you decide to create a factory then it would look like this:
angular.module('myModule', [])
.factory('baseUrl', ['$location', function ($location) {
return {
getBaseUrl: function () {
return $location.hostname;
}
};
}]);
A provider could be handy if you want to make any type of customization during config.
Maybe you want to build the baseurl manually instead of using hostname property.
If you want to use it on the templates then you need to create a filter that reuses it:
angular.module('myModule').filter('anchorBuilder', ['baseUrl', function (baseUrl) {
return function (path) {
return baseUrl.getBaseUrl() + path;
}
}]);
And on the template:
EDIT
The above example was to create links but if you want to use it on a ng-include directive then you will have a function on your controller that uses the factory and returns the url.
// Template
<div ng-include src="urlBuilder('path')"></div>
//Controller
$scope.urlBuilder = function (path) {
return BaseUrl.getBaseUrl() + path;
};
Make sure to inject the factory in the controller

Referencing resources in a global way either from a virtual directory or the web root?

Let's say I have an MVC/WebAPI/AngularJS site that I'm running locally, e.g. ;
localhost/Test/
which I then want to move to
www.test.com
While local, I have a lot of references to various directories (jsfiles, etc) of the following format (in either JS or HTML files)
app.directive('rpdbSpinner', function() {
return {
restrict: 'E',
**templateUrl: '/Test/templates/directives/spinner.html',**
scope: {
isLoading:'='
}
}
})
when updating/web publishing, I'd have to change everything to:
app.directive('rpdbSpinner', function() {
return {
restrict: 'E',
**templateUrl: '/templates/directives/spinner.html',**
scope: {
isLoading:'='
}
}
})
I can do this manually (which is what I've been doing),but the larger the project grows, the harder it becomes. I could, of course, only change it once and then excluded the files during publishing phase (web.config/rest), but it still feels like I am going about it the wrong way. Using "~/" wouldn't work on plain HTML/JS files as far as I'm aware, and this I can't really use it...
Any suggestions to map to paths globally regardless of whether in a Virtual Directory or the root of a project?
Thanks :)
If you simply care about getting the root/base url of the site so you can append that to get the other url you are after, you may simply use / as the first character of your url.
var getUsersUrl = "/api/users";
Here is an alternate approach if you want more than just the app root (Ex : Specific urls( built using mvc helper methods such as Url.RouteUrl etc)
You should not hard code your app base path like that. You may use the Url.Content or Url.RouteUrl helper methods in your razor view to generate the url to the app base. It will take care of correctly building the url regardless of your current page/path.Once you get this value, assign it to a javascript variable and use that in your other js code to build your other urls. Always make sure to use javascript namespacing when doing so to avoid possible issues with global javascript variables.
So in your razor view (Layout file or specific view), you may do this.
<script>
var myApp = myApp || {};
myApp.Urls = myApp.Urls || {};
myApp.Urls.baseUrl = '#Url.Content("~")';
myApp.Urls.userListUrl = '#Url.Action("Index","User")';
</script>
<script src="~/Scripts/NonAngularJavaScript.js"></script>
<script src="~/Scripts/AngularControllerForPage.js"></script>
<script>
var a = angular.module("app").value("appSettings", myApp);
</script>
In your angular controller, you can access it like,
var app = angular.module("app", []);
var ctrl = function (appSettings) {
var vm = this;
console.log(appSettings.Urls.userListUrl);
vm.baseUrl = appSettings.Urls.baseUrl;
//build other urls using the base url now
var getUsersUrl = vm.baseUrl + "api/users";
console.log(getUsersUrl);
};
app.controller("ctrl", ctrl)
You can also access this in your data services, directives etc.
In your non angular java script files.
// With the base url, you may safely add the remaining url route.
var urlToJobIndex2= myApp.Urls.baseUrl+"jobs/GetIndex";
Using "~/" wouldn't work on plain HTML/JS files as far as I'm aware,
and this I can't really use it...
Yes, but you could inject it in your main server-side served webpage as a variable:
<script>
var baseUrl = ... get the base url from the server using ~/
</script>
and then in your external scripts simply concatenate the relative urls with it. As far as static html files are concerned, then it could be a little more problematic. You could serve them through some special server side handler that will take care of injecting this logic.
You can use module.constant to create an injectable which you can use.
app.constant("URL_BASE", "/Test");
app.directive('rpdbSpinner', function(URL_BASE) {
return {
restrict: 'E',
**templateUrl: URL_BASE + '/templates/directives/spinner.html',**
scope: {
isLoading:'='
}
}
})
You can also use module.value if you register it before you register your directive.
For more information see AngularJS Module Guide -- configuration.

Gulp: how to pass parameters from watch to tasks

With gulp you often see patterns like this:
gulp.watch('src/*.jade',['templates']);
gulp.task('templates', function() {
return gulp.src('src/*.jade')
.pipe(jade({
pretty: true
}))
.pipe(gulp.dest('dist/'))
.pipe( livereload( server ));
});
Does this actually pass the watch'ed files into the templates task? How do these overwrite/extend/filter the src'ed tasks?
I had the same question some time ago and came to the following conclusion after digging for a bit.
gulp.watch is an eventEmitter that emits a change event, and so you can do this:
var watcher = gulp.watch('src/*.jade',['templates']);
watcher.on('change', function(f) {
console.log('Change Event:', f);
});
and you'll see this:
Change Event: { type: 'changed',
path: '/Users/developer/Sites/stackoverflow/src/touch.jade' }
This information could presumably be passed to the template task either via its task function, or the behavior of gulp.src.
The task function itself can only receive a callback (https://github.com/gulpjs/gulp/blob/master/docs/API.md#fn) and cannot receive any information about vinyl files (https://github.com/wearefractal/vinyl-fs) that are used by gulp.
The source starting a task (.watch in this case, or gulp command line) has no effect on the behavior of gulp.src('src-glob', [options]). 'src-glob' is a string (or array of strings) and options (https://github.com/isaacs/node-glob#options) has nothing about any file changes.
Hence, I don't see any way in which .watch could directly affect the behavior of a task it triggers.
If you want to process only the changed files, you can use gulp-changed (https://www.npmjs.com/package/gulp-changed) if you want to use gulp.watch, or you cold use gulp-watch.
Alternatively, you could do this as well:
var gulp = require('gulp');
var jade = require('gulp-jade');
var livereload = require('gulp-livereload');
gulp.watch('src/*.jade', function(event){
template(event.path);
});
gulp.task('templates', function() {
template('src/*.jade');
});
function template(files) {
return gulp.src(files)
.pipe(jade({
pretty: true
}))
.pipe(gulp.dest('dist/'))
}
One of the possible way to pass a parameter or a data from your watcher to a task. Is through using a global variable, or a variable that is in both blocks scops. Here is an example:
gulp.task('watch', function () {
//....
//json comments
watch('./app/tempGulp/json/**/*.json', function (evt) {
jsonCommentWatchEvt = evt; // we set the global variable first
gulp.start('jsonComment'); // then we start the task
})
})
//global variable
var jsonCommentWatchEvt = null
//json comments task
gulp.task('jsonComment', function () {
jsonComment_Task(jsonCommentWatchEvt)
})
And here the function doing the task work in case it interest any one, But know i didn't need to put the work in such another function i could just implemented it directly in the task. And for the file you have your global variable. Here it's jsonCommentWatchEvt. But know if you don't use a function as i did, a good practice is to assign the value of the global variable to a local one, that you will be using. And you do that at the all top entry of the task. So you will not be using the global variable itself. And that to avoid the problem that it can change by another watch handling triggering. When it stay in use by the current running task.
function jsonComment_Task(evt) {
console.log('handling : ' + evt.path);
gulp.src(evt.path, {
base: './app/tempGulp/json/'
}).
pipe(stripJsonComments({whitespace: false})).on('error', console.log).
on('data', function (file) { // here we want to manipulate the resulting stream
var str = file.contents.toString()
var stream = source(path.basename(file.path))
stream.end(str.replace(/\n\s*\n/g, '\n\n'))
stream.
pipe(gulp.dest('./app/json/')).on('error', console.log)
})
}
I had a directory of different json's files, where i will use comments on them. I'm watching them. When a file is modified the watch handling is triggered, and i need then to process only the file that was modified. To remove the comments, i used json-comment-strip plugin for that. Plus that i needed to do a more treatment. to remove the multiple successive line break. Whatever, at all first i needed to pass the path to the file that we can recover from the event parameter. I passed that to the task through a global variable, that does only that. Allow passing the data.
Note: Even though that doesn't have a relation with the question, in my example here, i needed to treat the stream getting out from the plugin processing. i used the on("data" event. it's asynchronous. so the task will mark the end before the work completely end (the task reach the end, but the launched asynchronous function will stay processing a little more). So the time you will get in the console at task end, isn't the time for the whole processing, but task block end. Just that you know. For me it doesn't matter.

How do I allow an MIME extension map in ASP.NET vNext?

Background
I have a piece of LESS code that needs to be compiled at runtime with Less.js -- it calculates some things via JavaScript -- so I can't use the task runner, etc.
In my index.html, I have:
<head>
...
<link rel="stylesheet/less" href="assets/less/DynamicHeight.less" />
...
<script type="text/javascript" src="lib/less/less.js"></script>
...
</head>
Problem
Less.js appears unable to find the file:
And when I try to access the file directly, I see:
Question
How can I add the configuration that will allow this less file to be downloaded? Am I still able to use web.config files with vNext, or do I need to do something with config.json instead?
Lead 1: Should I use Owin?
Thinking this might be the right path but I'm pretty unfamiliar.
I see a number of tutorials out there, such as K. Scott Allen's, which reference code such as:
public void Configuration(IAppBuilder app)
{
var options = new StaticFileOptions
{
ContentTypeProvider = new FileExtensionContentTypeProvider()
};
((FileExtensionContentTypeProvider)options.ContentTypeProvider).Mappings.Add(
new KeyValuePair<string, string>(".less", "text/css"));
app.UseStaticFiles(options);
}
However, it appears that in its current version, asp.net is looking for a signature of Configure(IApplicationBuilder app) instead.
The IApplicationBuilder class doesn't have a method along the lines of UseStaticFiles -- it only has a signature of IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware).
I have a feeling that this is likely the right path to solve the issue -- I just can't find out how to propertly configure the IAppliationBuilder to map the MIME extension.
Okay, I believe I figured it out.
Step 1: Add the appropriate library for static files
In ASP.NET vNext, this is Microsoft.Aspnet.StaticFiles.
In your project.json file, add the following under "dependencies":
"Microsoft.AspNet.StaticFiles": "1.0.0-beta2"
This adds the static middleware method that you can use later.
Step 2: Configure the app to use Static Files
Add the using statement at the top:
using Microsoft.AspNet.StaticFiles;
At this point, the app.UseStaticFiles method will be available, so your Configure method can look as follows:
public void Configure(IApplicationBuilder app)
{
var options = new StaticFileOptions
{
ContentTypeProvider = new FileExtensionContentTypeProvider()
};
((FileExtensionContentTypeProvider)options.ContentTypeProvider).Mappings.Add(
new KeyValuePair<string, string>(".less", "text/css"));
app.UseStaticFiles(options);
}
And voila! I get text when browsing to .less files, and no more error is appearing from LessJS.
In .NET Core 1.0.1, SeanKileen answer is still good. The following is a simple code rewrite:
public void Configure(IApplicationBuilder app, ...)
var contentTypeProvider = new FileExtensionContentTypeProvider();
contentTypeProvider.Mappings[".map"] = "application/javascript";
contentTypeProvider.Mappings[".less"] = "text/css";
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = contentTypeProvider
});
The above code EXTENDS the default mapping list (see the source), which already has ~370 mappings.
Avoid using the FileExtensionContentTypeProvider constructor overload that takes a dictionary (as suggested by JHo) if you want those 370 default mappings.
SeanKilleen's answer is right on, and still works ASP.NET Core RC1. My only improvement is to write the exact same code using collection initializers to make it cleaner.
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary<string, string>
{
{ ".less", "text/css" },
{ ".babylon", "text/json" },
// ....
})
});

Rendering an email throws a TemplateCompilationException using RazorEngine 3 in a non-MVC project

I am trying to render emails in a windows service host.
I use RazorEngine 3 forked by coxp which has support for Razor 2.
https://github.com/coxp/RazorEngine/tree/release-3.0/src
This works fine for a couple of emailtemplates but there is one causing me problems.
#model string
Click here to enter a new password for your account.
This throws a CompilationException: The name 'WriteAttribute' does not exist in the current context. So passing in a string as model and putting it in the href-attribute causes problems.
I can make it work by changing this line by:
#Raw(string.Format("Klik hier.", #Model))
but this makes the template very unreadable and harder to pass along to a marketing department for further styling.
I like to add that referencing the RazorEngine by using a Nuget package is not a solution since it is based on Razor 1 and somewhere along the process the DLL for system.web.razor gets replaced by version 2 which breaks any code using RazorEngine. It seems more interesting to use Razor 2 to benefit from the new features and to be up to date.
Any suggestions on how to fix this would be great. Sharing your experiences is also very welcome.
UPDATE 1
It seems like calling SetTemplateBaseType might help, but this method does not exist anymore, so I wonder how to be able to bind the templatebasetype?
//Missing method in the new RazorEngine build from coxp.
Razor.SetTemplateBaseType(typeof(HtmlTemplateBase<>));
I use Windsor to inject the template service rather than using the Razor object. Here is a simplified part of the code that shows how to set the base template type.
private static ITemplateService CreateTemplateService()
{
var config = new TemplateServiceConfiguration
{
BaseTemplateType = typeof (HtmlTemplateBase<>),
};
return new TemplateService(config);
}
RazorEngine 3.1.0
Little bit modified example based on coxp answer without the injection:
private static bool _razorInitialized;
private static void InitializeRazor()
{
if (_razorInitialized) return;
_razorInitialized = true;
Razor.SetTemplateService(CreateTemplateService());
}
private static ITemplateService CreateTemplateService()
{
var config = new TemplateServiceConfiguration
{
BaseTemplateType = typeof (HtmlTemplateBase<>),
};
return new TemplateService(config);
}
public static string ParseTemplate(string name, object model)
{
InitializeRazor();
var appFileName = "~/EmailTemplates/" + name + ".cshtml";
var template = File.ReadAllText(HttpContext.Current.Server.MapPath(appFileName));
return RazorEngine.Razor.Parse(template, model);
}