Gulp中BrowserSync任务仅工作一次即卡住,如何修复?
Gulp + BrowserSync 二次修改后进程卡住问题解决
问题描述
使用Gulp搭建前端构建流程,已配置CSS/JS编译任务及文件监听,首次修改JS/SCSS文件时热重载正常,但第二次修改后整个进程卡住。
终端输出
λ gulp [14:28:47] Using gulpfile ~\OneDrive\Desktop\gulp\GulpLearning\gulpfile.js [14:28:47] Starting 'default'... [14:28:47] Starting 'style'... [14:28:47] Starting 'js'... [14:28:47] Starting 'browserSyncTask'... [14:28:47] Starting 'watch'... [Browsersync] 2 files changed (style.min.css.map, style.min.css) [14:28:47] Finished 'style' after 223 ms [Browsersync] 2 files changed (index.min.js.map, index.min.js) [Browsersync] Reloading Browsers... (buffered 2 events) [Browsersync] Access URLs: ------------------------------------- Local: http://localhost:3000 External: http://192.168.56.1:3000 ------------------------------------- UI: http://localhost:3001 UI External: http://localhost:3001 ------------------------------------- [Browsersync] Serving files from: ./
原代码
// Require packages (from package json) const gulp = require( 'gulp' ); const rename = require( 'gulp-rename' ); const sass = require('gulp-sass')(require('sass')); const autoprefixer = require('gulp-autoprefixer'); const sourcemaps = require('gulp-sourcemaps'); const browserify = require('browserify'); const babelify = require('babelify'); const source = require('vinyl-source-stream'); const buffer = require('vinyl-buffer'); const uglify = require('gulp-uglify'); const browserSync = require('browser-sync').create(); // CONSTS const styleSRC = 'src/scss/style.scss'; const styleDIST = './dist/css/'; const styleWATCH = 'src/scss/**/*.scss'; const jsSRC = 'index.js'; const jsFolder = 'src/js/'; const jsDIST = './dist/js/'; const jsWATCH = 'src/js/**/*.js'; const jsFiles = [jsSRC]; /** * Gulp task for compile,compress, * create source map and add autoprefixes * for styles. * @returns */ function style() { return gulp.src( styleSRC ) .pipe( sourcemaps.init() ) .pipe( sass({ errorLogToConsole: true, outputStyle: 'compressed', }) ) .on( 'error', console.error.bind( console ) ) .pipe( autoprefixer({ overrideBrowserslist: ['last 2 versions', '> 1%'], cascade: false }) ) .pipe( rename( { suffix: ".min" } ) ) .pipe( sourcemaps.write( './' ) ) .pipe( gulp.dest( styleDIST ) ) .pipe( browserSync.stream() ); } exports.style = style; /** * Gulp task for compile Javascripts * @returns */ function js( ){ return jsFiles.map(function ( entry ){ // 1. browserify return browserify({ entries: [jsFolder + entry], }) // 2. transform babelify [env] (env is set up in package.json) .transform( babelify, {presets: ['@babel/preset-env']} ) // 3. bundle .bundle() // 4. source .pipe( source( entry ) ) // 5. rename .min .pipe( rename( { extname: ".min.js" } ) ) // 6. buffer .pipe( buffer() ) // 7. sourcemap .pipe( sourcemaps.init({ loadMaps:true }) ) // 8. uglify .pipe( uglify() ) // 9. write sourcemaps .pipe( sourcemaps.write( './' ) ) // 10. dist .pipe( gulp.dest( jsDIST ) ) .pipe( browserSync.stream() ); }) } exports.js = js; /** * Task which start server and * apply hot-reload for changes in FE * @returns */ function browserSyncTask(){ return browserSync.init({ // This works only for localhost if we need specific URL we need specify further server: { baseDir: "./", }, injectChanges: false // Disable the injectChanges option }); } exports.browserSync = browserSyncTask; // Watch function for catch changes in files function watch(){ gulp.watch( styleWATCH, style ); gulp.watch( jsWATCH, js); } // Gulp default task for default command in console. ( gulp ) gulp.task('default', gulp.parallel([ style, js, browserSyncTask, watch, ]));
问题分析
- JS任务返回值错误:
js任务通过jsFiles.map返回了一个流数组,但Gulp任务要求返回单个流、Promise或回调函数。返回数组会导致Gulp无法正确跟踪任务完成状态,首次执行可能因异步时序侥幸成功,第二次修改时任务状态混乱引发进程卡住。 - BrowserSync初始化返回问题:
browserSync.init是异步启动服务器的方法,不需要返回值。返回它会让Gulp认为任务一直处于未完成状态,干扰后续任务触发逻辑。 - injectChanges配置不当:设置为
false会强制整页刷新而非注入变更,虽非核心问题,但可能加重任务阻塞风险。
解决方案
1. 安装merge-stream合并多流
首先安装merge-stream,用于将多个流合并为单个流:
npm install merge-stream --save-dev
2. 修改JS任务
引入merge-stream,合并流后返回:
const merge = require('merge-stream'); // 新增引入 function js() { const streams = jsFiles.map(function (entry) { return browserify({ entries: [jsFolder + entry], }) .transform(babelify, { presets: ['@babel/preset-env'] }) .bundle() .pipe(source(entry)) .pipe(rename({ extname: ".min.js" })) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) .pipe(uglify()) .pipe(sourcemaps.write('./')) .pipe(gulp.dest(jsDIST)) .pipe(browserSync.stream()); }); return merge(streams); // 合并流后返回 }
3. 调整BrowserSync任务
移除return,让Gulp正确识别任务完成:
function browserSyncTask() { browserSync.init({ server: { baseDir: "./", }, injectChanges: true // 开启注入式刷新,优化体验 }); }
4. 优化watch任务(可选)
给watch任务加上gulp.series,确保任务触发后正确通知Gulp:
function watch() { gulp.watch(styleWATCH, gulp.series(style)); gulp.watch(jsWATCH, gulp.series(js)); }
5. 修正default任务的parallel参数
gulp.parallel不需要传入数组,直接传任务函数即可:
gulp.task('default', gulp.parallel(style, js, browserSyncTask, watch));
修改后的完整代码
// Require packages (from package json) const gulp = require( 'gulp' ); const rename = require( 'gulp-rename' ); const sass = require('gulp-sass')(require('sass')); const autoprefixer = require('gulp-autoprefixer'); const sourcemaps = require('gulp-sourcemaps'); const browserify = require('browserify'); const babelify = require('babelify'); const source = require('vinyl-source-stream'); const buffer = require('vinyl-buffer'); const uglify = require('gulp-uglify'); const browserSync = require('browser-sync').create(); const merge = require('merge-stream'); // 新增 // CONSTS const styleSRC = 'src/scss/style.scss'; const styleDIST = './dist/css/'; const styleWATCH = 'src/scss/**/*.scss'; const jsSRC = 'index.js'; const jsFolder = 'src/js/'; const jsDIST = './dist/js/'; const jsWATCH = 'src/js/**/*.js'; const jsFiles = [jsSRC]; function style() { return gulp.src( styleSRC ) .pipe( sourcemaps.init() ) .pipe( sass({ errorLogToConsole: true, outputStyle: 'compressed', }) ) .on( 'error', console.error.bind( console ) ) .pipe( autoprefixer({ overrideBrowserslist: ['last 2 versions', '> 1%'], cascade: false }) ) .pipe( rename( { suffix: ".min" } ) ) .pipe( sourcemaps.write( './' ) ) .pipe( gulp.dest( styleDIST ) ) .pipe( browserSync.stream() ); } exports.style = style; function js() { const streams = jsFiles.map(function (entry) { return browserify({ entries: [jsFolder + entry], }) .transform(babelify, { presets: ['@babel/preset-env'] }) .bundle() .pipe(source(entry)) .pipe(rename({ extname: ".min.js" })) .pipe(buffer()) .pipe(sourcemaps.init({ loadMaps: true })) .pipe(uglify()) .pipe(sourcemaps.write('./')) .pipe(gulp.dest(jsDIST)) .pipe(browserSync.stream()); }); return merge(streams); } exports.js = js; function browserSyncTask() { browserSync.init({ server: { baseDir: "./", }, injectChanges: true }); } exports.browserSync = browserSyncTask; function watch() { gulp.watch(styleWATCH, gulp.series(style)); gulp.watch(jsWATCH, gulp.series(js)); } gulp.task('default', gulp.parallel(style, js, browserSyncTask, watch));
验证
执行gulp命令后,多次修改JS/SCSS文件,进程不会再卡住,热重载功能正常工作。
内容的提问来源于stack exchange,提问作者Young L.
相关产品推荐
相关产品推荐

