I'm using BrowserSync in server mode (using its built-in static server) with GulpJS on a local project, and everything seems to be working correctly except that the BrowserSync server is very slow to startup. BrowserSync itself seems to initialize right away when I run Gulp, but it takes about 4 to 5 minutes (and occasionally more) for the server to start and for it to return the access URLs. During this period, everything continues to run and BrowserSync responds to reload() calls and such, but access is not available via the usual URLs (in this case, localhost:3000 and localhost:3001). Once the access URLs are returned, the server has seemingly started and BrowserSync's page refreshes work fine and are actually very speedy.
I have tried several different configurations of my gulpfile.js, trying different ways to initialize BrowserSync, different approaches to calling the stream() and reload() methods (including trying BrowserSync's basic Gulp/SASS "recipe"), and different port numbers, but all configurations had the same problem. I even tried disabling my firewall and AV software (Avast), but nothing.
I'm running Windows 8.1, if that's relevant. BrowserSync is freshly installed locally to the project via NPM, and fresh local installs to other directories have the same problem. NPM, Ruby, Gulp, and all modules seem to be up-to-date. For what it's worth, all of my other experience with Ruby, Gulp, and Node.js have been very smooth and problem-free.
I can't find any other posts mentioning this problem and am beginning to think this is normal behavior. Is this normal, and, if not, does anyone have any ideas of things to try? This delay is not the end of the world since the BrowserSync server does always start (eventually), but it's still a kink in my workflow that I'd rather fix than just deal with.
Finally, here is my gulpfile.js:
/* File: gulpfile.js */
var gulp = require('gulp'),
gutil = require('gulp-util');
jshint = require('gulp-jshint');
sass = require('gulp-sass');
concat = require('gulp-concat');
uglify = require('gulp-uglify');
sourcemaps = require('gulp-sourcemaps');
imagemin = require('gulp-imagemin');
browserSync = require('browser-sync').create();
gulp.task('default', ['watch'], browserSync.reload);
// JSHint
gulp.task('jshint', function() {
return gulp.src('src/js/**/*.js')
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
// Build JS
gulp.task('build-js', function() {
return gulp.src('src/js/**/*.js')
.pipe(sourcemaps.init())
.pipe(concat('main.js'))
//only uglify if gulp is ran with '--type production'
.pipe(gutil.env.type === 'production' ? uglify() : gutil.noop())
.pipe(sourcemaps.write())
.pipe(gulp.dest('public/www/js/core'));
});
// Build CSS
gulp.task('build-css', function() {
return gulp.src('src/sass/**/*.{sass,scss}')
.pipe(sourcemaps.init())
.pipe(sass()).on('error', handleError)
.pipe(sourcemaps.write()) // Add the map to modified source.
.pipe(gulp.dest('public/www/css/core'))
.pipe(browserSync.stream({match: '**/*.css'}));
});
// ImageMin
gulp.task('imagemin', function () {
return gulp.src('src/img/*')
.pipe(imagemin({
progressive: true,
svgoPlugins: [{removeViewBox: false}]
}))
.pipe(gulp.dest('public/www/img'));
});
// Handle errors
function handleError(err) {
console.log(err.toString());
this.emit('end');
}
// Watch function
gulp.task('watch', function() {
browserSync.init({
server: "./public/www",
//port: 3002
});
gulp.watch('src/js/**/*.js', ['jshint']);
gulp.watch('src/sass/**/*.{sass,scss}', ['build-css']);
gulp.watch('src/js/**/*.js', ['build-js']);
gulp.watch('src/img/*', ['imagemin']);
gulp.watch("public/www/css/**/*.css").on('change', browserSync.reload);
})
The BrowserSync Twitter account suggested that I set the "online" option to true, and...it seems to have worked!
I set it in BrowserSync's init like so:
browserSync.init({
server: "./public/www",
online: true
});
...and the delay is gone!
Going by the BrowserSync docs ( http://www.browsersync.io/docs/options/#option-online ), it seems that setting the online option to true skips the online check. So, I guess that check was somehow what was causing the delay? That seems odd to me, but it's working better now.
In my case I had this code in gulpfile which delay startup about 50 seconds
gulp.watch('./**/*.{js,html}').on('change', browserSync.reload);
and the problem was in the glob string. It inspects even node_modules folder. And I did some changes
gulp.watch(['./scripts/**/*.{js,html}', './index.html'])
.on('change', browserSync.reload);
I think that it is performance feature, that we should more exactly specify glob.
Related
Hi everyone I hope you having a great day, I'm trying to find a way on how do I make a min file in the same path or gulp.dest() on gulp(gulp-uglify and gulp-rename). In my code below when I run my gulp it keeps on creating *.min.js , *.min.min.js , *.min.min.min.js so on and so forth unless I stop the terminal. How do I make my gulp create only one *.min.js at the same time it uglify's. I hope everyone can help me with this one. Thank You.
const gulp = require('gulp');
const browserSync = require('browser-sync').create();
const rename = require('gulp-rename');
const uglify = require('gulp-uglify');
gulp.task('scripts', function() {
return gulp.src('./src/js/*.js')
.pipe(uglify())
.pipe(rename( {suffix: '.min'} ))
.pipe(gulp.dest('./src/js/'))
.pipe(browserSync.stream());
});
gulp.task('browserSync', function(){
browserSync.init({
server : {
baseDir : './'
}
});
gulp.watch('./src/js/**.js', gulp.series('scripts'));
});
gulp.task('default', gulp.series('scripts', 'browserSync'));
This is happening because your scripts task is outputting the files to the same directory as you are watching:
.pipe(gulp.dest('./src/js/'))
and
gulp.watch('./src/js/**.js', gulp.series('scripts'));
So every time scripts runs and saves to that directory it triggers your watch again which fires scripts, etc., etc.
So either save your .min's to a directory you are not watching or don't watch .min files.
BTW, change to gulp.watch('./src/js/*.js', gulp.series('scripts')); // removed one asterisk
gulp.watch(['./src/js/*.js', '!./src/js/*.min.js'], gulp.series('scripts')); //
might work - untested though.
I have following directory structure
workspace
|--dev
|--proj
|--css
|--style.css
|--js
|--app.js
|index.php
|something.html
|gulpfile.js
|package.json
I had installed vhost named as dev.local on ...workspace\dev. As you can see I have created a gulpfile.js in my proj directory.
Now if I run gulp browser-sync command my browser window is open showing following url http://dev.local:3000/proj/. It perfectly opens my index.php page but if I do any modification in my files they are not monitored and are not injected into my page. So there is no auto reload of my page.
Here is my gulpfile.js
var gulp = require('gulp');
var bs = require('browser-sync').create(); // create a browser sync instance.
gulp.task('browser-sync', function() {
bs.init({
open: 'external',
host: 'dev.local',
proxy: 'dev.local/proj'
});
});
gulp.task('watch', ['browser-sync'], function () {
gulp.watch("*.html,*.php,css/*.css,js/*.js").on('change', bs.reload);
});
Here is the output of my terminal
gulp browser-sync
[12:14:12] Using gulpfile ~/Documents/workspace/dev/proj/gulpfile.js
[12:14:12] Starting 'browser-sync'...
[12:14:12] Finished 'browser-sync' after 15 ms
[BS] Proxying: http://dev.local
[BS] Access URLs:
------------------------------------------------
Local: http://localhost:3000/proj
External: http://dev.local:3000/proj
------------------------------------------------
UI: http://localhost:3001
UI External: http://dev.local:3001
------------------------------------------------
I had already searched SO for various solutions but of no avail. Please help I am stuck.
UPDATE
I am using BrowserSync version 2.18.8 and gulp version 3.9.1
First of i would suggest to split the watching tasks into multiple, makes it easier to maintain and update. By reading your comments i can suggest to reverse the chain of gulp.tasks. You are currently loading 'browser-sync' from your watch task, but you can load your 'watch' task from your browser-sync task.
var gulp = require('gulp');
var bs = require('browser-sync').create(); // create a browser sync instance.
gulp.task('serve', function() {
bs.init({
open: 'external',
host: 'dev.local',
proxy: 'dev.local/proj'
});
});
gulp.task('watch', function () {
gulp.watch("*.html").on('change', bs.reload);
gulp.watch("*.php").on('change', bs.reload);
gulp.watch("./css/*.css").on('change', bs.reload);
gulp.watch("./js/*.js").on('change', bs.reload);
});
gulp.task('default', ['serve', 'watch']);
Also modifying css files can be streamed by browser-sync,
gulp.watch("css/*.css").on('change', bs.stream);
Next i would suggest to test weather or not the files are actually beeing monitored, and change the path of the gulp.watch tasks accordingly.
If you need help with this comment below.
Can you try this way? This is what I implemented in my application to finding the new uploaded images and resize and move to another folder.
This gulp code is watching new images from folder and reduce image size and move to scaled folder.
Probably it may helpful to you.
// include gulp
var gulp = require('gulp');
// include plug-ins
var imagemin = require('gulp-imagemin');
var watch = require("gulp-watch");
var newer = require("gulp-newer");
var gulpgm = require("gulp-gm");
//var imgSource = './app/client/media/site/max/*';
//var imgDestination = './app/client/media/site/min';
var imgSource = [
'./app/client/media/**/*.png',
'./app/client/media/**/*.jpg',
'./app/client/media/**/*.jpeg',
'./app/client/media/**/*.gif',
'./app/client/media/**/**/*.png',
'./app/client/media/**/**/*.jpg',
'./app/client/media/**/**/*.jpeg',
'./app/client/media/**/**/*.gif',
'./app/client/media/**/**/**/*.png',
'./app/client/media/**/**/**/*.jpg',
'./app/client/media/**/**/**/*.jpeg',
'./app/client/media/**/**/**/*.gif',
];
var imgDestination = './app/client/scaled/';
gulp
.task('imagemin', function () {
console.log("image min called");
return gulp.src(imgSource)
.pipe(watch(imgSource))
.pipe(newer(imgDestination))
.pipe(gulpgm(function (gmFile) {
return gmFile.minify();
}))
.pipe(gulp.dest(imgDestination));
});
gulp
.task("default", ["imagemin", "watch"]);
gulp
.task("watch", function () {
watch(imgSource, ["imagemin"]);
});
Got Browsersync to work with my Gulp file but I've really been struggling with getting browsersync to auto reload my static site when I make changes to the main.scss file. I've followed all the documentation on there webpage thoroughly and I still cant get page to auto refresh.
I know parts of my integration with gulp are working because when I run my default gulp task which is linked to the browser-sync task a browser window fires up with the server but when I make s simple change to my main.scss file nothing auto reloads. I have to manually refresh to see changes.
Here's my gulpfile..What am I missing in here?
// refferance gulp
var gulp = require('gulp');
// browser-sync
var browserSync = require('browser-sync');
var reload = browserSync.reload;
// other packages installed
var concat = require('gulp-concat');
var cssmin = require('gulp-minify-css');
var rename = require('gulp-rename');
var scss = require('gulp-sass');
var uglify = require('gulp-uglify');
// browser-sync task
gulp.task('browser-sync',['styles'] , function(){
browserSync.init({
server:'./'
});
gulp.watch('.//src/scss/*.scss',['styles']);
gulp.watch('.//*.html').on('change',browserSync.reload);
});
// scripts task
gulp.task('scripts', function(){
// fetch all files in the .js extension in the /src/js directory
return gulp.src('./src/js/*.js')
// concatenate files and save as app.js
.pipe(concat('app.js'))
// save app.js in dest directory
.pipe(gulp.dest('./dest/js/'))
.pipe(uglify())
// minfiy file and rename to app.min.js
.pipe(rename({
suffix: '.min'
}))
// save in dest directory
.pipe(gulp.dest('./dest/js'));
});
// styles task
gulp.task('styles', function(){
// fetch all files with scss extension in /src/scss directory
return gulp.src('./src/scss/*.scss')
// compile scss
.pipe(scss())
// output css in css dest directory
.pipe(gulp.dest('./dest/css/'))
// minify css
.pipe(cssmin())
// rename as styles.min.css
.pipe(rename({
suffix: '.min'
}))
// save in same directory
.pipe(gulp.dest('./dest/css'))
// reload browser by injecting css into browser via browsersync
// .pipe(reload({stream:true}));
.pipe(browserSync.stream());
});
gulp.watch('./src/js/*.js', ['scripts']);
// we use the watch task in the default task bellow
gulp.task('watch',function(){
// watch js
gulp.watch('./src/js/*.js',['scripts']);
// watch scss
gulp.watch('./src/scss/*.scss',['styles']);
});
// default task allows us to run all tasks at once by just running `gulp` in command line
gulp.task('default', ['scripts', 'styles', 'browser-sync', 'watch']);
If you take out
gulp.watch('.//src/scss/*.scss',['styles']);
gulp.watch('.//*.html').on('change',browserSync.reload);
and replace with
gulp.watch('dest/**/*.html').on('change', browserSync.reload);
you should see changes providing that you are looking at a HTML file located under the dest directory.
I would also check that your styles and scripts tasks are firing. You should see this in the terminal/cli. If they are firing, any reload will also be logged too.
Hope that helps you out!
Just getting started with BrowserSync and I have a question regarding the common use-cases on configuration for SASS + CSS injecting.
What I'm a little confused about is weather I can give the server property its own name.
In the docs here they use "./app". Can I use another name like "./site" or am I only allowed to use "./app"?
Here's the code
// task
gulp.task('serve',['sass'], function (){
// static server
browserSync.init({
server: "./app"
});
// watching html and scss files for changes then reloading browser
gulp.watch("app/scss/*.scss", ['sass']);
gulp.watch("app/*.html").on('change', browserSync.reload);
});
UPDATED
If you're looking to set up browserSync as a static server with live reloading you're pretty much right with your approach. You can point browsersync to any folder in your repository using the baseDir option. You can also use multiple directories. For further info check out the options documentation.
First. I would look to split up the tasks you have.
Personally, I would opt to have my server task something like;
gulp.task('serve', ['build'], function(event) {
var server = browsersync.create();
server.init({
baseDir: 'app/'
});
return server.watch('app/**', function(evt, file) {
server.reload();
});
});
Note how build is a dependency. This ensures that all of our served files are in place when we initiate BrowserSync.
Keeping it generic we can then split the SCSS related tasks into their own tasks such as scss:compile and scss:watch.
gulp.task('scss:compile', function(){
return gulp.src('src/scss/**/*.scss')
.pipe(plumber())
.pipe(scss())
.pipe(gulp.dest('app/css/');
});
and
gulp.task('scss:watch', function() {
gulp.watch('src/scss/**/*.scss', ['scss:compile']);
});
For CSS injection. There are two options for doing this
Remember injection differs from reload. Whereas reload will reset the page state, injection won't affect the current page state and justs injects the styles.
Option one is to invoke browsersync.stream() with the piped content of your SASS compilation like follows;
gulp.task('scss:compile', function() {
return gulp.src('src/scss/**/*.scss')
.pipe(plumber())
.pipe(scss())
.pipe(gulp.dest('app/css')
.pipe(browsersync.stream());
});
Note that the last pipe injects the changes. This also requires to check the file type in the BrowserSync watch to only reload when a non CSS file changes.
This option is OK. However, I think it's not clear to have it just bundled on the end there and separate from BrowserSync setup code.
The second option(personally preferred) is to watch for changes with BrowserSync and if a CSS file changes, use vinyl to stream those changes to BrowserSync.
Something like the following tends to work;
var gulp = require('gulp'),
browsersync = require('browser-sync'),
vss = require('vinyl-source-stream'),
vb = require('vinyl-buffer'),
vf = require('vinyl-file');
gulp.task('serve', ['build'], function() {
var server = browsersync.create();
server.init({ baseDir: 'app/' });
return server.watch('app/**', function(evt, file) {
if (evt === 'change' && file.indexOf('.css') === -1)
server.reload();
if (evt === 'change' && file.indexOf('.css') !== -1)
vf.readSync(file)
.pipe(vss(file))
.pipe(vb())
.pipe(server.stream());
});
});
Hope that helps you out!
I'm trying to conditionally pipe a file stream based on the value of a variable, as a way to define two separate build environments (ie. development and production).
Some tasks can be run individually with a command-line flag like so:
gulp scripts --env production
And will then do some production-only pipeline steps:
gulp.task('scripts', function() {
var jsFilter = filter(['*.js']),
appFiles;
return gulp.src(appFiles)
.pipe(jsFilter)
.pipe(concat('application-build.js'))
.pipe(gulpif(env === 'production', uglify()))
.pipe(size())
.pipe(gulpif(env === 'production', gulp.dest('dist/js'), gulp.dest('tmp/js')))
.pipe(browserSync.reload({ stream: true }));
});
I have a build task that calls a number of other tasks as dependencies (including this scripts task for instance). I want this build task to assign a variable (env, in this case) before running task dependencies. Which means that this:
gulp.task('build', ['scripts', 'styles', 'otherstuff'], function() {
env = 'production';
}
doesn't work, because the dependencies are run before the body of the task.
I currently have it implemented with gulp.start:
gulp.task('build', function() {
env = 'production';
gulp.start('scripts');
});
But the .start method isn't actually part of gulp's public API - it comes from Orchestrator - and isn't intended to be used for anything. Plus, the equivalent method gulp.run was deprecated from the API awhile ago.
So I'm wondering - is there another way I could assign a variable in a task before running its dependencies?
(Or maybe there's a better way to to implement something like build environments in gulp?)
THE RIGHT WAY
I disagree with #Justin. Defining an environmental variable with a task is a hackjob of an idea. This is better done with gutil.env this way.
gulp --env prod task
gulp.task( 'myTask', () => { console.log( gutil.env.env ) } )
Now from this point, you have gulp.env.env set.
Or, alternatively you can do like this example in this ticket.. which addresses this from the developers of Gulp which first suggest to use an environmental variable, but provide this idiom..
function js(shouldMinify) {
return gulp.src('./js/*.js')
.pipe(concat('app.js'))
.pipe(gulpif(shouldMinify, uglify()))
.pipe(gulp.dest('js'));
});
gulp.task('develop', function () {
shouldMinify = false;
return js(shouldMinify);
});
gulp.task('build', function () {
shouldMinify = true;
return js(shouldMinify);
});
That same developer (phated) always says to use env...
Not to mention, you should control this type of logic with environment variables or command line flags. - phated
Presumably, he's referring to the use of gutil.noop() in gulp-util's docs:
// gulp should be called like this :
// $ gulp --type production
gulp.task('scripts', function() {
gulp.src('src/**/*.js')
.pipe(concat('script.js'))
// LOOK BELOW: if we don't send to uglify, we push to noop stream.
.pipe(gutil.env.type === 'production' ? uglify() : gutil.noop())
.pipe(gulp.dest('dist/'));
});
You could create a task specifically to set the environment and run it before your other tasks.
gulp.task('set-production', function() {
env = 'production';
});
// Doesn't quite work because tasks are run in parallel
gulp.task('build', ['set-production', 'scripts', 'styles', 'otherstuff']);
The problem here is that your tasks will be run in parallel, meaning the set-production task may be run after the other tasks. You can solve this problem with the run-sequence package.
var runSequence = require('run-sequence');
gulp.task('build', function(callback) {
runSequence('set-production', ['scripts', 'styles', 'otherstuff'], callback);
});
This will run the set-production task first, then run the scripts, styles, and otherstuff tasks in parallel.