Search code examples
javascripthtmlgulpgulp-watch

Gulp-file-include doesn't work with gulp.watch


I want to use gulp-file-include to assemble the index.html from different HTML files. The dist folder contains all production files. The problem is that gulp-watch does not recognize if an HTML file has changed, so the HTML file in the dist folder will not be updated while I run watch.

How can I customize gulp so that gulp-watch also detects these changes in real-time?

-- dist
---- css
---- js
---- vendor
---- index.html
-- res
---- js
---- scss
-- src
---- footer.html
---- nav.html
gulpfile.js
index.html

index.html

@@include('./src/nav.html')
@@include('./src/footer.html')

gulpfile.js

"use strict";

// Load plugins
const autoprefixer = require("gulp-autoprefixer");
const browsersync = require("browser-sync").create();
const cleanCSS = require("gulp-clean-css");
const del = require("del");
const gulp = require("gulp");
const header = require("gulp-header");
const merge = require("merge-stream");
const plumber = require("gulp-plumber");
const rename = require("gulp-rename");
const sass = require("gulp-sass");
const uglify = require("gulp-uglify");
const fileinclude = require('gulp-file-include');

// Load package.json for banner
const pkg = require('./package.json');

// BrowserSync
function browserSync(done) {
    browsersync.init({
        server: {
            baseDir: "./dist/"
        },
        port: 3000
    });
    done();
}

// BrowserSync reload
function browserSyncReload(done) {
    browsersync.reload();
    done();
}

// Clean vendor
function clean() {
    return del(["./dist/vendor/"]);
}

// Bring third party dependencies from node_modules into vendor directory
function modules() {
    // Bootstrap
    var bootstrap = gulp.src('./node_modules/bootstrap/dist/**/*')
        .pipe(gulp.dest('./dist/vendor/bootstrap'));
    // Font Awesome CSS
    var fontAwesomeCSS = gulp.src('./node_modules/@fortawesome/fontawesome-free/css/**/*')
        .pipe(gulp.dest('./dist/vendor/fontawesome-free/css'));
    // Font Awesome Webfonts
    var fontAwesomeWebfonts = gulp.src('./node_modules/@fortawesome/fontawesome-free/webfonts/**/*')
        .pipe(gulp.dest('./dist/vendor/fontawesome-free/webfonts'));
    // jQuery Easing
    var jqueryEasing = gulp.src('./node_modules/jquery.easing/*.js')
        .pipe(gulp.dest('./dist/vendor/jquery-easing'));
    // jQuery
    var jquery = gulp.src([
        './node_modules/jquery/dist/*',
        '!./node_modules/jquery/dist/core.js'
    ])
        .pipe(gulp.dest('./dist/vendor/jquery'));
    return merge(bootstrap, fontAwesomeCSS, fontAwesomeWebfonts, jquery, jqueryEasing);
}

// CSS task
function css() {
    return gulp
        .src("./res/scss/**/*.scss")
        .pipe(plumber())
        .pipe(sass({
            outputStyle: "expanded",
            includePaths: "./node_modules",
        }))
        .on("error", sass.logError)
        .pipe(autoprefixer({
            cascade: false
        }))
        .pipe(header(banner, {
            pkg: pkg
        }))
        .pipe(gulp.dest("./dist/css"))
        .pipe(rename({
            suffix: ".min"
        }))
        .pipe(cleanCSS())
        .pipe(gulp.dest("./dist/css"))
        .pipe(browsersync.stream());
}

// JS task
function js() {
    return gulp
        .src([
            './res/js/*.js',
            '!./res/js/*.min.js',
            '!./res/js/contact_me.js',
            '!./res/js/jqBootstrapValidation.js'
        ])
        .pipe(uglify())
        .pipe(header(banner, {
            pkg: pkg
        }))
        .pipe(rename({
            suffix: '.min'
        }))
        .pipe(gulp.dest('./dist/js'))
        .pipe(browsersync.stream());
}

function html() {
    return gulp
        .src(['index.html'])
        .pipe(fileinclude({
            prefix: '@@',
            basepath: '@file'
        }))
        .pipe(gulp.dest('./dist/'))
        .pipe(browsersync.stream());
}

// Watch files
function watchFiles() {
    gulp.watch("./res/scss/**/*", css);
    gulp.watch(["./res/js/**/*", "!./dist/js/**/*.min.js"], js);
    gulp.watch("./**/*.html", browserSyncReload);
}

// Define complex tasks
const vendor = gulp.series(clean, modules);
const build = gulp.series(vendor, gulp.parallel(css, js, html));
const watch = gulp.series(build, gulp.parallel(watchFiles, browserSync));

// Export tasks
exports.css = css;
exports.js = js;
exports.html = html;
exports.clean = clean;
exports.vendor = vendor;
exports.build = build;
exports.watch = watch;
exports.default = build;

