Skip to content

Incremental build does not update streamed file contents #30

Description

@lkubb

First of all, thanks for writing/maintaining this handy plugin!

I tried implementing the incremental build/watch setup described in https://github.com/ym-project/gulp-esbuild/blob/v0/examples/watch/gulpfile.js. However, while the file is rebuilt, esbuild still operates with the initial file contents of streamed files, meaning the bundled file's contents are exactly the same as during the first iteration.

I looked into this behavior and it seems the new stream contents are discarded when a context has already been initialized:

params contains a plugin that returns the (updated) file contents:

gulp-esbuild/index.js

Lines 121 to 124 in c5a65ee

plugins: [
resolvePlugin(entryPoints),
...(esbuildOptions.plugins || []),
],

It is never actually passed to esbuild though (likely since rebuild is intended to run repeatedly with the same options):

gulp-esbuild/index.js

Lines 135 to 138 in c5a65ee

// if it's the first build
if (!ctx) {
ctx = await context(params)
}

I was able to fix this issue via the following patch:

diff --git i/index.js w/index.js
index 0095fae..f2216f1 100644
--- i/index.js
+++ w/index.js
@@ -25,8 +25,12 @@ function createTransformStream(flushFn, entryPoints) {
 			if (!file.isBuffer()) {
 				return cb(createError(new TypeError('File should be a buffer')))
 			}
-
-			entryPoints.push(file)
+			const fileIndex = entryPoints.findIndex((cfile) => cfile.path === file.path);
+			if (fileIndex >= 0) {
+				entryPoints[fileIndex] = file
+			} else {
+				entryPoints.push(file)
+			}
 			cb(null)
 		},
 		flush: flushFn,
@@ -106,10 +110,10 @@ function simpleBuild() {
 
 function incrementalBuild() {
 	let ctx
+	/** @type Array<import('vinyl').BufferFile> */
+	const entryPoints = []
 
 	return function plugin(pluginOptions = {}) {
-		/** @type Array<import('vinyl').BufferFile> */
-		const entryPoints = []
 		const {metafileName, esbuildOptions} = splitOptions(pluginOptions)
 
 		async function flushFunction(cb) {
For reference, this is a trimmed-down version of my gulpfile.js:
const browserSync = require("browser-sync").create();
const { src, dest, watch, series, parallel } = require("gulp");
const gulpEsbuild = require("gulp-esbuild");
const incrementalGulpEsbuild = gulpEsbuild.createGulpEsbuild({
  incremental: true,
});
const options = {
  config: {
    port: 9050,
  },
  paths: {
    src: {
      base: './src',
      js: './src/js',
    },
    dist: {
      base: './dist',
      js: './dist/js',
    },
  }
}

function livePreview(done) {
  browserSync.init({
    server: {
      baseDir: options.paths.dist.base,
    },
    port: options.config.port || 5000,
  });
  done();
}

function previewReload(done) {
  browserSync.reload();
  done();
}

function devScripts() {
  return src(`${options.paths.src.js}/main.js`)
    .pipe(
      incrementalGulpEsbuild({
        outfile: "app.js",
        bundle: true,
        target: "es2015",
        platform: "browser",
      })
    )
    .pipe(dest(options.paths.dist.js));
}

function watchFiles() {
  // ...
  watch(`${options.paths.src.js}/**/*.js`, series(devScripts, previewReload));
  // ...
}


exports.default = series(
  // ...
  parallel(
    devScripts,
    // ...
  ),
  livePreview,
  watchFiles
);

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions