Disable uglyfying in r.js - javascript

I am looking for a way to prevent r.js (RequireJS' optimization script) from ugylyfying our JS-modules to maintain readability for debugging purposes.
I expect the script (running on Node.js by the way) to have some command line option to be passed.
Unfortunately, the documentation if this tool is rather poor.

Pass optimize=none on the command line to r.js, or include optimize: "none" in your build script.
eg:
({
baseUrl: ".",
paths: {
jquery: "some/other/jquery"
},
name: "main",
out: "main-built.js",
optimize: "none"
})
See http://requirejs.org/docs/optimization.html for more information.
If you check the source, you will see that the default is set to "uglify". Here are the options which are accepted:
uglify: (default) uses UglifyJS to minify the code.
uglify2: in version 2.1.2+. Uses UglifyJS2.
closure: uses Google's Closure Compiler in simple optimization mode to minify the code. Only available if running the optimizer using Java.
closure.keepLines: Same as closure option, but keeps line returns in the minified files.
none: no minification will be performed.

Related

is it possible to not mangling in .NET minification?

To bundle and minify the files of my application I'm using .NET Bundling and Minification feature (and it's complicated to use any other tool, so I would like to find a solution for this).
As a remark and just in case it could help, I'm trying to minify angular files, files compiled from typescript and regular javascript files.
The problem is that when I execute the application I got some javascript exceptions related mostly to angular. I think it's not useful but maybe it could help, so this is the main exception I get:
Error: [$injector:unpr] Unknown provider: tProvider <- t <- highChartSeriesMappingService
http://errors.angularjs.org/1.5.5/$injector/unpr?p0=tProvider%20%3C-%20t%20%3C-%20highChartSeriesMappingService
[Rest of the exception trace][...]
If I just bundle them and no minify my files, by setting this instruction myScriptBundle.Transforms.Clear(), it works fine. Obviously, this action also avoids the mangling of variables, classes...names.
In order to be sure of what was happening, I used grunt and its plugin grunt-contrib-uglify to bundle and minify. At the beginning I had the same problem as before because of the basic configuration I used for the task:
uglify: {
options: {
preserveComments: false
},
myScript: {
files: {
'myScript.min.js': conf.myScript
}
}
}
Where conf is a reference to a json file with the url of the files to minify. But when I set the mangle property to false (here you have more info about it):
uglify: {
options: {
preserveComments: false,
mangle: false
},
myScript: {
files: {
'myScript.min.js': conf.myScript
}
}
}
It works fine too. It leads me to think that is the mangling of some classes names the root of the problem.
As you can see, I reached a solution using grunt but I would like to find a way to avoid mangling with .NET. Any idea?
After read the post of #AbdelrhmanMohamed and check again my project's files I realized that it was a problem related to angular and its array sytntax; some files lacked the dependencies injection through the array strings, so when those files where minimizied and the functions' names where mangled caused my exception in execution time.
To sum up, .NET bndling and minification process seems to work fine. If you work with angular you just have to be sure that all your classes which depend of other modules have the array string with those dependencies defined.

play framework and requirejs development javascript code

I am using requirejs to build frontend on play 2.2 framework. play provides great development/stage code difference for this case. In devel mode I am working with browser based requirejs and in stage I am using precompiled with r.js version of the project. But one feature fails - is it possible to distinguish on javascript side is it development mode or not and remove part of code during compilation or something like:
#ifdef DEVELOPMENT
code in Development only
#endif
By default r.js uses UglifyJS to optimize your modules. In r.js' configuration you can use the uglify option to send configuration options to UglifyJS. For instance,
uglify: {
defines: {
DEV: ['name', 'false']
}
},
This would tell uglifyjs replace every instance of the symbol DEV with the name false. Then, parts like this:
if (DEV) {
// ....
}
would be automatically removed by uglifyjs as being unreachable.
See uglifyjs' documentation for the details of how that works.
You might also want to look at UglifyJS2, because it perhaps does more than UglifyJS. You can tell r.js to use it by setting the optimize option to uglify2, and use the uglify2 option to control what it does.
UglifyJS2 from sbt-rjs 1.0.7 already has some other usefull option:
uglify: {
drop_console: true
}
uglify2: {
compress: { drop_console: true }
}
it removes all console.log messages from minified script.

TypeScript: How do you test your client-side code?

