I have just recently moved from grunt to gulp and I am wanting to pre-compile my handlebars templates (with .handlebars extension) into separate .js files.
from:
www/templates/login.handlebars
www/templates/home.handlebars
to:
www/templates/login.js
www/templates/home.js
I am trying to use gulp but to no avail. A lot of the npm packages ask you to pass data to the compiler, but the data in my web app is collected mainly from ajax requests and then passed to the handlebars template.
My gulpfile.js:
// cache vars
var gulp = require('gulp'),
rename = require('gulp-rename'),
handlebars = require('gulp-compile-handlebars');
// start task
gulp.task('default', function(){
return gulp.src( 'www/templates/*.handlebars' )
.pipe( handlebars() )
.pipe( rename('*.js') )
.pipe( gulp.dest( 'www/templates' ) );
});
});
The main reason i moved from Grunt to Gulp was because grunt doesnt seem to support the newer handlebars version (link here).
There are lots of examples how to compile handlebars templates but not in the way I want too (Is my way possible?)
Also i don't want to wrap my handlebar js files into a namespace if possible.
When i run my gulp task none of the .js files are generated any ideas?
I have a not so clean solution that works for me. I'm using pump + gulp as it's a good idea to clean the source if something goes wrong while processing the pipe.
in the gulpfile.js:
const pump = require( 'pump' )
const handlebars = require( 'gulp-handlebars' )
gulp.task( 'default', ( done ) => {
const templates = [
'login',
'home'
] // <-- You may want to get the list of files programmatically ;)
let pipe = []
templates.forEach( ( template ) => {
pipe.push( gulp.src( 'www/templates/' + template + '.handlebars' ) )
pipe.push( handlebars() )
pipe.push( gulp.dest( 'www/templates/' ) )
} )
pump( pipe, done )
} )
Related
I started working on a chrome extension.
So far I setup the project using gulp to watch the folder containing the code for background, popup, content and a few other pages.
Each component shares some some code with the others.
The problem is that every time I edit a file watchify will trigger a full rebuild.
I have tried to limit the browserify process to only handle the files that have changed. It works very well for root scripts (popup.js, background.js, content.js)...
But unfortunately I have no way of tracking dependencies (files required by the root scripts or their dependencies) and this strategy fails when a dependency is edited.
So here is my question is there a good strategy to automatically update any dependent script upon change while avoiding a full browserify of the entire tree?
gulp.task('babel', () => {
buildingTasks.start('babel');
return gulp.src(scriptSrc)
.pipe(through2.obj(function (file, enc, next){
var b = browserify(file.path, {
debug: (process.env.NODE_ENV === 'development')
});
b.transform(babelify, {presets: ['es2015', 'react']});
b.bundle(function(err, res){
if (err) return next(err);
file.contents = res;
next(null, file);
});
}))
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('map'))
.pipe(gulp.dest(scriptDest))
});
I have found this answer to access the dependencies list, but it would require building a dependency tree by hand, storing it somewhere and updating it every time a build is triggered. Is there a better solution?
For Browserify to watch the bundled files, you need to configure Watchify:
var browserify = require('browserify');
var watchify = require('watchify');
...
var options = Object.assign({}, watchify.args, {
debug: (process.env.NODE_ENV === 'development')
});
var b = watchify(browserify(file.path, options));
The watchify methods wrap the Browserify bundler and provides some shared arguments via options that are used to determine which files need to be watched. It returns the same bundler that would have been returned by browserify.
There is a parent folder (gulp module) which has some child folders (gulp modules too). I want to run the default gulp task of each child through the gulpfile of the parent.
My approach was to iterate through the folders by using gulp-folders and run a gulp through gulp-shell by setting the current work directory to the corresponding child.
var tOptions = {};
[...]
gulp.task('setup-modules', folders('./', function(folder){
tOptions.cwd = folder;
gulp.start('setup-module');
return gulp.src('', {read: false});
}));
gulp.task('setup-module', shell.task([
'gulp'
], tOptions));
It seems that just one instance of the task setup-module gets started. What do I need to change to get several instances (for each child folder) of the task running?
Instead of using gulp-shell you can use gulp-chug and pass a glob to gulp.src() to access your child gulpfiles eliminating the need to iterate over each subdirectory. You can even specify which tasks you would like to run if you want to run any task(s) other than default.
Additionally, gulp-chug will do everything so there's no need to depend on more than just that one package accomplish what you're looking to do.
One of the examples from the gulp-chug docs goes over almost the exact scenario you're discussing.
gulpfile.js (parent)
// This example was taken from the gulp-chug docs
var gulp = require( 'gulp' );
var chug = require( 'gulp-chug' );
gulp.task( 'default', function () {
// Find and run all gulpfiles under all subdirectories
gulp.src( './**/gulpfile.js' )
.pipe( chug() )
} );
I've started using React with Flux architecture for full functional frontend application, and I really liked approach JSX and Flux , but the main issue is that when I'm building JSX files using Gulp, Babel and Uglyfy I'm getting about 1mb minified JS file, without minified mode it is giving almost 8mb of JS file.
And that's not the end !! for making AJAX requests React don't have built in functionality, so I need also include jQuery
I's working well, development process is faster and code is nicer than with other frameworks thanks to JSX. But how to make production files smaller ?
I'm including just a few libs Dispatcher and EventEmmiter for Flux architecture. So it's not about having unused libs in my code. I think it is because I'm writing JSX and now I have HTML+JS in one single file.
What is the best practice to split files or make JS output more smaller ?
Thanks !
There are some steps to reduce production size:
Use production version of ReactJS, which includes extra performance optimizations and strips all error messages.
You don't have to include the whole jQuery library to just use Ajax, I suggest use other lightweight library for handling ajax only e.g. reqwest or superagent.
When build for production, separate to two js files (or more), usually we will have one file called vendor.js for all libraries and app.js for just the code we made. This will leverage cache on browser as vendor.js won't change much each built.
I saw that there is a little information about using React for different pages, so I learned a lot from Gulp documentation and I found a lot of very small JS libraries MicroJS which could replace Dispatcher and EventEmmiter with just a 4-6 KB in size of course you need to do some manual work with them, but they saving about 20 times in JS file size.
Here is my Gulp file for generating minified react bundle for each page. I'm using Django for backend.
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var htmlreplace = require('gulp-html-replace');
var source = require('vinyl-source-stream');
var browserify = require('gulp-browserify');
var reactify = require('reactify');
var babelify = require('babelify');
var streamify = require('gulp-streamify');
var fs = require("fs");
var rename = require("gulp-rename");
var path = {
APP_DIR: './apps/*.jsx',
OUT_DIR: './../static/apps',
};
process.env.NODE_ENV = 'development';
gulp.task('jsx', function() {
return gulp.src([path.APP_DIR])
.pipe(browserify({
insertGlobals : true,
debug : true,
transform: [reactify, babelify.configure({
presets: ["es2015", "react"]
})],
}))
.pipe(rename({
extname: ".min.js"
}))
.pipe(gulp.dest(path.OUT_DIR));
});
gulp.task('jsx_min', function() {
return gulp.src([path.APP_DIR])
.on('error', function (error) {
console.log(error);
})
.pipe(browserify({
insertGlobals : true,
debug : false,
transform: [reactify, babelify.configure({
presets: ["es2015", "react"]
})],
}))
.pipe(streamify(uglify().on('error', function (e) {
console.log(e);
})))
.pipe(rename({
extname: ".min.js"
}))
.pipe(gulp.dest(path.OUT_DIR));
});
gulp.task('build', ['jsx_min']);
gulp.task('default', ['jsx'], function () {
return gulp.watch([path.APP_DIR], ['jsx', function () {
var current_date = new Date();
var time = current_date.getHours() + ":" + current_date.getMinutes() + ":" + current_date.getSeconds();
console.log(time, " -> Rebuilding");
}]);
});
Now for each logical page I got about 40KB minified JS file for handling all JavaScript including AJAX functionality.
So I'm marking my question answered :)
Thanks for help.
I use Gulp to build a small web application based on the React framework.
To compile the client scripts, my task starts like that :
gulp.task( 'buildClientScripts', function () {
// Get all the js and jsx scripts
// Starts with the app.js file
return gulp.src( [
'app/app.js',
'app/clientScripts/**/*.jsx',
'app/clientScripts/**/*.js',
] )
The order of the files is my problem. For this file structure :
- clientScripts
---- components
-------- subComponents
------------ mysubComponent.js
-------- myComponent.js
---- main.js
The load order will be : main.js, myComponent.js, mysubComponent.js. But obviously, my top files need the deeper files to work.
How do I ask gulp to load the deepest files first ?
You can use gulp-sort to order the files after gulp.src reads them.
Count slashes in path as crude way to determine depth.
var sort = require('gulp-sort');
var path = require('path');
gulp.task( 'buildClientScripts', function () {
// Get all the js and jsx scripts
// Starts with the app.js file
return gulp.src( [
'app/app.js',
'app/clientScripts/**/*.jsx',
'app/clientScripts/**/*.js',
] )
.pipe(sort(function(file1, file2) {
return countSlashes(file2) - countSlashes(file1);
function countSlashes(file) {
return file.path.split(path.sep).length - 1;
}
})
I'm just started to use Gulp to improve my workflow. I'm currently have a task called styles that compiles .less files, and a task called watch, to watch for changes in any .less file and, then, run styles task. My gulpfile.js contains this code:
var gulp = require( 'gulp' ),
less = require( 'gulp-less' ),
autoprefixer = require( 'gulp-autoprefixer' ),
minifycss = require( 'gulp-minify-css' ),
jshint = require( 'gulp-jshint' ),
uglify = require( 'gulp-uglify' ),
imagemin = require( 'gulp-imagemin' ),
rename = require( 'gulp-rename' ),
clean = require( 'gulp-clean' ),
concat = require( 'gulp-concat' ),
notify = require( 'gulp-notify' ),
cache = require( 'gulp-cache' ),
header = require( 'gulp-header' ),
footer = require( 'gulp-footer' );
// styles task
gulp.task( 'styles', function() {
return gulp.src( 'src/styles/main.less' )
.pipe( less({ paths: ['src/styles/'] }) )
.pipe( autoprefixer( 'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4' ) )
.pipe( gulp.dest( 'dist/assets/css' ) )
.pipe( rename( 'main.min.css' ) )
.pipe( minifycss() )
.pipe( gulp.dest( 'dist/assets/css' ) )
.pipe( notify({ message: 'Styles task complete' }) );
} )
(...)
// watch task
gulp.task('watch', function() {
// Watch .less files
gulp.watch('src/styles/**/*.less', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
gulp.run('styles');
});
});
The problem is, when I run gulp watch, it starts the task and runs the styles task on the first time that I change a .less file. After the first time, I only got the message logged (File X was changed, running tasks...). Am I doing something wrong?
Thanks for any hint or help!
EDIT
Just some information as requested: I'm running Node.js 0.10.24 with Gulp 3.4.0. Here is a screenshot of the prompt output:
After #SteveLacy suggestion to break out my task parts and check if any of them was causing the troubles, I got my really dumb mistake that causes the error: gulp-notify works only on Mac and Linux, and my OS is Windows. From the plugin description:
Send messages to Mac Notification Center or Linux notifications (using
notify-send) using the node-notifier module. Can also specify custom
notifier (e.g. Growl notification).
Shame on me.
I follow a really good tutorial about getting started with Gulp, and gulp-notify was one of the plugins used on it. My mystake was not paying attention at the plugin details.
After I removed gulp-notify from my gulpfile.js, everything works as it should be, I got all the right logs and my gulp watch task works like a charm!
In short: AWAYS check a plugin compatibility with your OS.
Thanks for everybody that spent time trying to help me!
I had the same problem, and mine was a total gulp newbie problem. If anyone is as pathetically new to gulp as I am, ensure your triggered watch functions end with a done():
gulp.task("watch", function() {
gulp.watch("lib/*.js, "foobar");
});
gulp.task("foobar", function(done) {
// This task completion was omitted.
done();
});
If I remember correctly gulp.run is deprecated in Gulp version 3.5. Try to replace gulp.run(); with gulp.start(); and see if that works.