【问题标题】:Grunt: How to run a function and then a task and then another function, sequentially, when the functions can not be split in to different tasks?Grunt:当函数不能被拆分成不同的任务时,如何依次运行一个函数、一个任务和另一个函数?
【发布时间】:2017-11-18 20:11:57
【问题描述】:

我正在使用 Grunt 生成构建。我是 Grunt、javascript 和 nodejs 的新手,因此欢迎任何新的观点。

我的 Gruntfile 中的一些任务依赖于插件(例如 'uglify' 用于 javascript 缩小),而还有一些其他工作流最适合只编写 javascript 函数本身。

我经常遇到需要执行以下操作的情况:(1) 执行一个 javascript 函数 (2) 在该函数之后立即运行一个 grunt 任务 (3) 执行另一个 javascript 函数。它需要按这个顺序发生。然而,由于 Grunt 只是一个任务调度程序,它最终会运行 (1)、排队 (2)、运行 (3),然后运行 ​​(2) 作为最后一步,在 (1) 和 (3) 完成之后。

以下是假设自定义任务的一个非常简单的用例,以更好地解释情况。

grunt.task.registerTask('minifyJS', function() {

    jsFilepathMapping = configureUglifiy();
    /** note - configureUglify is needed because the minification filepaths
        are generated on the fly, I do not know them before the script runs
        and more than that, there are so many that it would be really bulky
        to create init targets for each single minification file that needs
        to be generated.*/

    grunt.task.run('uglify');

    updateJsScriptTags(jsFilepathMapping); // update the <script> tags in my HTML

});

问题是我需要按照上面显示的顺序运行这些东西。 然而,由于 grunt 是一个任务调度器,当这个任务运行时会发生以下情况

  1. configureUglify() 函数将运行
  2. 'uglify' 将被排队 - 不运行。
  3. updateJsScriptTags() 函数将RUN
  4. 现在默认任务已经完成 - 现在才会“丑化”,它已排队运行

现在,我明白为什么会这样了。 Grunt 是一个任务调度程序——任务正在排队。这是有道理的,而不是抱怨它。 相反,我问的是解决这个问题的方法是什么?这样我在使用这种功能和任务的组合时就可以实现这种排序?我想这一定是超级简单和普遍的,我只是不知道它是什么!

我意识到的一个选择是将这些功能中的每一个转换为任务本身。但是,问题在于 configureUglifiy() 返回一个复杂的数据结构,然后 updateJsScriptTags() 会使用该结构。除了使用 'options' 属性之外,似乎没有一种在 Grunt 任务之间共享数据的好方法,该属性仅在任务本身中可用。我想我可以这样做,但是,我在这里担心的是这会使事情变得不可读并且......有点危险,因为你现在有这个任务,它依赖于在另一个任务期间修改的数据结构,而且它不是立即很明显,直到你开始挖掘函数。

让我举个例子。哪个更适合你?

/** 
    documentation which defines what the argment filepathMapping is

    Furthermore, since the function takes an argument, the context is
    immediately clearer just looking at the function declaration.
*/
function updateJsScriptTags(filepathMapping) {

    // do stuff ...
    for ( key in filepathMapping ) { // oh cool!  i know what this arg does, my documentation nicely explains it, and its structure too
         // lots of stuff
    }
}

...
// and elsewhere in the script, where it's being invoked:

var aMapping = someFunc();
updateJsScriptTags(aMapping);

对比

grunt.task.registerTask('updateJsScriptTags', 'update js tags', function() {

   // do stuff.
   ...

    // many lines later:
    grunt.options('filepathMapping') // Oh, what is this attribute?  Let me go look around the rest of the script to find out where it comes from

}

...
// and ultimately, where it's being invoked.
grunt.task.run('someTask'); // global options param gets modified somewhere in here, but you'd never know it looking at this line of code
grunt.task.run('updateJsScriptTags'); // this task will depend on that modification

我发现这让事情变得更不可读,而不是一个简单的函数,它接受要使用的参数,并且可以强加一个特定的结构。如果我在一个任务中修改一些全局参数中的一堆属性,这些属性稍后会在另一个任务中被消耗掉,这似乎也更容易让事情变得错误。更麻烦的是,共享的属性名称是硬编码的。我知道这是一个非常简单的用例,但开始想象一组更复杂的函数,它们依赖于可能是复杂数据类型的多个参数,并且是我关心的地方。

简单总结一下:是否有替代方法可以实现函数/插件任务/函数/插件任务的顺序排列,而不需要将函数本身转换为自定义任务? p>

【问题讨论】:

    标签: javascript node.js gruntjs scheduled-tasks


    【解决方案1】:

    所以作为一个快速总结:是否有替代方法可以实现函数/插件任务/函数/插件任务的顺序排序,而无需将函数本身转换为自定义任务?

    简答:不,要保持执行顺序,您需要使用 grunt 任务而不是普通的 JavaScript 函数来定义顺序。

    taskList数组中定义的每个alias-task的顺序进行顺序排序。例如使用grunt.registerTask时:

    grunt.registerTask('foo', [ 'a', 'b', 'c' ]);
    

    鉴于上面的伪示例并运行foo 任务将首先运行任务a,然后是任务b,依此类推(即任务b 直到任务a 才会运行完成;任务c 在任务b 完成之前不会运行)

    但这并不意味着不能将纯 JavaScript 函数与 grunt custom Tasks 结合使用。


    详细解答:

    似乎没有一种在 Grunt 任务之间共享数据的好方法...

    您可以使用Object 来存储数据。第一个示例中的伪代码暗示您希望 configureUglifiy 函数:

    1. 动态配置Uglify任务
    2. 返回由configureUglifiy 自身生成的数据(Object)。
    3. 然后将返回的数据作为参数传递给updateJsScriptTags 函数。

    因此,不要从 configureUglifiy 函数返回 Object。您可以将其存储在另一个Object 中,然后在updateJsScriptTags 函数中对其进行访问。

    在以下要点中,请注意 shared 对象,其属性/键名为 jsFilepathMapping。我们将使用这个对象来存储可以在另一个任务中访问的动态生成的数据。

    Gruntfile.js (伪代码)

    module.exports = function (grunt) {
    
      'use strict';
    
      var shared = {
        jsFilepathMapping: {} // <-- Intentionally empty. The object will
                              //     be defined via `configureUglify` function,
                              //     and consumed by `updateJsScriptTags` Task.
      };
    
      grunt.initConfig({
        uglify: {
          // <-- Intentionally empty, will be dynamically generated.
        }
      });
    
      //---------------------------------------------------------------------------
      // Functions
      //---------------------------------------------------------------------------
    
      /**
       * Helper function to dynamically configure the uglify task.
       */
      function configureUglify() {
    
        // <-- Do stuff here to determine configuration of uglify task.
    
        grunt.config('uglify', config);
    
        // Store object (for referencing later) instead of returning.
        shared.jsFilepathMapping = config;
      };
    
      /**
       * Helper function to update the js script tags in html.
       */
      function updateJsScriptTags(filepathMapping) {
    
        // `filepathMapping` object now available in this function.
        for ( var key in filepathMapping ) {
          console.log(filepathMapping[key])
        }
      }
    
      //---------------------------------------------------------------------------
      // Tasks
      //---------------------------------------------------------------------------
    
      grunt.task.registerTask('updateJsScriptTags', 'Updates tags', function () {
    
        // Invoke the function passing in the values which were previously
        // ascertained and set via the `configureUglify` function.
        updateJsScriptTags(shared.jsFilepathMapping)
      });
    
      grunt.task.registerTask('minifyJS', function() {
        configureUglify();
        grunt.task.run(['uglify']);
      });
    
      grunt.loadNpmTasks('grunt-contrib-uglify');
    
      // Define sequential ordering of each Task in the taskList Array.
      grunt.registerTask('default', ['minifyJS', 'updateJsScriptTags']);
    };
    

    注意注释为 // &lt;-- Do stuff here to determine configuration of uglify task. 的逻辑类似于我提供给您的其他问题 hereGruntfile.js 要点。


    总结

    1. 应通过将任务添加到TaskList 数组来定义顺序排序(根据上面的简短回答部分)
    2. 必要时可以通过 grunt 自定义任务调用函数。但是请记住,自定义任务是一个函数,因此只有在真正需要时才将逻辑分离到它自己的函数中。你会发现你的 Gruntfile.js 读起来更好。
    3. 当一个任务/函数动态获取数据以在其他任务/函数之间共享时,请考虑将其存储在 Object 中,而不是使用 return 关键字从函数返回值。

    4. 在可能的情况下,将逻辑分成单独定义的任务,并尽量避免在一个任务中做太多事情。例如,在您在名为minifyJS 的问题中提供的第一个自定义任务中,您试图在一个任务中做两件事。 IE。您正在配置和运行 uglify 任务(构成一个任务),并更新 JS 脚本标签(构成另一个任务)。理想情况下,这应该是两个独立的不同任务。

    我提供的伪Gruntfile.js(上面)它目前没有采用我在第 2 点和第 4 点中给出的建议。通过一些重构,Gruntfile.js 将更像这样(注意函数不再存在,而是它们的逻辑已与调用它们的自定义任务相结合):

    Gruntfile.js (伪代码重构)

    module.exports = function (grunt) {
    
      'use strict';
    
      var shared = {
        jsFilepathMapping: {} // <-- Intentionally empty. The object will
                              //     be defined via `minifyJS` Task,
                              //     and consumed by `updateJsScriptTags` Task.
      };
    
      grunt.initConfig({
        uglify: {
          // <-- Intentionally empty, will be dynamically generated.
        }
      });
    
      //---------------------------------------------------------------------------
      // Tasks
      //---------------------------------------------------------------------------
    
      grunt.task.registerTask('updateJsScriptTags', 'Updates tags', function () {
    
        // `filepathMapping` object now available in this task.
        for ( var key in shared.jsFilepathMapping ) {
          console.log(shared.jsFilepathMapping[key])
        }
      });
    
      grunt.task.registerTask('minifyJS', function() {
    
        // <-- Do stuff here to determine configuration of uglify task.
    
        // Save object (for referencing later) instead of returning.
        shared.jsFilepathMapping = config;
    
        grunt.config('uglify', config);
        grunt.task.run(['uglify']);
      });
    
      grunt.loadNpmTasks('grunt-contrib-uglify');
    
      // Define sequential ordering of each Task in the taskList Array.
      grunt.registerTask('default', ['minifyJS', 'updateJsScriptTags']);
    };
    

    【讨论】:

      猜你喜欢
      • 2019-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多