When I write tests for my in-browser TS code, I hit the following problem. My "test" code files are located in a separate folder from the "application" code files (an arrangement that I am not willing to give up). Therefore, in order to import my "app" modules, I have to do this:
// tests/TS/SubComponent/Module.Test.ts
import m = module("../../Web/Scripts/SubComponent/Module");
This compiles just fine. But when loaded in browser, it will obviously not work, because from the standpoint of RequireJS running in the browser, the module is located at "app/SubComponent/Module" (after being remapped through web server and RequireJS config).
With TS 0.8.3 I was able to pull off this clever trick, but in 0.9.0 it no longer works, because now the compiler doesn't let me treat a module as an interface.
So the question is: how do you test your client-side code?
Clearly, I can't be the only person to be doing it, can I? :-)
I can't tell if you are using Visual Studio - this next bit is Visual Studio specific...
This is how I do it:
In my test project, I created a folder named "ReferencedScripts" and
referenced the scripts from the project being tested (add existing
item > add as link). Set the file to copy to the output folder.
Source: Include JavaScript and TypeScript tests in Visual Studio.
Using add-as-link makes the scripts available in your test project.
Not using Visual Studio? I recommend creating a task / job / batch file to copy the files into the test folder. You could even use tsc to do this task for you.
I am in the middle of a project where I have to migrate parts of a large javascript project to typescript and this is how I managed to keep the tests running:
Use grunt-typescript task to watch and compile all my .ts files from the source to a tmp folder (with their source-maps). If you only have to deal with typescript files, then you can use the tsc in watch mode to do it as well. The latter would be faster, but the former allowed me to simultaneous edit javascript and typescript files with livereload.
Include the .ts files in karma.conf but don't watch them or include them:
// list of files / patterns to load in the browser
files = [
JASMINE,
JASMINE_ADAPTER,
// ...
// We want the *.js to appear in in the window.__karma__.files list
{ pattern: 'app/**/*.ts', included: false, watched: false, served: true },
{ pattern: 'app/**/*.js', included: false },
// We do watch the folder where the typescript files are compiled
{ pattern: 'tmp/**/*.js', included: false },
// ...
// Finally, the test-main file.
'tests/test-main.js'
];
Finally, in the test-main.js file, I mangle the names of typescript files and declare them as require modules with the correct paths (to the corresponding .js file) in test-main.js:
var dynPaths = {
'jquery' : 'lib/jquery.min',
'text' : 'lib/text'
};
var baseUrl = 'base/app/',
compilePathUrl = '../tmp/';
Object.keys(window.__karma__.files)
.forEach(function (file) {
if ((/\.ts$/).test(file)) {
// For a typescript file, include compiled file's path
var fileName = file.match(/(.*)\.ts$/)[1].substr(1),
moduleName = fileName.substr(baseUrl.length);
dynPaths[moduleName] = compilePathUrl +
fileName.substr(baseUrl.length);
}
});
require({
// Karma serves files from '/base'
baseUrl: '/' + baseUrl,
paths: dynPaths,
shim: { /* ... */ },
deps: [ /* tests */ ],
// start test run, once requirejs is done
callback: function () {
window.__karma__.start();
}
});
Then as I edit the typescript files, they are compiled and put in the tmp folder as javascript files. These trigger karma's auto watch and it reruns the tests. In the tests, the require calls resolve correctly since we have explicitly overwritten the paths to the typescript files.
I realise that this is a bit hacky, but I had to jump through similar hoops while trying to include all my tests with REQUIRE_ADAPTER. So I assumed that there is no cleaner way of doing it.
Hopefully, if typescript becomes more prevalent, we will see better support for testing.
So here's ultimately what I've done: it turns out that Karma can handle/watch/serve files that are not within the base directory, and it makes them look to the browser in the form of "/absolute/C:/dir/folder/blah/file.js". This happens whenever files -> pattern starts with "../".
This feature can be used to make RequireJS see the whole directory structure exactly as it exists on the file system, thus allowing the tests to import app modules in the form of "../../Web/App/Module.ts".
files = [
// App files:
{ pattern: '../../Web/App/**/*', watched: true, served: true, included: false },
// Test files:
{ pattern: '../js/test/**/*.js', watched: true, served: true, included: false }
];
Reference (version 0.8): http://karma-runner.github.io/0.8/config/files.html
Since the typescript code is compiled to Javascript you can use all Javascript test frameworks.
I am using Jasmine: https://github.com/pivotal/jasmine/wiki
You can write your tests in Typescript with the .d.ts file here: https://github.com/borisyankov/DefinitelyTyped/blob/master/jasmine/jasmine.d.ts
But my client code is rather small and compiled to one output file, so I don't have the module issues that you describe.
Might be that I misunderstood your question - can't comment yet...
The runtime of the browser does not need any typescript information. So your test script should import the compiled ts files the same way as any other javascript files they need. Might be that you have to copy them to a subfolder of your test-project before you run your script.
I assume the bigger problem is that you have no interface information. Why do you want to import these informations instead of referencing them? Especially since importing them will also occur in the browser.
The Reference will only take place in the IDE , so it does not matter in which folders the interface-files are located.
/// <reference path="../../Web/Scripts/SubComponent/Module/References.ts" />

