gpt4 book ai didi

javascript - 合并的 gulp 任务从不触发 `end` 事件

转载 作者:搜寻专家 更新时间:2023-10-31 23:15:04 24 4
gpt4 key购买 nike

我有一个 gulp 任务,它循环遍历一个文件夹以查找子文件夹,并根据每个文件夹的内容输出一个 JavaScript 文件。下面是一个更直观的示例。

  • 来源
    • Assets
      • 脚本
        • 关键
          • loadCSS.init.js
        • 遗产
          • flexibility.init.js
          • picturefill.init.js
        • 现代的
          • connectivity.js
          • layzr.init.js
          • menu_list.js
          • 滚动提示.init.js
          • slideout.init.js
          • swiper.init.js
        • 服务人员
          • service-worker.js

变成:

  • 开发
    • Assets
      • 脚本
        • critical.js
        • legacy.js
        • 现代.js
        • service-worker.js

这是通过读取 src/assets/scripts 目录的内容,然后对每个文件夹(criticallegacy)运行一个循环来实现的>, modern, service-worker) 并将每个文件夹的内容发送到与 merge-stream 合并在一起的 Gulp 任务.

所有这一切都很好,除了一旦任务重新合并在一起,我想在编译成功时触发通知。如果我尝试将任何内容通过管道传输到合并的流中,那是行不通的。它只返回合并的流,并且永远不会继续。

如果我取消 promise 我的 PROCESS_SCRIPTS 函数并且不使用合并流(即只处理一个手动指定的文件夹),它工作正常,所以我不知道是什么继续。

这是我的完整任务:

module.exports = {
scripts(gulp, plugins, ran_tasks, on_error) {
// task-specific plugins
const ESLINT = require("gulp-eslint");
const WEBPACK = require("webpack-stream");

// process scripts
const PROCESS_SCRIPTS = (js_directory, destination_file_name = "modern.js", compare_file_name = "modern.js", source = [global.settings.paths.src + "/assets/scripts/*.js"]) => {
return new Promise((resolve, reject) => {
const WEBPACK_CONFIG = {
mode: "development",
};

// update webpack config for the current target destination and file name
WEBPACK_CONFIG.mode = plugins.argv.dist ? "production" : WEBPACK_CONFIG.mode;
WEBPACK_CONFIG.output = {
filename: destination_file_name
};

const TASK = gulp.src(source)
// prevent breaking on error
.pipe(plugins.plumber({errorHandler: on_error}))
// check if source is newer than destination
.pipe(plugins.newer(js_directory + "/" + compare_file_name))
// lint all scripts
.pipe(ESLINT())
// print lint errors
.pipe(ESLINT.format())
// run webpack
.pipe(WEBPACK(WEBPACK_CONFIG))
// generate a hash and add it to the file name
.pipe(plugins.hash({template: "<%= name %>.<%= hash %><%= ext %>"}))
// output scripts to compiled directory
.pipe(gulp.dest(js_directory))
// generate a hash manfiest
.pipe(plugins.hash.manifest(".hashmanifest-scripts", {
deleteOld: true,
sourceDir: js_directory
}))
// output hash manifest in root
.pipe(gulp.dest("."))
// reject after errors
.on("error", () => {
reject(TASK);
})
// return the task after completion
.on("end", () => {
resolve(TASK);
});
});
};

// scripts task, lints, concatenates, & compresses JS
return new Promise ((resolve) => {
// set JS directory
const JS_DIRECTORY = plugins.argv.dist ? global.settings.paths.dist + "/assets/scripts" : global.settings.paths.dev + "/assets/scripts";

// set the source directory
const SOURCE_DIRECTORY = global.settings.paths.src + "/assets/scripts";

// set up an empty merged stream
const MERGED_STREAMS = plugins.merge();
// get the script source folder list
const SCRIPT_FOLDERS = plugins.fs.readdirSync(SOURCE_DIRECTORY);
// get the script destination file list
const SCRIPT_FILES = plugins.fs.existsSync(JS_DIRECTORY) ? plugins.fs.readdirSync(JS_DIRECTORY) : false;

// process all the script folders
const PROCESS_SCRIPT_FOLDERS = () => {
return Promise.resolve().then(() => {
// shift to the next folder
const FOLDER_NAME = SCRIPT_FOLDERS.shift();

// find the existing destination script file name
const FILE_NAME = SCRIPT_FILES ? SCRIPT_FILES.find((name) => {
return name.match(new RegExp(FOLDER_NAME + ".[a-z0-9]{8}.js"));
}) : FOLDER_NAME + ".js";

// process all scripts, update the stream
return PROCESS_SCRIPTS(JS_DIRECTORY, FOLDER_NAME + ".js", FILE_NAME, SOURCE_DIRECTORY + "/" + FOLDER_NAME + "/**/*").then((processed) => {
MERGED_STREAMS.add(processed);
});
}).then(() => SCRIPT_FOLDERS.length > 0 ? PROCESS_SCRIPT_FOLDERS() : resolve());
};

PROCESS_SCRIPT_FOLDERS().then(() => {
// wrap up
return MERGED_STREAMS
// prevent breaking on error
.pipe(plugins.plumber({
errorHandler: on_error,
}))
// notify that task is complete, if not part of default or watch
.pipe(plugins.gulpif(gulp.seq.indexOf("scripts") > gulp.seq.indexOf("default"), plugins.notify({
title: "Success!",
message: "Scripts task complete!",
onLast: true,
})))
// push task to ran_tasks array
.on("data", () => {
if (ran_tasks.indexOf("scripts") < 0) {
ran_tasks.push("scripts");
}
})
// resolve the promise on end
.on("end", () => {
resolve();
});
});

});
}
};

