When using the following Grunt Configuration, I get 404 errors.
module.exports = function(grunt) {
var taskConfig = {
app: 'app',
dist: 'app'
};
grunt.initConfig({
taskConfig: taskConfig,
connect: {
serveMyApp: {
options: {
keepalive: true,
debug: true,
port: '3001',
hostname: '0.0.0.0',
livereload: true,
base: '<%= taskConfig.dist %>/',
middleware: function(connect, options, middlewares) {
// 1. mod-rewrite behavior
var rules = [
'!\\.html|\\.js|\\.css|\\.ico|\\.svg|\\.jp(e?)g|\\.png|\\.woff|\\.gif$ /index.html'
];
middlewares.unshift(rewrite(rules));
return middlewares;
}
}
}
}
);
If I would set base to a string value as follows, connect works as expected:
base: 'app/',
I was expecting the template string evaluation to generate the same string value for base, but I guess it doesn't.
What I am doing wrong?
the <%= ... %> syntax is for templating.
within your Gruntfile.js just call the variable like you would do it within any other js-file
...
base: taskConfig.dist,
...
Here is my problem.
All mentioned paths as per below gruntfile.js are watched fine (shown in grunt --verbose -v). Livereload fires whenever I change files (at least --verbose shows livereload fires). But the page is live reloaded ONLY in case I change my /development/index.html (in Sublime Text) or /less/mainpage.less (with contrib-less).
If I change development/img//* or anyting in /test//*, livereload FIRES but do not RELOAD my page.
I would really appreciate if someone could help.
Here is my folder structure:
source location root: /development/
destination location root: /test/
Here is my gruntfile.js:
module.exports = function(grunt) {
grunt.initConfig({
watch: {
livereload: {
files: ['development/*.html', "test/**/*", "development/img/**/*"],
options: {
livereload: true,
spawn: false
}
},
// watch tasks start here
scripts: {
files: ['development/js/**/*.js'],
tasks: ['concat']
},
html: {
files: ['development/*.html'],
tasks: ['copy:html']
},
less_compile: {
files: ['development/a_source/less/**/*.less'],
tasks: ['less', "stripCssComments"]
},
images: {
files: ['development/img/**/*'],
tasks: ['tinyimg']
}
},
// runs local server for livereload
connect: {
sever: {
options: {
hostname: 'localhost',
port: 3000,
base: 'test/',
livereload: true
}
}
},
// *** *.html, *.img copy task here
copy: {
html: {
expand: true,
cwd: 'development',
src: '*.html',
dest: 'test/',
}
},
// *** LESS tasks here
less: {
compile: {
options: {
paths: ["development/b_components/less/"]
},
files: {
"temp/css/style.css": "development/a_source/less/style.less"
}
}
}, // compiles less and put compiled version into /temp/css/style.test
stripCssComments: {
dist: {
files: {
'test/css/style.css': 'temp/css/style.css'
}
}
}, // strips comments from /temp/css/style.css and copies it to /test/
// minify images
tinyimg: {
dynamic: {
files: [{
expand: true, // Enable dynamic expansion
cwd: 'development/img/', // Src matches are relative to this path
src: ['**/*.{png,jpg,gif}'], // Actual patterns to match
dest: 'test/img/' // Destination path prefix
}]
}
}
}); //initConfig
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-strip-css-comments');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-tinyimg');
grunt.registerTask('default', ["connect", "watch"]);
}; //wrapper function
Try this
livereload:{
options:{
livereload:'<%= connect.options.livereload %>'
},
files:[
'app/{,*/}*.html',
'app/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
This should reload if you make changes in your images folder. (Customize the URL according to your structure.)
OK. I just wanted to wrap up after I solved all my problems.
I arrived at the following acceptably working setup:
- as per above: Grunt serves as only "files" worker doing all compile / concat / copy etc.
work.
- browser-sync is my local server (with bunch of other vital capabilities) and fast livereload tool, that additionally syncs
several open test windows (https://browsersync.io/).
- Divvy: great addition to my workflow capable of arranging windows on the desktop on the fly (http://mizage.com/divvy/).
Update:
Soon after I switched to Gulp + Browsersync. I could not be satisfied more. Gulp works roughly 10 times faster and Browsersync is smooth and convenient.
Here is my gulpfile.js example just to demonstrate the tasks this pair manages for me:
var gulp = require("gulp"),
gutil = require("gulp-util"),
less = require('gulp-less'),
concat = require('gulp-concat'),
browserify = require('gulp-browserify'),
browserSync = require('browser-sync').create(),
gulpcopy = require('gulp-copy'),
newer = require('gulp-newer'),
imagemin = require('gulp-imagemin'),
autoprefixer = require('gulp-autoprefixer'),
uglifyjs = require('gulp-uglify'),
cleanCSS = require('gulp-clean-css'),
uglifycss = require('gulp-uglifycss'),
htmlmin = require('gulp-htmlmin'),
htmlhint = require("gulp-htmlhint"),
htmlv = require('gulp-html-validator'),
validatecss = require('gulp-w3c-css'),
sourcemaps = require('gulp-sourcemaps');
var lessMain = ["src/styles/less/styles.less"],
lessSources = ["src/styles/less/*.less", "src/styles/**/*.css"],
jsSources = "src/js/*.js",
jsonSources = ["src/js/*.json"],
htmlSources = ["src/html/*.html"],
imgSources = ["z_design/images/processed/**/*.*"],
imgDest = ["public/img/**/*.*"],
cssTemp = ["src/temp/css/styles.css"],
srcjQuery = "node_modules/jquery/dist/jquery.min.js",
srcMustache = "node_modules/mustache/mustache.min.js";
gulp.task("message", function() {
gutil.log("============= Gulp script started ==============");
});
// compiling less
gulp.task("less-compile", function() {
gulp.src(lessMain)
// switches sourcemaps on/off
.pipe(sourcemaps.init())
.pipe(less()
.on("error", gutil.log))
// switches sourcemaps on/off
.pipe(sourcemaps.write())
// change .dest("folder") to "public/css"
// to make no-autoprefix
// or to "src/temp/css/" to switch autoprefix on
.pipe(gulp.dest("public/css"))
});
// prepare & copy js files
gulp.task("js", function() {
gulp.src([srcjQuery, srcMustache, jsSources])
.pipe(concat("script.js"))
.pipe(gulp.dest("public/js/"))
});
// .pipe(browserify())
// {bundleExternal: false}
// copy JSON files
gulp.task("copyjson", function() {
gulp.src(jsonSources)
.pipe(newer("public/js/"))
.pipe(gulpcopy("public/js/", {
prefix: 2
}))
});
// copy html files
gulp.task("copyhtml", function() {
gulp.src(htmlSources)
.pipe(newer("public/"))
.pipe(gulpcopy("public/", {
prefix: 2
}))
});
// --- minify & compress images: 2 tasks - auto and manual
// minify & copy images - manual task
gulp.task("img-ondemand", function() {
gulp.src("z_design/images/unprocessed/**/*.*")
.pipe(newer("public/img/"))
.pipe(imagemin({
progressive: true
}))
.pipe(gulp.dest('z_design/images/processed/'))
});
// minify & copy images - automatic task
gulp.task("processimages", function() {
gulp.src(imgSources)
.pipe(newer("public/img/"))
.pipe(imagemin({
progressive: true
}))
.pipe(gulp.dest('public/img/'))
});
// --- end
// forced reload
gulp.task("reload", function() {
browserSync.reload();
});
// autoprefixer
gulp.task("autoprefix", function() {
gulp.src(cssTemp)
.pipe(autoprefixer({
browsers: ['last 3 versions', 'safari 5', 'ie 8', 'ie 9', 'ie 10', "ie11", 'opera 12.1', 'ios 6', 'android 4'],
cascade: false
}))
.pipe(gulp.dest("public/css/"))
});
// watching for changes
gulp.task("watch", function() {
gulp.watch(lessSources, ["less-compile"])
gulp.watch(jsSources, ["js"])
gulp.watch(jsonSources, ["copyjson"])
gulp.watch(htmlSources, ["copyhtml"])
gulp.watch(imgSources, ["processimages"])
gulp.watch(imgDest, ["reload"])
gulp.watch("src/temp/css/styles.css", ["autoprefix"])
});
// serving localhost
gulp.task('browser-sync', function() {
browserSync.init({
server: ["public", "src"],
watchTask: true,
open: false,
files: ["public/*.html", "public/css/*.css", "public/js/*.*",
"public/img/**/*.*"]
});
});
// === production preparations: RUN SEPARATE TASKS ON DEMAND ===
// --- minify & compress HTML, CSS, JS
// uglify JS
gulp.task("compress-js", function() {
gulp.src("public/js/script.js")
.pipe(uglifyjs())
.pipe(gulp.dest('public/js/'))
});
// uglify CSS
gulp.task('uglify-css', function() {
gulp.src('public/css/styles.css')
.pipe(uglifycss({
"debug": true,
"uglyComments": true
}))
.pipe(gulp.dest('public/css/'));
});
// compress HTML
gulp.task('compress-html', function() {
return gulp.src('src/html/*.html')
.pipe(htmlmin({
collapseWhitespace: true,
removeComments: true
}))
.pipe(gulp.dest('public/'));
});
// --- lint HTML and validate CSS
// lint html
gulp.task('lint-html', function() {
gulp.src("public/*.html")
.pipe(htmlhint())
.pipe(htmlhint.reporter())
});
// validate html
// Option format set to html
gulp.task('validate-html', function() {
gulp.src('public/*.html')
.pipe(htmlv({
format: 'html'
}))
.pipe(gulp.dest('src/temp/validation/'));
});
// add css validation
gulp.task('validate-css', function() {
gulp.src('public/css/*.css')
.pipe(validatecss())
.pipe(gulp.dest('src/temp/validation/'));
});
gulp.task("validate", ["validate-html", "validate-css", "lint-html"]);
gulp.task("compress", ["compress-js", "uglify-css", "compress-html"]);
gulp.task("default", ["watch", "browser-sync"]);
// =======================
Using: Grunt 1.01, load-grunt-config, jit-grunt.
I'm looking to put a simple means of setting a development/production flag in place for use in certain Grunt tasks.
The first task that needs the flag is webpack.js, in order to switch between the development and production builds of React. Here's that file:
module.exports = function( grunt ) {
// Get the task that was invoked from the command line.
var theTask = process.argv[2];
// Check to see if it's a production task. If so, change the
// `env` variable accordingly.
if ( theTask !== undefined && theTask.indexOf('prod') === 0 ) {
grunt.config.set('env', 'production');
}
return {
app: {
entry: './<%= siteInfo.build_dir %>/<%= siteInfo.temp_dir %>/<%= siteInfo.app_dir %>/<%= siteInfo.app_file %>.js',
output: {
path: '<%= siteInfo.build_dir %>/<%= siteInfo.temp_dir %>',
filename: '<%= siteInfo.bundle_file %>.tmp.js'
},
stats: false,
failOnError: true,
progress: false,
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(grunt.config.data.env)
}),
]
}
}
};
In the context of this task, it works perfectly. If I run grunt prod then the correct version of React is being included in the bundled JS.
However, I was under the (most certainly) mistaken impression that by setting the env variable using grunt.config.set this update to Grunt's config object would then be available to subsequent tasks.
As I've found out, env is undefined if I console.log(grunt.config.data.env) in another task.
Any pointers or suggestions of alternative approaches appreciated!
Instead of returning the config, try this:
Create a pre-build task which sets any config/options prior to running your tasks. You can check if the task is prod or not by checking this.name, and then since it's a simple value, set it using grunt.option:
function preBuild() {
grunt.option('env', this.name === 'prod' ? 'production' : 'development');
grunt.task.run(['task1', 'task2', task3']);
}
grunt.registerTask('prod', preBuild);
grunt.registerTask('dev', preBuild);
Using a lo-dash template, you can pass the option value to your config. Grunt compiles the lo-dash template strings when the task accessing it is run:
grunt.initConfig({
app: {
entry: './<%= siteInfo.build_dir %>/<%= siteInfo.temp_dir %>/<%= siteInfo.app_dir %>/<%= siteInfo.app_file %>.js',
output: {
path: '<%= siteInfo.build_dir %>/<%= siteInfo.temp_dir %>',
filename: '<%= siteInfo.bundle_file %>.tmp.js'
},
stats: false,
failOnError: true,
progress: false,
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': "<%= grunt.option('env') %>"
}),
]
}
});
How to get Source Maps with "stylify" and "insert-css" using Browserify / Gulp?
My gulp javascript task is like this:
gulp.task('js_watch', ['environmentCheck'], function()
{
var bundle = function()
{
return bundler.bundle()
.on('start', bundleLogger.start)
.on('error', handleErrors)
.pipe(source('bundle.js'))
// remove console.logs and such
.pipe(gulpif( global.ENV === 'production', streamify( strip() )))
// uglify JS and obfuscate in produciton mode only
.pipe(gulpif( global.ENV === 'production', streamify(uglify({ mangle: global.ENV === 'production' }))))
.pipe(print())
.pipe(gulp.dest(global.outputDir + datapaths.dataPath + '/js'))
.on('end', bundleLogger.end);
}
var browserify_instance = browserify({
// Required watchify args
cache: {}, packageCache: {}, fullPaths: true,
// Browserify Options
entries: ['./core/js/core.js'],
extensions: ['.jade', '.styl'],
debug: global.ENV === 'development'
});
browserify_instance.transform('stylify', {
use :[
jeet(),
rupture(),
typographic(),
axis(),
autoprefixer({ browsers: ['ie 7', 'ie 8'] })
],
sourcemap: { inline: global.ENV === 'development' },
compress: global.ENV === 'production',
});
var bundler = watchify(browserify_instance);
bundler.on('update', bundle); // on any dep update, runs the bundler
bundle();
});
Then in the JS code:
var insertCss = require('insert-css');
insertCss(require('../../stylus/pages/dashboard.styl'));
Every option in the Transform options works, except I get no Sourcemaps in the resulting CSS (in the browser).
It appears Stylify only accepts settings passed in with the set object.
browserify_instance.transform('stylify', {
use: [...]
set: {
sourcemap: { inline: global.ENV === 'development' },
compress: global.ENV === 'production'
}
});
I've set up a gruntfile that looks like the following. The aim being to perform e2e tests using protractor for my angularjs project. When running this using mochaProtractor Chrome fires up as expect but the lint is telling me that I'm missing the dependancies for the expect statement. This should referencing the assertion library chai. How do I include dependencies for chai to get this to work correctly?
Thanks
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['public/specs/e2e/*.js'],
tasks: ['mochaProtractor','jshint'],
options: {
spawn: false,
},
},
},
jshint: {
all: [
'Gruntfile.js',
'public/app/js/*.js'
],
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
unused: true,
boss: true,
eqnull: true,
node: true
}
},
mochaProtractor: {
options: {
browsers: ['Chrome']
},
files: ['public/specs/e2e/*.js'],
baseUrl: 'http://localhost:3000/'
},
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-mocha-protractor');
Below is the spec I'm trying to test against. Note: I added the require statement at the top in attempt to get it to work. Any thoughts?
var chai = require('chai');
var expect = chai.expect;
describe("Given a task entry screen", function() {
ptor = protractor.getInstance();
beforeEach(function() {
ptor.get('#/');
button = ptor.findElement(protractor.By.className('btn-say-hello'));
button.click();
});
it('says hello', function() {
message = ptor.findElement(protractor.By.className('message'));
expect(message.getText()).toEqual('Hello!');
});
});
You have to add chai as a dev dependency in your package.json.
{
"name": "yourProject",
"devDependencies": {
"chai": "~1.8.1"
}
}
then install the dependenvy via
npm install`
and then you should be able to write a spec :
var chai = require('chai');
var expect = chai.expect;
describe("Given a task entry screen", function() {
ptor = protractor.getInstance();
beforeEach(function() {
ptor.get('#/');
button = ptor.findElement(protractor.By.className('btn-say-hello'));
button.click();
});
it('says hello', function() {
message = ptor.findElement(protractor.By.className('message'));
expect(message.getText()).toEqual('Hello!');
});
});