I am using gulp, browserify, watchify and factor bundle to build several javascript files in development. Everything works fine, excepts after some time I start seeing this warning:
Trace
at Browserify.addListener (events.js:179:15)
at f (/Users/benoit/git/figure/web/node_modules/factor-bundle/index.js:55:7)
at Browserify.plugin (/Users/benoit/git/figure/web/node_modules/browserify/index.js:345:9)
at Browserify.bundle (/Users/benoit/git/figure/web/gulpfile.js:46:13)
at Browserify.emit (events.js:107:17)
at null._onTimeout (/Users/benoit/git/figure/web/node_modules/watchify/index.js:126:15)
at Timer.listOnTimeout (timers.js:110:15)
(node) warning: possible EventEmitter memory leak detected. 11 finish listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
at ConcatStream.addListener (events.js:179:15)
at ConcatStream.once (events.js:204:8)
at Labeled.Readable.pipe (/Users/benoit/git/figure/web/node_modules/factor-bundle/node_modules/labeled-stream-splicer/node_modules/stream-splicer/node_modules/readable-stream/lib/_stream_readable.js:612:8)
at /Users/benoit/git/figure/web/node_modules/factor-bundle/index.js:73:43
at Array.reduce (native)
at Transform._flush (/Users/benoit/git/figure/web/node_modules/factor-bundle/index.js:65:35)
at Transform.<anonymous> (/Users/benoit/git/figure/web/node_modules/factor-bundle/node_modules/through2/node_modules/readable-stream/lib/_stream_transform.js:135:12)
at Transform.g (events.js:199:16)
at Transform.emit (events.js:129:20)
at finishMaybe (/Users/benoit/git/figure/web/node_modules/factor-bundle/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:371:12)
at endWritable (/Users/benoit/git/figure/web/node_modules/factor-bundle/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:378:3)
at Transform.Writable.end (/Users/benoit/git/figure/web/node_modules/factor-bundle/node_modules/through2/node_modules/readable-stream/lib/_stream_writable.js:356:5)
(node) warning: possible EventEmitter memory leak detected. 11 finish listeners added. Use emitter.setMaxListeners() to increase limit.
Below is my gulpfile
var gulp = require('gulp');
var gutil = require('gulp-util');
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var reactify = require('reactify');
var watchify = require('watchify');
var factor = require('factor-bundle');
var uglify = require('gulp-uglify');
var fs = require('fs');
var concat = require('concat-stream');
var file = require('gulp-file');
gulp.task('watch', bundle)
function bundle () {
// react components
var files = [
'/path/to/file1.jsx',
'/path/to/file2.jsx',
'/path/to/file3.jsx'
];
var bundler = watchify(browserify(watchify.args))
bundler.add(files);
bundler.add('./lib/api.js', {expose: 'api'});
bundler.require('./lib/api.js', {expose: 'api'});
bundler.transform('reactify');
bundler.on('update', rebundle);
function rebundle() {
bundler.plugin('factor-bundle', {
outputs: [
write('/path/to/file1.js'),
write('/path/to/file2.js'),
write('/path/to/file3.js'),
]
});
bundler.bundle()
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(write('shared.js'));
};
return rebundle();
}
function write (name) {
return concat(function (content) {
// create new vinyl file from content and use the basename of the
// filepath in scope as its basename.
return file(name, content, { src: true })
// uglify content
.pipe(uglify())
// write content to build directory
.pipe(gulp.dest('./public/bundles/'))
});
}
I read I should set max listeners somewhere but I am afraid this might be a geniune memory leak.
My initial solution didn't work, and it looks like it really is a bug. I think I've found a temporary hacky fix though.
Edit node_modules/factor-bundle/index.js and change
From
b.on('reset', addHooks);
to
b.once('reset', addHooks);
Your original code should work.
Here's the GitHub issue for anyone who's keeping score :D
Related
I'm following a pretty basic tutorial for react to get acquainted with how it functions. So forgive me if I've missed something obvious. Part of the beginning of the tutorial was setting up gulp to handle sass files. So I set up my gulp file, setup my dependencies and tried to save my scss file, unfortunately I got an TypeError error and spent about an hour or so trying to overcome it on my own, but couldn't find anything concrete.
I'm running into an issue with gulp-change. I've gone line by line and ensure that was the line causing the TypeError issue.
gulpfile.js
'use strict';
var gulp = require('gulp');
var sass = require('gulp-sass');
var minifyCSS = require('gulp-clean-css');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var changed = require('gulp-change');
/////////////////
// - SCSS / CSS
/////////////////
var SCSS_SRC = './src/Assets/scss/**/*.scss';
var SCSS_DEST = './src/Assets/css';
gulp.task('compile_scss', function(){
gulp.src(SCSS_SRC)
.pipe(sass().on('error', sass.logError))
.pipe(minifyCSS())
.pipe(rename({ suffix: '.min' }))
////////////line creating the error//////////////
.pipe(changed(SCSS_DEST))
.pipe(gulp.dest(SCSS_DEST));
});
//detect changes in SCSS
gulp.task('watch_scss', function(){
gulp.watch(SCSS_SRC, ['compile_scss']);
});
//run tasks
gulp.task('default', ['watch_scss']);
Error Given
internal/streams/legacy.js:59
throw er; // Unhandled stream error in pipe.
TypeError: run.call is not a function
at R:\Documents\Projects\React Goal App\goal-app\node_modules\gulp-change\index.js:31:14
at wrappedMapper (R:\Documents\Projects\React Goal App\goal-app\node_modules\map-stream\index.js:84:19)
at Stream.stream.write (R:\Documents\Projects\React Goal App\goal-app\node_modules\map-stream\index.js:96:21)
at Transform.ondata (_stream_readable.js:639:20)
at emitOne (events.js:116:13)
at Transform.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at Transform.Readable.push (_stream_readable.js:208:10)
at Transform.push (_stream_transform.js:147:32)
gulp-change index.js
var eventStream = require('event-stream');
module.exports = gulpChange;
function gulpChange(run) {
return eventStream.map(function(file, done) {
if (file.isNull()) {
return done(null, file);
}
if (file.isStream()) {
return done(new PluginError('gulp-change', 'Streaming not supported.'));
}
var content = file.contents.toString();
var ctx = {
file: file,
fname: file.history[file.history.length - 1].substr(file.base.length),
originalContent: content
};
function next(err, content) {
if (err) {
return done(err);
}
if (content) {
file.contents = new Buffer(content);
}
done(null, file);
}
if (run.length > 1) {
////////////////line 31 where run is indicated as not a function/////////////
run.call(ctx, content, next);
} else {
next(null, run.call(ctx, content))
}
});
}
default.scss file I'm working with
body{
font-size: 10px;
}
Folder Structure for scss/css
goal-app (root)
src
Assets
css
scss
default.scss
If I understood your code correctly then the run parameter of gulpChange method is same thing you pass to changed method in .pipe(changed(SCSS_DEST)) line. That makes the run variable to be string.
String is not a function but it has length property and that's why if (run.length > 1) { line doesn't throw error and is even calculated as true.
The used package is gulp-change not gulp-changed as might think. The documentation of gulp-change says that you must pass function as a parameter.
I want to apply react to my NodeJs
This is my gulpfile:
let gulp = require('gulp');
let uglify = require('gulp-uglify');
let browserify = require('browserify');
let babelify = require('babelify');
let source = require('vinyl-source-stream');
let buffer = require('vinyl-buffer');
let gutil = require('gulp-util');
let sourcemaps = require('gulp-sourcemaps');
let assign = require('lodash.assign');
let watchify = require('watchify');
let customOpts = {
entries : ['./App/app.js'],
extensive : ['.js'],
debug: true
};
let opts = assign({}, watchify.args, customOpts);
let b = watchify(browserify(opts));
gulp.task('js', bundle); // so you can run `gulp js` to build the file
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
function bundle() {
return b.transform(babelify,babelify.configure())
.bundle()
// log errors if they happen
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('app.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('dest'));
}
gulp.task('default',['js']);
Then I intput gulp js
D:\weather-app>gulp js
[00:03:47] Using gulpfile D:\weather-app\gulpfile.js
[00:03:47] Starting 'js'...
[00:03:57] 2112196 bytes written (10.56 seconds)
[00:04:27] Finished 'js' after 41 s
The terminal got stuck here, I had to type Ctrl C to stop it.
Strangely, when I opened the index.html, the appearance changed.
So I don't know how could that be.
I use perforce for code checkin in our private server, so after production build (i.e., when index.html is read only) my gulp task fails with below error.
[INFO] [11:30:19] Error: EPERM: operation not permitted, open 'C:\MyProjectDir\index.html'
Once I checkout files or uncheck the read only property (using windows box) the gulp task finishes successfully. Is there a way to change it's permission through gulp task to avoid this manual intervention?
PS: I have used chmod(777)
Gulp file (end part where inject takes place)
var gulp = require('gulp'),
gutil = require('gulp-util'),
uglify = require('gulp-uglify'),
minify = require('gulp-minify-css'),
concatVendor = require('gulp-concat-vendor'),
concatCss = require('gulp-concat-css'),
rev = require('gulp-rev'),
clone = require('gulp-clone'),
inject = require('gulp-inject'),
del = require('del'),
runSequence = require('run-sequence'),
chmod = require('gulp-chmod'),
series = require('stream-series'),
ngAnnotate = require('gulp-ng-annotate'),
rename = require("gulp-rename");
...
gulp.task('index', ['gulp-js-files', 'gulp-css-files'], function() {
var target = gulp.src(mainIndexFile);
return target.pipe(chmod(777)).pipe(inject(series(vendorCss, customCss, vendorJs), { ignorePath: ['MyProjectDir'], addRootSlash: false }))
.pipe(gulp.dest(mainDestination));
});
...
Running cmd in Administrator mode
One option would be to use gulp-exec to remove the read-only flag with attrib -r, then re-set it with attrib +r after injecting the data (if necesarry).
Following is an example:
gulp.task('remove-readonly-attributes', function() {
require("child_process").exec("attrib -r <dir-name>\*.* /s");
});
We've been using gulp and browserify to create builds of our project whenever a js file changes. As the project has grown this process has become incredibly slow, from 200ms -> ~5s. The project has 69 directories, 173 files, and a max depth of 4 folders. We are applying a few transforms. Here's our build code.
var buildJS = function (entryPoint, name, cb) {
var browserify = require('browserify');
var uglify = require('gulp-uglify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var reactify = require('reactify');
var literalify = require('literalify');
var brfs = require('brfs');
browserify()
.require(entryPoint + '/' + name + '.jsx')
.transform({
global: true
}, reactify)
.transform({
global: true
}, brfs)
.transform({
global: true
}, literalify.configure(literalifyConfig))
.external(config.libs)
.bundle({
debug: config.DEV,
//detectGlobals : false
})
.on('error', handleError)
.pipe(source('bundle.js'))
.pipe(buffer())
.pipe(gulpIf(!config.DEV, uglify()))
.pipe(gulp.dest(config.buildPath + '/' + name))
.on('finish', cb)
};
Is this just normal behavior based on our project size? Or are we doing something wrong?
That's because browserify always recompile everything. You should be using incremental builds instead if you want good perfs.
I've developed a gulp plugin precisely for that: https://github.com/ngryman/gulp-bro.
Here's my gulpfile.js:
var gulp = require('gulp');
var clean = require('gulp-clean');
var DEST_BASE = 'dist';
var JADE_TASK = 'jade';
var JADE_SRC = 'app/**/ui/*.jade';
var JADE_DEST = DEST_BASE + '/dist/app';
gulp.task(JADE_TASK, function() {
return gulp.src(JADE_SRC).pipe(gulp.dest(JADE_DEST));
});
gulp.task('clean', function() {
return gulp.src(DEST_BASE, {read: false}).pipe(clean());
});
gulp.task('default', ['clean'], function() {
gulp.start(JADE_TASK);
});
gulp.task('watch', ['default'], function(){
gulp.watch(JADE_SRC, JADE_TASK);
});
All it does is copy files from one directory to another. When I run
gulp
it copies the files as expected. When I run
gulp watch
it runs the default task as expected. When I modify a source file, I get the following error:
<PROJECT_ROOT>\node_modules\gulp\node_modules\vinyl-fs\node_modules\glob-watcher\index.js:17
if(cb) cb(outEvt);
^
TypeError: string is not a function
at Gaze.<anonymous> (<PROJECT_ROOT>\node_modules\gulp\node_modules\vinyl-fs\node_modules\glob-watcher\index.js:17:14)
at Gaze.EventEmitter.emit (events.js:98:17)
at Gaze.emit (<PROJECT_ROOT>\node_modules\gulp\node_modules\vinyl-fs\node_modules\glob-watcher\node_modules\gaze\lib\gaze.js:120:32)
at <PROJECT_ROOT>\node_modules\gulp\node_modules\vinyl-fs\node_modules\glob-watcher\node_modules\gaze\lib\gaze.js:393:16
at StatWatcher._pollers.(anonymous function) (<PROJECT_ROOT>\node_modules\gulp\node_modules\vinyl-fs\node_modules\glob-watcher\node_modules\gaze\lib\gaze.js:316:7)
at StatWatcher.EventEmitter.emit (events.js:98:17)
at StatWatcher._handle.onchange (fs.js:1104:10)
Am I doing something wrong besides using Windows? (edit: reproducible in OS X)
The second argument to gulp.watch should either be an array or a function, not (as in your case) a string.
So use this instead:
gulp.watch(JADE_SRC, [ JADE_TASK ]);