修改部分时Gulp重新生成父js文件

uqzxnwby  于 2022-12-08  发布在  Gulp
关注(0)|答案(2)|浏览(176)

I have the following gulp task for my js files:

gulp.task("js", () => {
  return gulp
    .src([
      src_js_folder + "*.js",
      src_js_folder + "**/*.js" // Include partial js files, to trigger the build when there is a change in them
    ], { since: gulp.lastRun("js"), read: false }) // no need of reading file because browserify does.
    .pipe(dependents())
    .pipe(filter(['**'].concat( // filter partial js files (inside subdirectories)
      readdirSync(src_js_folder, { withFileTypes: true }) // list all js files inside subdirectories
      .filter(dirent => dirent.isDirectory())
      .map(dirent => `!${src_js_folder.substring(2) + dirent.name}/**/*.js`)
    )))
    .pipe(plumber({errorHandler: reportError}))
    .pipe(tap(function (file) {
      logger.info('bundling ' + file.path);
      // replace file contents with browserify's bundle stream
      file.contents = browserify(file.path, {debug: true})
        .bundle();
    }))
    .pipe(buffer()) // transform streaming contents into buffer contents (because gulp-sourcemaps does not support streaming contents)
    .pipe(beautify.js({ indent_size: 2 }))
    .pipe(gulp.dest(dist_folder + "js"))
    .pipe(browserSync.stream());
});

And this watcher for browserSync:

gulp.watch([src_js_folder + '**/*.js'], gulp.series("dev")).on("change", browserSync.reload);

So what I did in my task is I included the partial js files in the src as well, and then filter them to not build them.
The problem I'm having is that when I update a parent js file that includes these partials gulp is rebuilding them, but when I change something in the partials, gulp doesn't build the parent js files that include these partials.
for example if I change the following file: src_js_folder + 'somefile.js' , gulp successfully rebuild the file:

[16:27:34] Starting 'js'...
[16:27:34] bundling ...\www-src\assets\scripts\global.V3-1.js
[Browsersync] 1 file changed (global.V3-1.js)
[16:27:34] Finished 'js' after 597 ms

But when I change something in the partial js file, for example: src_js_folder + '/subdir/_somePartialFile.js' , gulp does nothing:

[16:29:21] Starting 'js'...
[16:29:21] Finished 'js' after 10 ms

The logic I followed in my task is the same as my sass task:

gulp.task("sass", () => {
  return (
    gulp.src([
        src_sass_folder + "*.scss",
        src_sass_folder + "**/*.scss"
      ], {
        since: gulp.lastRun("sass"),
      })
      .pipe(dependents())
      .pipe(filter(['**'].concat( // filter partial SASS files (inside subdirectories) this is used to not build the partial SASS files
        readdirSync(src_sass_folder, { withFileTypes: true }) // selector for all partial SASS files
        .filter(dirent => dirent.isDirectory())
        .map(dirent => `!${src_sass_folder.substring(2) + dirent.name}/**/*.scss`)
      )))
      .pipe(debug({title: "sass-debug:", showCount: false}))
      .pipe(sourcemaps.init())
      .pipe(plumber({errorHandler: reportError}))
      .pipe(sass({ fiber: Fiber })) // call asynchronous importers from the synchronous code path (for using Dart Sass)
      .pipe(autoprefixer())
      .pipe(minifyCss({debug: true}, (details) => {
        console.log(`Original size: ${details.stats.originalSize}, Minified size: ${details.stats.minifiedSize}, Efficiency: ${details.stats.efficiency}`);
      }))
      .pipe(sourcemaps.write("."))
      .pipe(gulp.dest(dist_folder + "Content"), {overwrite: true})
      .pipe(browserSync.stream({match: '**/*.css'}))
  );
});

gulp.watch([src_sass_folder + '**/*.scss'], gulp.series("sass"));

This is successfully working when I change something in the partial sass files, because when a partial sass file changes, gulp only builds the sass files that include them.
How can I make my js task work properly?

Edit:

My parent js files are looking like this:

bundle = require('./subdir/_partial1.js');
bundle = require('./subdir/_partial2.js');
bundle = require('./subdir/_partial3.js');
8cdiaqws

8cdiaqws1#

我能够使用gulp-dependents来设置JS(ES6)增量构建。
为此,我不得不编写正则表达式来从import语句中提取文件路径,幸运的是,我找到了一个GitHub Gist,它有所需的正则表达式。下面是解析JS import语句的gulp-dependents配置:

