I have two different paths where I want to compile the mobile vs desktop code. I would like to alternate by passing a grunt parameter in the command line.
/**
* #module Build
* #class Build.Config
* #static
*/
module.exports = function(grunt) {
var config = {};
var NewPath;
var env = grunt.option('target') || "Mobile";
if (env == "Desktop") { // MAKE THIS DYNAMIC WITH COMMAND LINE ARGUMENT
newPath = "source/desktop/";
}
else {
newPath = "source/mobile/";
}
config.root = newPath;
config.stylesheets = config.root + '/stylesheets';
config.javascripts = config.root + '/javascripts';
config.images = config.root + '/images';
config.jsbin = config.javascripts + '/generated';
config.cssbin = config.stylesheets + '/generated';
config.docsbin = 'docs';
// Project configuration.
grunt.initConfig({
'beautifier': {
'options': {
'indentSize': 1,
'indentChar': '\t',
'spaceAfterAnonFunction': true
}
},
'beautify': {
'files': [ config.javascripts + '/app/**/*.js' ]
},
'requirejs': require('./build/config/requirejs.js')(config),
'watch': require('./build/config/watch.js')(config),
'stylus':require('./build/config/stylus.js')(config)
});
// Default task.
grunt.registerTask('default', ['stylus:compile','requirejs']);
grunt.registerTask('dev', ['stylus:dev']);
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.loadNpmTasks('grunt-contrib-stylus');
};
Turns out I was doing it right I just needed to pass in the variable for env correctly:
$ grunt --target="Desktop"
An alternate to --option is to pass it through the colon. for example passing it to jshint
grunt jshint:desktop
Then configure grunt to pick up that command line argument using process.argv and you can use it to configure your paths or whatever else might be needed:
module.exports = function(grunt) {
"use strict";
//dynamic config after the ':'. 'desktop' here
var env = process.argv[2].split(':')[1];
var config = {
pkg: grunt.file.readJSON('package.json'),
jshint: {
options: {
jshintrc: '.jshintrc',
"force": true
}
},
};
//...
config.jshint[env] = { // ex: $ grunt jshint:desktop
src: ['public/'+env+'/js/main.js']
};
//...
// Project configuration.
grunt.initConfig(config);
//...
};
One caveat on using process is that it won't work when you use a grunt task that respawns your process like the useful grunt-concurrent. In that case it's bettter to go with grunt.option as shown by #im_benton. passing grunt mytask --myvar=myval and picking it up in you Gruntfile.js as grunt.option('myvar') `
Related
I am trying to minify an angularjs application using grunt and terser. I first used uglifiy-es but then read that it has some issues. So I tried terser. But the output does not give me minified files.
The gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
//grunt task configuration will go here
ngAnnotate: {
options: {
singleQuotes: true
},
app: {
files: {
'./public/min-safe/js/_config_min.js': ['./controllers/_config.js'],
'./public/min-safe/js/ctrl_accountingdashboard.js': ['./controllers/ctrl_accountingdashboard.js'],
}
}
},
concat: {
js: { //target
src: ['./public/min/app.js', './public/min-safe/js/*.js'],
dest: './public/min/app.js'
}
},
terser: {
options: {},
files: {
'./public/min/app.js': ['./public/min/app.js'],
},
}
});
//load grunt tasks
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-terser');
grunt.loadNpmTasks('grunt-ng-annotate');
//register grunt default task
grunt.registerTask('default', ['ngAnnotate', 'concat', 'terser']);
}
I had the same problem. According to the documentation, this should work but it didn't for me. Wrapping the "files" setting in a custom target works for me:
terser: {
options: {},
main: {
files: {
'./public/min/app.js': ['./public/min/app.js'],
}
}
}
To add to #Tim's great answer:
Here is an example that allows to run grunt-terser with path / file wildcard patterns (globbing) – which it does not support out of the box.
Please note the helper properties _src and _dest in the terser config which are not read by grunt-terser itself but by the task terser_all. This task expands the globbing pattern(s) in _src and builds the real config in the files property. When done it runs terser with that updated config.
module.exports = function (grunt) {
grunt.initConfig({
terser: {
dist: {
options: {
compress: {
drop_console: true // remove console.log, console.info, ...
}
},
files: {
// FILLED through terser_all task below!
// Examples config:
// "dist/example.js": [ "path/to/files/example.js" ]
// "dist/example_joined.js": [ "path/to/files/*.js" ]
},
// -----
// HELPER PROPERTIES to build the files prop (see above) in the terser_all task below.
_src: [
"path/to/files/*.js"
],
_dest: "dist/"
}
}
});
grunt.registerTask('terser_all', function () {
// work on this target in terser config
var terser_target_name = "dist";
// read the terser config
var terser_config = grunt.config.get('terser') || {};
var terser_target_config = terser_config[terser_target_name] || {};
// get the destination dir
var destDir = terser_target_config._dest;
// loop through all source files and create an entry in the terser config for each of it
var files = grunt.file.expand(terser_target_config._src);
for (const [i, file] of files.entries()) {
grunt.log.writeln(file);
// add this file to the terser config as: dest_file: src_file
terser_target_config.files[destDir + file] = file;
}
// show new config on CLI
grunt.log.writeflags(terser_target_config);
// write back config and run task
grunt.config.set('terser', terser_config);
grunt.task.run('terser');
});
grunt.loadNpmTasks('grunt-terser');
grunt.registerTask('build', ['terser_all']);
grunt.registerTask('default', ['build']);
};
Just a note:
If you try to "disable" some options by renaming this disables the whole process. At least this was my result with grunt-terser. I was left with the original js file.
{
mangleX: {
reserved: [/* ... */]
}
}
The goal is, transpiling ES6 scripts into ES5 and make them browser readable.
This works most with my node.js gulp task, but some of the script use "import" like
import EstaticoModule from '../../assets/js/helpers/module';
I would like to skip this "import" and more over delete this row from result.
Is there a param in "gulp-babel" to achieve this or has one another idea to make this in a better way?
Here is my gulp task:
'use strict';
/**
* #function `gulp js:lint1`
* #desc Lint JavaScript files (using `ESLint`).
*/
var gulp = require('gulp'),
helpers = require('require-dir')('../../helpers'),
webpack = require('webpack'),
babel = require("gulp-babel");
//babel = require("babelify");
//babel = require("babel-core");
//require("babel-core");
var taskName = 'js:lint1',
taskConfig = {
src: [
'source/assets/js/**/*.js',
'source/modules/**/*.js',
'source/pages/**/*.js',
'source/demo/modules/**/*.js',
'source/demo/pages/**/*.js',
'!source/modules/**/*.data.js',
'!source/pages/**/*.data.js',
'!source/demo/modules/**/*.data.js',
'!source/demo/pages/**/*.data.js',
'!source/modules/.scaffold/scaffold.js',
'!source/assets/js/libs/**/*.js',
'!source/assets/js/libs/wtscript.js'
],
watch: [
'./source/assets/js/**/*.js',
'./source/modules/**/*.js',
'./source/pages/**/*.js',
'./source/demo/modules/**/*.js',
'./source/demo/pages/**/*.js',
'!./source/modules/.scaffold/scaffold.js'
],
dest: './RSE/',
srcBase: './source/assets/js/'
}
gulp.task( taskName, function() {
var helpers = require('require-dir')('../../helpers'),
tap = require('gulp-tap'),
path = require('path'),
cached = require('gulp-cached'),
eslint = require('gulp-eslint');
return gulp.src(taskConfig.src, {
dot: true
})
.pipe(cached('linting'))
.pipe(eslint())
.pipe(eslint.formatEach())
.pipe(tap(function(file) {
if (file.eslint && file.eslint.errorCount > 0) {
helpers.errors({
task: taskName,
message: 'Linting error in file "' + path.relative('./source/', file.path) + '" (details above)'
});
}else{
console.log(file);
}
}))
.pipe(babel({
presets: [
'es2015',
'react'
],
plugins: [
// Work around some issues in IE
'transform-class-properties',
'transform-proto-to-assign',
['transform-es2015-classes', {
loose: true
}]
]
}))
.pipe(gulp.dest(taskConfig.dest))
;
});
module.exports = {
taskName: taskName,
taskConfig: taskConfig
};
I have found a way:
// EXCLUDE IMPORTS FROM STREAM
var content = file.contents.toString();
content = content.replace(/import/g, "//$&");
// RETURN STREAM INTO PIPE
file.contents = Buffer.from(content);
This will result in
//import EstaticoModule from '../../assets/js/helpers/module';
Here is the code in summary:
'use strict';
/**
* #function `gulp js:create:js:files`
* #desc Lint JavaScript files (using `ESLint`), EXCLUDE IMPORTS FROM STREAM and create separate js files in modules/%module% folder.
*/
var gulp = require('gulp'),
helpers = require('require-dir')('../../helpers'),
webpack = require('webpack'),
babel = require("gulp-babel");
var taskName = 'js:create:js:files',
taskConfig = {
src: [
'source/assets/js/**/*.js',
'source/modules/**/*.js',
'source/pages/**/*.js',
'source/demo/modules/**/*.js',
'source/demo/pages/**/*.js',
'!source/modules/**/*.data.js',
'!source/pages/**/*.data.js',
'!source/demo/modules/**/*.data.js',
'!source/demo/pages/**/*.data.js',
'!source/modules/.scaffold/scaffold.js',
'!source/assets/js/libs/**/*.js',
'!source/assets/js/libs/wtscript.js'
],
watch: [
'./source/assets/js/**/*.js',
'./source/modules/**/*.js',
'./source/pages/**/*.js',
'./source/demo/modules/**/*.js',
'./source/demo/pages/**/*.js',
'!./source/modules/.scaffold/scaffold.js'
],
dest: './build/',
srcBase: './source/assets/js/'
}
gulp.task( taskName, function() {
var helpers = require('require-dir')('../../helpers'),
tap = require('gulp-tap'),
path = require('path'),
cached = require('gulp-cached'),
eslint = require('gulp-eslint');
return gulp.src(taskConfig.src, {
dot: true
})
.pipe(cached('linting'))
.pipe(eslint())
.pipe(eslint.formatEach())
.pipe(tap(function(file) {
if (file.eslint && file.eslint.errorCount > 0) {
helpers.errors({
task: taskName,
message: 'Linting error in file "' + path.relative('./source/', file.path) + '" (details above)'
});
}else{
// EXCLUDE IMPORTS FROM STREAM
var content = file.contents.toString();
content = content.replace(/import/g, "//$&");
// RETURN STREAM INTO PIPE
file.contents = Buffer.from(content);
}
}))
.pipe(babel({
presets: [
'es2015'
,'react'
],
plugins: [
// Work around some issues in IE
'transform-class-properties',
'transform-proto-to-assign',
['transform-es2015-classes', {
loose: true
}]
]
}))
.pipe(gulp.dest(taskConfig.dest))
;
});
module.exports = {
taskName: taskName,
taskConfig: taskConfig
};
I would appreciate some help fixing my file paths/setup/whatever I am doing wrong.
First off; this is my first time setting up Gulp, and I am NOT a pro.
I am setting up Gulp in an existing app, using wiredep and gulp-inject to read the file paths of my bower_components and custom .js files, and injecting these paths into my index.html.
The issue I am getting is; when running the app in the browser, none of the paths - except for the bower paths - are working, resulting in a whole lot of 404 errors: Not Found.
The path to read the file names is (example) './src/vendorScripts/', and this adds the file to the index.html as <script src="/src/vendorScripts/ChartFactory.js"></script>, whereas the path is supposed to be <script src="vedorScripts/ChartFactory.js"></script>.
This is my gulp.config.js file:
module.exports = function () {
var source = './src/';
var sourceScripts = './src/scripts/';
var sourceScriptsPlugins = './src/scripts/plugins/';
var vendorcripts = './src/vendorScripts/';
var vendorcriptsUsedInApp = './src/vendorScripts/usedInApp/';
var sourceScriptsSocialMedia = './src/socialMedia.module/';
var sourceScriptsCookiesModule = './src/cookies.module/';
var config = {
temp: './.temp/',
/**
* File paths
*/
// all js to vet
alljs: [
'./src/**/*.js',
'./*.js'
],
source: source,
index: source + 'index.html',
js: [
sourceScripts + '**/app.js',
sourceScriptsPlugins + '**/*.js',
vendorcriptsUsedInApp + '**/*.js',
sourceScripts + '**/*Controller.js',
sourceScriptsSocialMedia + '**/*.js',
sourceScriptsCookiesModule + '**/*.js',
sourceScripts + '**/*Directive.js',
sourceScripts + '**/*Filter.js',
sourceScripts + '**/*Service.js',
sourceScripts + '**/*Factory.js',
sourceScripts + '**/*Constant.js'
],
less: source + './src/styles/main.less',
/**
* Bower and NPM locations
*/
bower: {
json: require('./bower.json'),
directory: './bower_components/',
ignorePath: '../..'
}
};
config.getWiredepDefaultOptions = function (){
var options = {
bowerJson: config.bower.json,
directory: config.bower.directory,
ignorePath: config.bower.ignorePath
};
return options;
};
return config;
};
This is my gulpfile.js:
var gulp = require('gulp');
var args = require('yargs').argv;
var config = require('./gulp.config')();
var del = require('del');
var inject = require('gulp-inject');
var wiredep = require('wiredep').stream;
var $ = require('gulp-load-plugins')({ lazy: true });
gulp.task('vet', function () {
log('Analysing source with JSHint and JSCS');
return gulp
.src(config.alljs)
.pipe($.if(args.verbose, $.print()))
.pipe($.jscs())
.pipe($.jshint())
.pipe($.jshint.reporter('jshint-stylish', { verbose: true }))
.pipe($.jshint.reporter('fail'));
});
gulp.task('styles', ['clean-styles'], function () {
log('Compiling Less --> CSS');
return gulp
.src(config.less)
.pipe($.plumber())
.pipe($.less())
.pipe($.autoprefixer({ browsers: ['last 2 versions', '> 5%'] }))
.pipe(gulp.dest(config.temp));
});
gulp.task('clean-styles', function(){
var files = config.temp + '**/*.css';
return clean(files);
});
gulp.task('less-watcher', function(){
gulp.watch([config.less], ['styles']);
});
gulp.task('wiredep', function () {
// log('Wire up the bower css js and our app js into the html');
var options = config.getWiredepDefaultOptions();
return gulp
.src(config.index)
.pipe(wiredep(options))
.pipe($.inject(gulp.src(config.js)))
.pipe(gulp.dest(config.source))
.pipe($.jshint.reporter('jshint-stylish', { verbose: true }))
.pipe($.jshint.reporter('fail'));
});
//////////////
function clean(path){
log('Cleaning: ' + $.util.colors.blue(path));
return del(path); // returns a promise
}
function log(msg) {
if (typeof (msg) === 'object') {
for (var item in msg) {
if (msg.hasOwnProperty(item)) {
$.util.log($.util.colors.blue(msg[item]));
}
}
} else {
$.util.log($.util.colors.blue(msg));
}
}
This image shows my directory listing:
I would appreciate your advice!
I managed to resolve my issue making use of the following solution:
NOTE: gulp-inject takes various options that one can use to define the destination and other settings. You can read more on this on the official npm gulp-inject page: gulp-inject.
The options object below sorts out my issues with the relative path and root slash. I added this to my gulpfile.js:
var injectOptions = {
addRootSlash: false,
ignorePath: 'src/'
};
And then add the injectOptions to my gulp.task('wiredep'):
gulp.task('wiredep', function () {
var options = config.getWiredepDefaultOptions();
return gulp
.src(config.index)
.pipe(wiredep(options))
.pipe($.inject(gulp.src(config.js), injectOptions))
.pipe(gulp.dest(config.source))
.pipe($.jshint.reporter('jshint-stylish', { verbose: true }))
.pipe($.jshint.reporter('fail'));
});
The output is the desired script source:
<script src="vedorScripts/ChartFactory.js"></script>
here is my gruntfile.js
var fs = require("fs"),
browserify = require("browserify"),
pkg = require("./package.json");
module.exports = function(grunt) {
grunt.initConfig({
mochaTest: {
test: {
options: {
style: 'bdd',
reporter: 'spec'
},
src: ['test/unit/*.js']
}
},
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: "/*\n" + grunt.file.read('LICENSE') + "*/"
},
dist: {
files: {
'<%=pkg.name%>-<%=pkg.version%>.min.js': ['<%=pkg.name%>-<%=pkg.version%>.js']
}
}
}
});
grunt.registerTask('build', 'build a browser file', function() {
var done = this.async();
var outfile = './brain-' + pkg.version + '.js';
var bundle = browserify('./browser.js').bundle(function(err, src) {
console.log("> " + outfile);
// prepend license
var license = fs.readFileSync("./LICENSE");
src = "/*\n" + license + "*/" + src;
// write out the browser file
fs.writeFileSync(outfile, src);
done();
});
});
grunt.registerTask('test', 'mochaTest');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-contrib-uglify');
};
When I simply run grunt in the terminal - here is the error
Warning: Task "default" not found. Use --force to continue.
Aborted due to warnings.
After adding --force it shows:
Warning: Task "default" not found. Used --force, continuing.
Done, but with warnings.
First you need to understand how grunt command work
you define/register a task in your Gruntfile.js
Thenyou call that task from the command prompt
From your grunt file below is a task registered
grunt.registerTask('build', 'build a browser file', function() {
var done = this.async();
var outfile = './brain-' + pkg.version + '.js';
var bundle = browserify('./browser.js').bundle(function(err, src) {
console.log("> " + outfile);
// prepend license
var license = fs.readFileSync("./LICENSE");
src = "/*\n" + license + "*/" + src;
// write out the browser file
fs.writeFileSync(outfile, src);
done();
});
});
you can then call that task by calling grunt build which will run that task. And when you only run grunt it looks for a task which name is default
As in your grunt file there is no default task defined you command fails.
There is no task called "default" in your gruntfile. Are you trying to run the build task ?
If so, replace this line:
grunt.registerTask('build', 'build a browser file', function() {
...
With this line
grunt.registerTask('default', 'build a browser file', function() {
...
Tasks have to be registered in grunt before they can be executed.
You have registered a build task in your grunt,
grunt.registerTask('build', 'build a browser file', function() {
var done = this.async();
var outfile = './brain-' + pkg.version + '.js';
var bundle = browserify('./browser.js').bundle(function(err, src) {
console.log("> " + outfile);
// prepend license
var license = fs.readFileSync("./LICENSE");
src = "/*\n" + license + "*/" + src;
// write out the browser file
fs.writeFileSync(outfile, src);
done();
});
});
This can be executed by called grunt build.
When you execute grunt, by default, it looks for a task called default, which should be registered.
So, register a default task (same like build task)
grunt.registerTask('default', 'Executed default task', function() {
...
});
You can also pass the third parameter as array of registered tasks so that that will be executed if you run grunt.
grunt.registerTask('default', 'Executed default task', [
'task1',
'task4',
'task3',
]);
Now when you execute grunt, all these tasks will be executed in sequence.
Please note that the each task in the tasks array should be registered using grunt.registerTask.
You forgot to add default task.
add following line after "grunt.registerTask('test', 'mochaTest');" line.
grunt.registerTask('default', ['test', 'build']);
this task will run both 'test' and 'build'. when run "grunt" without any argument.
For more details refer grunt document on task.
I use this code in grunt config:
const libDir = 'public/lib'
const cssDir = 'public/css'
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: '**/*.js',
tasks: ['default'],
},
},
clean: [libDir],
bower_concat: {
all: {
dest: {
'js': libDir + '/vendor.js',
'css': libDir + '/vendor.css'
},
}
},
sass: {
options: {
sourceMap: true
},
dist: {
files: {
'output.css': 'input.scss'
}
}
}
});
How do I generate output.css dynamically by concatenating cssDir and some string ?
I tried using templating but it ignores cssDir.
Templates are not expanded for all config properties and especially not for config keys.
Since Grunt files are basically Javascript programs, you can construst the object programmatically:
const cssDir = 'public/css';
var sassFilesMap = {};
// build sass output file mapping programmatically
sassFilesMap[cssDir + "/output.scss"] = "input.scss";
// Project configuration.
grunt.initConfig({
// ...
sass: {
options: {
sourceMap: true
},
dist: {
files: sassFilesMap
}
}
});
If there are multiple .scss files to be converted (to be configured) you might with something like this:
const sassMappings = [["edit.scss", "edit.css"], ["public.scss", "public.css"]];
sassMappings.forEach(function(pair) {
// pair[0] is the .scss filename, pair[1] is the .css filename
sassFilesMap[cssDir + "/" + pair[0]] = pair[1];
});
I found out that ES6 supports dynamic property keys so basically this solves the problem as I can now compute both the key and value as dirVar + 'outputFile': inputDir + 'input.file'