How to build several modules using RequireJS using one physical configuration file with overrides

I have been battling with this for a while (even used some Ant-based workarounds), even posted a question that went unanswered: older similar/related question.
Require.js allows to build several modules using the same profile/config file. For example:
({
appDir: 'some/path',
baseUrl: 'some/base/path',
dir: 'some/other/path',
optimize: 'none',
paths: {
...
},
modules: [
{
name: 'someModule',
},
{
name: 'someOtherModule'
}]
})
Which works fairly well. Additionally, Require.js provides an option to override any option for the build for a specific module: Require/js example build configuration, like this :
({
appDir: 'some/path',
baseUrl: 'some/base/path',
dir: 'some/other/path',
optimize: 'none',
paths: {
...
},
modules: [
{
name: 'someModule',
},
{
name: 'someModule',
override : {
optimize: 'uglify'
}
}]
})
or so I understood it. The purpose is to use the same build configuration file on the same application, but have it both non-minified and minified. This doesn't work.
EDIT
The error I am getting is (cleaned up, since it is part of a larger Ant build):
Error: ENOENT, no such file or directory 'some/other/path/someModule.js-temp'
Any help, suggestions (on both questions) are greatly appreciated.
The listing of modules: config does not allow duplicates for the name value. I suspect that is the source of the problem. It is an array just to allow proper sequencing of build layers that may be excluded in other build layers -- using an object hash would not work since key iteration on an object does not guarantee order.
If you want to do a build that has the layer in non-minified and minified format, I suggest driving the build via a node script, then manually requiring uglify and doing a copy of the built file and minification of that copy after the build.
Here is an example of a node script that drives the build:
https://github.com/jrburke/r.js/blob/master/build/tests/tools/override/override.js
That one is replacing the version of uglify used, but you could use it and do the file copy/manual minification in the callback function passed to requirejs.optimize().

Optimize/build modules under parallel directories using the same config file in RequireJS

I have a feeling that the title just might not be explanatory :)
Setup
Suppose that I have the following structure:
where app.js files are main bootstrapping/entry modules for the applications that look like this:
app01
require.config({});
require([
'app/component1.js'
],
function(component){
// do something with component1
});
app02
require.config({});
require([
'app/component2.js'
],
function(component){
// do something with component2
});
which both work with appropriate index.html files.
I have a RequireJS build configuration file (assume correct placement related to the paths) for app01:
({
appDir: 'apps/app01',
baseUrl: '.',
dir: 'built_apps/app01',
optimize: 'closure',
paths: {
},
modules: [
{
name: 'app'
}
]
})
which works just fine. Similar file (replacing app01 with app02) works just fine for app02.
Problem/target
Now I want to be able to run RequireJS build tool (using Google Closure with Rhino under Ant, not that it really matters in this case) for both app01 and app02 applications using the same build configuration file and, preferably, without actually listing all the apps by name (since the number and names may vary over time).
Basically I expect (or rather hope) to have something like this:
({
appDir: 'apps',
baseUrl: '.',
dir: 'built_apps',
optimize: 'closure',
paths: {
},
modules: [
{
name: 'app*/app' // notice the wildcard
}
]
})
which would run over built_apps directory, find all apps under app*/app and optimize each one of them.
I know I can use Ant to create such build configuration file on the fly per app, run build against it and then clean up, but I'd rather have RequireJS solution.
Is there a way to do something like this with RequireJS?
There's no built-in wildcarding configuration for RequireJS. One way or another, you'll need code to do this. I'll observe that what you're asking for here amounts to translating a wildcard into some kind of implicit iteration on the module objects, akin to what mustache.js provides for its templates. IMO, that's a fairly brittle and limited approach in this context.
Instead, I recommend generating your modules array programmatically in JavaScript right in the build config. Recall, the build config is JavaScript not just a JSON data structure. This gives you sophisticated scripting capabilities there.
I've done this kind of scripting in the build config for the requirejs-rails gem. Here's an example gist that shows what r.js would see at build time.

Categories

Resources