const jsDependentsConfig = {
    ".js":{
        postfixes: ['.js'],
        parserSteps: [
            /import(?:["'\s]*(?:[\w*${}\n\r\t, ]+)from\s*)?["'\s]*(.*[@\w_-]+)["'\s].*;?$/gm,
            function(path){
                // Remove file extension, if any
                path = path.replace(/\.js$/,'');

                // Local packages
                paths = [`${path}/index.js`,`${path}.js`];

                return paths;
            },
        ]
    },
};

一旦实现了这一点,使用吞咽依赖就相当简单了。

最终代码:

const { src, dest, lastRun } = require('gulp');
const dependents = require('gulp-dependents');
const filter = require('gulp-filter');

const jsDependentsConfig = {
    ".js":{
        postfixes: ['.js'],
        parserSteps: [
            /import(?:["'\s]*(?:[\w*${}\n\r\t, ]+)from\s*)?["'\s]*(.*[@\w_-]+)["'\s].*;?$/gm,
            function(path){
                // Remove file extension, if any
                path = path.replace(/\.js$/,'');

                // Local packages
                paths = [`${path}/index.js`,`${path}.js`];

                return paths;
            },
        ]
    },
};

function scripts(){
    // Ref: https://stackoverflow.com/a/35413106
    const filterPartials = filter([
        `**/src/js/**/!(_)*.js`, // select all js files
        `!**/src/js/**/_*/`, // exclude all folder starting with _
        `!**/src/js/**/_*/**/*` //exclude files/subfolders in folders starting with '_'
    ]);

    return src('src/js/**/*.js',{ since: lastRun(scripts) })
       .pipe(gulpIf(!Config.production,
           dependents(jsDependentsConfig)
       ))
       .pipe(filterPartials)
       // other pipes
       .pipe(dest('assets/js'))
    ;
}
envsm3lx

envsm3lx2#

dependentsgulp-dependents吗?
默认情况下,gulp-dependents不支持.js文件。
当“partial sass file”发生变化时,gulp-dependents通过之前缓存的dependencyMap添加“parent sass file”,然后filter删除“partial sass file”,将“parent sass file”传递给gulp-sass
当“partial js file”被更改时,gulp-dependents不添加任何文件。然后filter删除“partial js file”。最后没有文件。
按浏览器化管道缓存依赖项。

function DependentsJS () {
  const fileDepMap = new Map()

  return {
    browserify (filePath, opts) {
      for (let deps of fileDepMap) {
        deps[1].delete(filePath)
      }

      const b = browserify(filePath, opts)
      b.pipeline.on('file', function (file) {
        if (!fileDepMap.has(file)) {
          fileDepMap.set(file, new Set())
        }

        fileDepMap.get(file).add(filePath)
      })

      return b
    },
    plugin: () => through.obj(function (file, encoding, callback) {
      this.push(file)
  
      if (fileDepMap.has(file.path)) {
        fileDepMap.get(file.path).forEach(pFile => {
          this.push({
            cwd: file.cwd,
            path: pFile
          })
        });
      }
      callback();
    }, function (callback) {
      callback()
    })
  }
}

用途:

const dependentsJS = DependentsJS()

gulp.task("js", () => {
  return gulp
    .src([
      src_js_folder + "*.js",
      src_js_folder + "**/*.js"
    ], { since: gulp.lastRun("js"), read: false })
    // .pipe(dependents())
    .pipe(dependentsJS.plugin()) // <<< USE `dependentsJS.plugin()`
    .pipe(filter(['**'].concat(
      readdirSync(src_js_folder, { withFileTypes: true })
      .filter(dirent => dirent.isDirectory())
      .map(dirent => `!${src_js_folder.substring(2) + dirent.name}/**/*.js`)
    )))
    .pipe(plumber({errorHandler: reportError}))
    .pipe(tap(function (file) {
      logger.info('bundling ' + file.path);
      // file.contents = browserify(file.path, {debug: true})
      file.contents = dependentsJS.browserify(file.path, {debug: true}) // <<< USE `dependentsJS.browserify`
        .bundle();
    }))
    .pipe(buffer())
    .pipe(beautify.js({ indent_size: 2 }))
    .pipe(gulp.dest(dist_folder + "js"))
    .pipe(browserSync.stream());
});

相关问题