Uglifying javascript code with grunt-contrib-uglify - javascript

I have the following file: package.json
{
"name": "uglify",
"devDependencies": {
"grunt": "^1.0.1",
"grunt-contrib-uglify": "^3.0.0"
}
}
also the following file: Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
uglify: {
options: {
beautify: true,
mangle: {
properties: true
}
},
log_sum_9: {
src: 'log_sum_9.js',
dest: 'log_sum_9.min.js'
}
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('log_sum_9', ['uglify:log_sum_9']);
}
also the following file: log_sum_9.js
(function() {
var
sum = "2+3+4",
calc = function(operation) {
return eval(operation);
}
;
console.log(calc(sum));
})();
Then I do:
to install the required NodeJS modules:
$ npm install
to uglify log_sum_9.js:
$ grunt log_sum_9
then I get the uglified file: log_sum_9.min.js:
!function() {
var sum = "2+3+4", calc = function(operation) {
return eval(operation);
};
console.log(calc("2+3+4"));
}();
Both scripts works properly:
$ node log_sum_9.js
9
$ node log_sum_9.min.js
9
My problem is that the uglified file log_sum_9.min.js didn't change the names of the variables: sum, calc, operation (all these variables are local variables).
If the content of the file log_sum_9.js is introduced on the following online obfuscator: https://www.javascriptobfuscator.com/Javascript-Obfuscator.aspx
then you get the following code:
var _0x257f = ["\x32\x2B\x33\x2B\x34", "\x6C\x6F\x67"];
(function() {
var _0xb897x1 = _0x257f[0],
_0xb897x2 = function(_0xb897x3) {
return eval(_0xb897x3)
};
console[_0x257f[1]](_0xb897x2(_0xb897x1))
})()
where as you can see the previous 3 variables: sum, calc, operation has changed their names.
If you put the above code on the file: log_sum_9.online.js, then you can do:
$ node log_sum_9.online.js
9
(it works properly too)
My question is:
How do I have to configure the file: Gruntfile.js to get the previous 3 variables been obfuscated?