在我的 GitHub 上也可见:https://github.com/JacobDB/new-site/blob/master/gulp-tasks/scripts.js


编辑:我已经尝试了一些东西,我会在这里详细说明。

  1. console.log("hello world") 永远不会在 MERGED_STREAMS.on("data")MERGED_STREAMS.on("error"),或 MERGED_STREAMS.on("end")
  2. const MERGED_STREAMS = plugins.merge(); 移动到模块级变量(即紧接在 const WEBPACK = require("webpack-stream") 之后)不会改变结果。
  3. 执行 #2 然后使用 MERGED_STREAMS.add(gulp.src(source) ...) 而不是在 promise 完成后添加流不会改变结果,除非离开 .pipe(gulp.dist(".")),它需要输出一个.hashmanifest,并且始终将任务标记为已运行。
  4. 禁用 webpackhasheslint 的任何组合都不会产生任何影响。
  5. PROCESS_SCRIPTS 从返回 promise 更改为返回流,然后将每个文件夹作为单独的变量处理,然后手动合并它们似乎确实正确地触发了运行的任务,但是 webpack 只能运行一次,所以它只输出一个文件——critical.hash.js注意:我没有在禁用 hash 的情况下测试此方法,如果始终输出 .hashmanifest,这可能会导致它被标记为正确运行.
  6. 将 linting 步骤和 webpack 步骤拆分为单独的任务 kind of 导致任务被正确标记为已运行,但前提是 lint 任务不是promise,这会导致控制台出现 unexpected end of stream 错误。

编辑 2:根据@Louis 的建议更新了我的任务的修订版本。

最佳答案

上面的代码有很多问题。使代码难以跟踪和调试的一个主要问题是您在不需要的地方使用了 new Promise通常,如果您有新的 Promise,并且 promise 执行器中的逻辑将根据另一个 promise 的结果解决或拒绝,那么您不需要使用 新的 Promise

有时人们会有这样的代码:

function foo() {
const a = getValueSynchronously();
const b = getOtherValueSynchronously();
return doSomethingAsynchronous(a, b).then(x => x.someMethod());
}

假设 doSomethigAsynchronous 返回一个 promise 。上面的 foo 函数的问题在于,如果 getValueSynchronouslygetOtherValueSynchronously 失败,那么 foo 将引发异常,但是如果 doSomethingAsynchronous 失败,那么它将拒绝 promise 。所以使用 foo 的代码必须处理同步异常异步拒绝,如果它想处理所有可能的失败。有时人们觉得他们可以通过将所有失败都变成 promise 拒绝来解决问题:

function foo() {
return new Promise((resolve, reject) => {
const a = getValueSynchronously();
const b = getOtherValueSynchronously();
doSomethingAsynchronous(a, b).then(x => x.someMethod()).then(resolve, reject);
});
}

在上面的代码中,如果 getValueSynchronouslygetOtherValueSynchronously 失败,那就是 promise 拒绝。但是上面代码的问题是很容易出错。您可以忘记在需要的地方调用 reject。 (事实上​​ ,您的代码中确实有此错误。您有嵌套的 promise ,其拒绝不会向上传播。它们只是丢失,这意味着如果发生错误你的代码会在你不知道原因的情况下停止。)或者你可能想在嵌套函数中调用 `resolve 方法,这使得逻辑难以遵循。

你也可以这样做:

function foo() {
return Promise.resolve().then(() => {
const a = getValueSynchronously();
const b = getOtherValueSynchronously();
return doSomethingAsynchronous(a, b);
}).then(x => x.someMethod());
}

您可以使用 Promise.resolve() 进入应许的世界(嗯……“应许之地?”)。在上面的代码中,您不必记住调用 reject。如果 .then 回调中的代码出于任何原因失败,您将得到一个被拒绝的 promise 。

我还注意到,在许多地方,您从传递给 new Promise 的执行程序函数中返回了一个值。如果您不在那里使用 return,您的代码将表现得完全相同。为了说明这一点,这段代码:

function foo() {
return new Promise((resolve, reject) => {
return doSomethingAsynchronous().then(resolve, reject);
});
}

与此代码的行为完全相同:

function foo() {
return new Promise((resolve, reject) => {
doSomethingAsynchronous().then(resolve, reject);
});
}

从执行器返回的值被忽略。故事结局。如果您认为从执行程序返回的值正在做某事,那是不正确的。

关于javascript - 合并的 gulp 任务从不触发 `end` 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52613825/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com