Solution

  • BrowserSync is amazing but always seems tough to get it running the way you want! I endedup creating a little test projct to debug your gulpfile.js

    Here is a tested, working version of your code, notes below:

    'use strict';
    
    // Load plugins
    const autoprefixer = require('gulp-autoprefixer');
    const browserSync = require('browser-sync').create();
    const cleanCSS = require('gulp-clean-css');
    const del = require('del');
    const gulp = require('gulp');
    const header = require('gulp-header');
    const merge = require('merge-stream');
    const plumber = require('gulp-plumber');
    const rename = require('gulp-rename');
    const sass = require('gulp-sass');
    const uglify = require('gulp-uglify');
    const fileinclude = require('gulp-file-include');
    
    // Load package.json for banner
    const pkg = require('./package.json');
    
    // BrowserSync
    function server(done) {
        browserSync.init({
            server: {
                baseDir: './dist/'
            },
            port: 3000
        });
        done();
    }
    
    // server reload
    function browserSyncReload(done) {
      browserSync.reload();
      done();
    };
    
    // Clean vendor
    function clean() {
        return del(['./dist/vendor/']);
    }
    
    // Bring third party dependencies from node_modules into vendor directory
    function modules() {
        // Bootstrap
        var bootstrap = gulp.src('./node_modules/bootstrap/dist/**/*')
            .pipe(gulp.dest('./dist/vendor/bootstrap'));
        // Font Awesome CSS
        var fontAwesomeCSS = gulp.src('./node_modules/@fortawesome/fontawesome-free/css/**/*')
            .pipe(gulp.dest('./dist/vendor/fontawesome-free/css'));
        // Font Awesome Webfonts
        var fontAwesomeWebfonts = gulp.src('./node_modules/@fortawesome/fontawesome-free/webfonts/**/*')
            .pipe(gulp.dest('./dist/vendor/fontawesome-free/webfonts'));
        // jQuery Easing
        var jqueryEasing = gulp.src('./node_modules/jquery.easing/*.js')
            .pipe(gulp.dest('./dist/vendor/jquery-easing'));
        // jQuery
        var jquery = gulp.src([
            './node_modules/jquery/dist/*',
            '!./node_modules/jquery/dist/core.js'
        ])
            .pipe(gulp.dest('./dist/vendor/jquery'));
        return merge(bootstrap, fontAwesomeCSS, fontAwesomeWebfonts, jquery, jqueryEasing);
    }
    
    // CSS task
    function css() {
        return gulp
            .src('./res/scss/**/*.scss')
            .pipe(plumber())
            .pipe(sass({
                outputStyle: 'expanded',
                includePaths: './node_modules',
            }))
            .on('error', sass.logError)
            .pipe(autoprefixer({
                cascade: false
            }))
            .pipe(header(banner, {
                pkg: pkg
            }))
            .pipe(gulp.dest('./dist/css'))
            .pipe(rename({
                suffix: '.min'
            }))
            .pipe(cleanCSS())
            .pipe(gulp.dest('./dist/css'))
            .pipe(browserSync.stream({match: '**/*.css'}));
    }
    
    // JS task
    function js() {
        return gulp
            .src([
                './res/js/*.js',
                '!./res/js/*.min.js',
                '!./res/js/contact_me.js',
                '!./res/js/jqBootstrapValidation.js'
            ])
            .pipe(uglify())
            .pipe(header(banner, {
                pkg: pkg
            }))
            .pipe(rename({
                suffix: '.min'
            }))
            .pipe(gulp.dest('./dist/js'));
    }
    
    function html() {
        return gulp
            .src(['index.html'])
            .pipe(fileinclude({
                prefix: '@@',
                basepath: '@file'
            }))
            .pipe(gulp.dest('./dist/'));
    }
    
    // Watch files
    function watchFiles() {
        gulp.watch('./res/scss/**/*', css);
        gulp.watch(['./res/js/**/*', '!./dist/js/**/*.min.js'], gulp.series(js, browserSyncReload));
        gulp.watch(['./src/**/*.html', 'index.html'], gulp.series(html, browserSyncReload));
    }
    
    // Define complex tasks
    const vendor = gulp.series(clean, modules);
    const build = gulp.series(vendor, gulp.parallel(css, js, html));
    const watch = gulp.series(build, server, watchFiles);
    
    // Export tasks
    exports.css = css;
    exports.js = js;
    exports.html = html;
    exports.clean = clean;
    exports.vendor = vendor;
    exports.build = build;
    exports.watch = watch;
    exports.browserSyncReload = browserSyncReload;
    exports.server = server;
    exports.default = build;
    

    Only a couple of bits had to change to get this working:

    1. I think the main issue you were seeing was you weren’t recompiling the html on change, it was just reloading the browser. I’ve updated the watch html from: gulp.watch('./**/*.html', browserSyncReload); to: gulp.watch(['./src/**/*.html', 'index.html'], gulp.series(html, browserSyncReload));
    2. The stream is meant for injecting in code onto the page, so won’t work as you want for the html and js, so I’ve removed it from the tasks and replaced with a reload in the watch task.
    3. Exports for browserSyncReload and server were needed
    4. It seemed there was a race issue with watchFiles and browserSync when running in parallel, so they now run in series. ie: The server builds first, then the files are watched.

    Changes that weren’t required but happened along the way:

    1. Having a function named browserSync and const named browsersync was confusing me, so the function has been renamed to server and the const is now browserSync.
    2. My editor config set all your quotes to single, rather than a mix.
    3. I have set the stream in the css task to only match: '**/*.css'