grunt-contrib-uglify, (as far as I'm aware), doesn't offer the same level of obfuscation as the online tool you linked to in your post - whereby it appears to encode Strings using JavaScript Hexadecimal Escape codes/sequences.
However, grunt-contrib-uglify utlilizes uglify-js which provides options for mangling names. You can set the mangle values for both the toplevel and eval properties to true.
Gruntfile.js
The options in your uglify Task can be set as follows:
// ...
options: {
beautify: true,
mangle: {
properties: true,
toplevel: true, // <-- Add this
eval: true // <-- Add this
}
},
// ...
Note: When mangling names you need to be diligent to ensure your code still function as intended. There may be certain names that you don't want to be mangled (e.g. jQuery is quite a common one). An excerpt from the uglify-js documentation reads:
When mangling is enabled but you want to prevent certain names from being mangled, you can declare those names with --mangle reserved — pass a comma-separated list of names...
To exclude certain names from being mangled in your grunt uglify Task you can provide an Array of names using the reserved property:
For example
The following configuration mangles all names excluding operation and jQuery:
// ...
options: {
beautify: true,
mangle: {
properties: true,
toplevel: true,
eval: true,
reserved: ['operation', 'jQuery'] // Exclude mangling specific names.
}
},
// ...

Related

Gulp doesnt watch for any SCSS changes. Do I have to use gulp-ruby-sass? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have gulp file set up to watch for changes. I'm developing an application in ReactJS using Redux architecture. What I've noticed is that the gulp does not watch for any changes in the SCSS files.
/*eslint-disable */
var path = require('path');
var runSequence = require('run-sequence');
var install = require('gulp-install');
var spawn = require('child_process').spawn;
var $ = require('gulp-load-plugins')({
pattern: [
'gulp',
'gulp-*',
'gulp.*',
'merge-stream',
'del',
'browserify',
'watchify',
'vinyl-source-stream',
'vinyl-transform',
'vinyl-buffer',
'glob',
'lodash',
'less-plugin-*',
'mochify'
],
replaceString: /^gulp(-|\.)/,
rename: {
'merge-stream': 'mergeStream',
'del': 'delete'
}
});
var env = require('env-manager')({
argv: process.argv,
dir: path.join(__dirname, 'environments'),
base: 'base.js',
pattern: '{env}.js',
defaults: {
'env': 'development'
}
});
$.util.log($.util.colors.magenta('Running in ' + env.name + ' environment'));
require('gulp-tasks-registrator')({
gulp: $.gulp,
dir: path.join(__dirname, 'tasks'),
args: [$, env],
verbose: true,
panic: true,
group: true
});
$.gulp.task('clean', ['clean:server', 'clean:client'], function task(done) {
done();
});
$.gulp.task('install', function () {
return $.gulp.src([ './package.json']).pipe(install());
});
$.gulp.task('build', function task(done) {
return runSequence(
//'lint',
// 'install',
'clean',
'build:server',
'build:client:images',
'build:client:fonts',
[
'build:client:scripts',
'build:client:styles'
],
'build:client:html',
done
);
});
$.gulp.task('run-wrapper', function(done) {
var server = spawn('node', ['serviceWrapper.js'], {stdio: ['inherit']});
server.stderr.on('data', function(data){
process.stderr.write(data);
});
server.stdout.on('data', function(data) {
process.stdout.write(data);
});
server.unref();
});
$.gulp.task('default', function task(done) {
runSequence('build', ['serve', 'run-wrapper','watch'], done);
});
$.gulp.task('run', function task(done) {
runSequence('serve', done);
});
/*eslint-enable */
In what you've provided, there's no watch task or Sass task (though you do call a task named watch so if running gulp (the default task) isn't giving you an error you must have defined the task named watch somewhere).
There are two Sass plugins for gulp, one using Ruby Sass (gulp-ruby-sass) and one using LibSass (gulp-sass). You can read about the difference here, but in short gulp-sass will probably be faste. The best way to find out is to try one and then the other and compare gulp's console logs (where it says "finished task after x ms").
Here's a SASS-watching example, edited very slightly from the example in the gulp-sass readme (assumes that gulp-sass is in your package.json, in which case it will have been imported by your gulp-load-plugins call). $.s added to match the code you provided
$.gulp.task('sass', function () {
return gulp.src('yourstylespath/*.scss') // grab the .scss files
.pipe(sass().on('error', sass.logError)) // compile them into css, loggin any errors
.pipe(gulp.dest('yourcompiledcsspath')); // save them in yourcompiledcsspath
});
$.gulp.task('sass:watch', function () {
gulp.watch('yourstylespath/*.scss', ['sass']); // "run the task 'sass' when there's a change to any .scss file in yourstylespath
});
Side notes:
Considering all the packages you're using that don't follow the "gulp-packagename" naming scheme, it might be more efficient to just write them out individually like this (of course depends on how many packages you're using)
var delete = require('del'),
mergeStream = require('merge-stream'),
...;
Looks like your run task could just be this? $.gulp.task('run', ['serve']);

grunt-frontend cannot assign to read only property 'spidermonkey'

I have a problem with grunt-frontend package.
When I run grunt task I get:
Running "frontend-js:main" (frontend-js) task
Processing /assets/js/main.min.js
Warning: Cannot assign to read only property 'spidermonkey' of /assets/js/main.min.js Used --force, continuing.
What is going wrong?
I have Gruntfile.js configured like in the documentation:
'frontend-js': {
main: {
options: {
minify: true,
uglify: {}
},
files: {
'out/js/f.js': [
'test/js/file1.js',
'test/js/file2.js'
]
}
}
}
When I set minify: false everything works normally, except minification of course.

gulp-jshint package: How to send parameters (without .jshintrc file)?

I'm currently trying to migrate a grunt project to a gulp project. Actually, in the gruntfile I have (for the jshint task) something like this:
jshint: {
options: {
trailing:true,
evil:false,
indent:4,
undef:true,
unused:true,
node:false,
browser:false,
loopfunc:true,
devel:false
},
default: {
options: {
browser:true,
globals: {
define:true
}
},
src: [basePath + "js/**/*.js"]
}
}
So, when I write "grunt jshint" in the terminal it seems to work fine. However, in the gulpfile I wrote this:
gulp.task("jshint", function() {
return gulp.src( basePath + "js/**/*.js" )
.pipe( jshint( { "trailing": true,..., "globals": true } ) )
.pipe( jshint.reporter("default") );
});
But when I write "gulp jshint" in terminal, it crashes.
My question is: Is there a way to send jshint parameters without .jshintrc file with the gulp-jshint node package? (I've already read the documentation in the npm site, but I dont undestand the "lookup" option)
globals is an array, not true false, here is my example. lookup works just like you were thinking.
gulp.src(files.backend)
.pipe(jshint({ "lookup": false, /* other options */ "globals": ['$']}))
.pipe(jshint.reporter(stylish))
.on('error', gutil.log);

Grunt - output 2 versions of web app

I'm learning Grunt and trying to sort out how I can create 2 versions of the same application. The difference between the two are configuration settings.
Ideally, I would like the process to output 2 versions. One with a boolean in one of the .js files set to false, the other left to true. I would also need to concat and minify then file.
Is there a recommended way to do this? Thanks in advance
You can specify 2 configurations in your grunt.initConfig
grunt.initConfig({
myTask: {
version1: { ... }
version2: { ... }
}
})
And then register your default task to run each of these versions
grunt.task.registerTask("default", ["myTask:version1", "myTask:version2"])
Or just some other task name, myTaskAllVersions instead of default
You could use this versioning to flip your .js boolean, per version 1 or 2.
A similar approach could be taken to minifying and concatting the files afterwards, i.e.
grunt.initConfig({
minify: {
version1: { ... }
version2: { ... }
}
})
and
grunt.task.registerTask("default", ["myTask:version1", "minify:version1"])
You could do all of this with the uglifyjs grunt task.
Here's an example of the config for your Gruntfile:
grunt.initConfig({
uglify: {
app1: {
files: {
'dist/app1.min.js': [
'src/app1.js',
'src/common.js'
]
}
},
app2: {
files: {
'dist/app2.min.js': [
'src/app2.js',
'src/common.js'
]
}
}
}
});

Use Global Variable to Set Build Output Path in Grunt

I have a couple grunt tasks and I am trying to share global variables across those tasks and I am running into issues.
I have written a some custom tasks which set the proper output path depending on the build type. This seems to be setting things correctly.
// Set Mode (local or build)
grunt.registerTask("setBuildType", "Set the build type. Either build or local", function (val) {
// grunt.log.writeln(val + " :setBuildType val");
global.buildType = val;
});
// SetOutput location
grunt.registerTask("setOutput", "Set the output folder for the build.", function () {
if (global.buildType === "tfs") {
global.outputPath = MACHINE_PATH;
}
if (global.buildType === "local") {
global.outputPath = LOCAL_PATH;
}
if (global.buildType === "release") {
global.outputPath = RELEASE_PATH;
}
if (grunt.option("target")) {
global.outputPath = grunt.option("target");
}
grunt.log.writeln("Output folder: " + global.outputPath);
});
grunt.registerTask("globalReadout", function () {
grunt.log.writeln(global.outputPath);
});
So, I'm trying to then reference global.outputPath in a subsequent task, and running into errors.
If I call grunt test from the command line, it outputs the correct path no problem.
However, if I have a task like this:
clean: {
release: {
src: global.outputPath
}
}
It throws the following error:
Warning: Cannot call method 'indexOf' of undefined Use --force to continue.
Also, my constants in the setOutput task are set at the top of my Gruntfile.js
Any thoughts? Am I doing something wrong here?
So, I was on the right path. The issue is that the module exports before those global variables get set, so they are all undefined in subsequent tasks defined within the initConfig() task.
The solution I came up with, although, there may be better, is to overwrite a grunt.option value.
I have an optional option for my task --target
working solution looks like this:
grunt.registerTask("setOutput", "Set the output folder for the build.", function () {
if (global.buildType === "tfs") {
global.outputPath = MACHINE_PATH;
}
if (global.buildType === "local") {
global.outputPath = LOCAL_PATH;
}
if (global.buildType === "release") {
global.outputPath = RELEASE_PATH;
}
if (grunt.option("target")) {
global.outputPath = grunt.option("target");
}
grunt.option("target", global.outputPath);
grunt.log.writeln("Output path: " + grunt.option("target"));
});
And the task defined in initConfig() looked like this:
clean: {
build: {
src: ["<%= grunt.option(\"target\") %>"]
}
}
Feel free to chime in if you have a better solution. Otherwise, perhaps this may help someone else.
I have a way to do this that allows you to specify the output path using values like --dev. So far it's working very well, I quite like it. Thought I'd share it, as someone else may like it, too.
# Enum for target switching behavior
TARGETS =
dev: 'dev'
dist: 'dist'
# Configurable paths and globs
buildConfig =
dist: "dist"
dev: '.devServer'
timestamp: grunt.template.today('mm-dd_HHMM')
grunt.initConfig
cfg: buildConfig
cssmin:
crunch:
options: report: 'min'
files: "<%= grunt.option('target') %>/all-min.css": "/**/*.css"
# Set the output path for built files.
# Most tasks will key off this so it is a prerequisite
setPath = ->
if grunt.option 'dev'
grunt.option 'target', buildConfig.dev
else if grunt.option 'dist'
grunt.option 'target', "#{buildConfig.dist}/#{buildConfig.timestamp}"
else # Default path
grunt.option 'target', buildConfig.dev
grunt.log.writeln "Output path set to: `#{grunt.option 'target'}`"
grunt.log.writeln "Possible targets:"
grunt.log.writeln target for target of TARGETS
setPath()
With this setup, you can run commands like:
grunt cssmin --dist #sent to dist target
grunt cssmin --dev #sent to dev target
grunt cssmin --dev #sent to default target (dev)
This is an older question, I just thought to throw in my 5 cents.
If you need config variable to be accessible from any task, just define it in your main (the one that you'll always load) config file like this:
module.exports = function(grunt)
{
//
// Common project configuration
//
var config =
{
pkg: grunt.file.readJSON('package.json'),
options: // for 'project'
{
dist:
{
outputPath: '<%= process.cwd() %>/lib',
},
dev:
{
outputPath: '<%= process.cwd() %>/build',
},
},
}
grunt.config.merge( config )
}
Then you can simply access value like this:
in config file(s)
...
my_thingie:
[
ends_up_here: '<%= options.dev.outputPath %>/bundle',
],
...
in tasks
// as raw value
grunt.config.data.options.dist.outputPath
// after (eventual) templates have been processed
grunt.config('options.dist.outputPath')
I used key options here just to be in line with convention, but you can use anything as long as you remember not to register a task named 'options' or whatever you used for the key :)

Categories

Resources