G运行t:如何按顺序 运行 一个函数,然后是一个任务,然后是另一个函数,当函数不能拆分到不同的任务时?
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?
我正在使用 G运行t 生成构建。我是 G运行t、javascript 和 nodejs 的新手,欢迎任何新观点。
我的 G运行tfile 中的一些任务依赖于插件(例如 'uglify' 用于 javascript 缩小),而还有一些其他工作流程最适合仅编写 javascript 函数本身。
我一直处于 运行ning 我需要执行以下操作的情况:(1) 执行一个 javascript 函数 (2) 运行 a g运行t在该函数 (3) 之后立即执行另一个 javascript 函数。它需要按照这个顺序发生。然而,由于 G运行t 只是一个任务调度器,它最终会 运行ning (1),排队 (2),运行ning (3),然后 运行ning (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
});
问题是我需要按照上面显示的顺序运行这些东西。
但是,由于 g运行t 是一个任务调度程序,因此当此任务为 运行
时,会发生以下情况
- configureUglify() 函数将 运行.
- 'uglify' 将 排队 - 不是 运行.
- updateJsScriptTags() 函数将 运行.
- 现在默认任务已经完成 - 只是现在排队的 'uglify' 将 运行.
现在,我明白为什么会这样了。 G运行t 是一个任务调度程序——任务正在排队。这是有道理的,而不是抱怨它。 相反,我想问的是解决这个问题的方法是什么?这样我就可以在使用这种功能和任务的组合时实现这种排序?我想这一定是超级简单和通用的,我只是不知道它是什么!
我意识到的一个选择 是将这些函数中的每一个转换为任务本身。然而,这个问题是 configureUglifiy() returns 一个复杂的数据结构,updateJsScriptTags() 然后使用它。除了使用 'options' 属性外,似乎没有在 G运行t 任务之间共享数据的好方法,该属性仅在任务本身内可用。我想我可以这样做,但是,我担心的是这会使事情变得不可读并且......有点危险,因为你现在有这个任务,它依赖于在另一个任务期间修改的数据结构,而且不是立即显而易见,直到您开始深入研究该功能。
我举个例子。哪个对您来说更具可读性?
/**
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
我发现这让事情变得更难读,而不是一个简单的函数,它接受要使用的参数,并可以强加一个特定的结构。事情似乎也更容易以另一种方式出现问题,即我在一个任务中修改某些全局参数中的一堆属性,这些属性稍后会在另一个任务中使用。更麻烦的是,属性名称是共享的,是硬编码的。我知道这是一个非常简单的用例,但开始想象一组更复杂的函数,这些函数依赖于可能是复杂数据类型的多个参数,并且这是我关心的地方。
所以作为一个快速总结:是否有替代方法来实现 function/plugin-task/function/plugin-task 的顺序排序,而不求助于将函数本身转换为自定义任务?
So as a quick summary: are there alternatives to achieving a sequential ordering of function/plugin-task/function/plugin-task, without resorting to converting the functions to custom tasks themselves?
简短回答: 不,要保持执行顺序,您需要使用 g运行t 任务而不是普通的 JavaScript 函数来定义顺序。
顺序排序是按照taskList
数组中定义的每个alias-task的顺序进行的。例如当使用 grunt.registerTask
:
grunt.registerTask('foo', [ 'a', 'b', 'c' ]);
鉴于上面的伪示例和 运行宁 foo
任务将 运行 任务 a
首先,然后是任务 b
,依此类推(即任务 b
不会 运行 直到任务 a
完成;任务 c
不会 运行 直到任务 b
完成).
然而,这并不意味着不能将普通 JavaScript 函数与 g运行t custom Tasks.
结合使用
带解决方案的长答案:
There does not seem to be a great way to share data between Grunt tasks...
您可以使用 Object
来存储数据。第一个示例中的伪代码意味着您希望 configureUglifiy
函数:
- 动态配置
Uglify
任务
- return数据(一个
Object
)由configureUglifiy
自身生成。
- 然后将 returned 数据作为参数传递给
updateJsScriptTags
函数。
因此,不是从 configureUglifiy
函数中 returning 一个 Object
。您可以将它存储在另一个 Object
中,然后在 updateJsScriptTags
函数中访问它。
在下面的要点中,请注意 shared
对象,其中 property/key 名为 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']);
};
注意 // <-- Do stuff here to determine configuration of uglify task.
的注释将与我提供的 Gruntfile.js 要点的逻辑类似你的另一个问题 .
总结
- 应通过将任务添加到
TaskList
数组来定义顺序(根据上面的 简短回答 部分)
- 必要时可以通过 g运行t 自定义任务调用函数。但请记住,自定义任务是一个函数,因此只有在确实有必要时才将逻辑分离到它自己的函数中。你会发现你的 Gruntfile.js 读起来更好。
当一个 task/function 动态获取数据以在其他 tasks/functions 之间共享时考虑将其存储在 Object
而不是 return 从函数中获取值使用 return
关键字。
尽可能将逻辑分成单独定义的任务,并尽量避免在一个任务中做太多事情。例如,在您在名为 minifyJS
的问题中提供的第一个自定义任务中,您试图在一个任务中做两件事。 IE。您正在配置和 运行ning 您的 uglify 任务(构成一个任务),同时更新 JS 脚本标签(构成另一个任务)。理想情况下,这应该是两个独立的不同任务。
我在上面提供的伪 Gruntfile.js
目前没有采纳我在第 2 点和第 4 点中给出的建议。通过一些重构 Gruntfile.js
会更像这样(注意函数 no不再存在,而是将它们的逻辑与调用它们的自定义任务相结合):
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']);
};
我正在使用 G运行t 生成构建。我是 G运行t、javascript 和 nodejs 的新手,欢迎任何新观点。
我的 G运行tfile 中的一些任务依赖于插件(例如 'uglify' 用于 javascript 缩小),而还有一些其他工作流程最适合仅编写 javascript 函数本身。
我一直处于 运行ning 我需要执行以下操作的情况:(1) 执行一个 javascript 函数 (2) 运行 a g运行t在该函数 (3) 之后立即执行另一个 javascript 函数。它需要按照这个顺序发生。然而,由于 G运行t 只是一个任务调度器,它最终会 运行ning (1),排队 (2),运行ning (3),然后 运行ning (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
});
问题是我需要按照上面显示的顺序运行这些东西。 但是,由于 g运行t 是一个任务调度程序,因此当此任务为 运行
时,会发生以下情况- configureUglify() 函数将 运行.
- 'uglify' 将 排队 - 不是 运行.
- updateJsScriptTags() 函数将 运行.
- 现在默认任务已经完成 - 只是现在排队的 'uglify' 将 运行.
现在,我明白为什么会这样了。 G运行t 是一个任务调度程序——任务正在排队。这是有道理的,而不是抱怨它。 相反,我想问的是解决这个问题的方法是什么?这样我就可以在使用这种功能和任务的组合时实现这种排序?我想这一定是超级简单和通用的,我只是不知道它是什么!
我意识到的一个选择 是将这些函数中的每一个转换为任务本身。然而,这个问题是 configureUglifiy() returns 一个复杂的数据结构,updateJsScriptTags() 然后使用它。除了使用 'options' 属性外,似乎没有在 G运行t 任务之间共享数据的好方法,该属性仅在任务本身内可用。我想我可以这样做,但是,我担心的是这会使事情变得不可读并且......有点危险,因为你现在有这个任务,它依赖于在另一个任务期间修改的数据结构,而且不是立即显而易见,直到您开始深入研究该功能。
我举个例子。哪个对您来说更具可读性?
/**
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
我发现这让事情变得更难读,而不是一个简单的函数,它接受要使用的参数,并可以强加一个特定的结构。事情似乎也更容易以另一种方式出现问题,即我在一个任务中修改某些全局参数中的一堆属性,这些属性稍后会在另一个任务中使用。更麻烦的是,属性名称是共享的,是硬编码的。我知道这是一个非常简单的用例,但开始想象一组更复杂的函数,这些函数依赖于可能是复杂数据类型的多个参数,并且这是我关心的地方。
所以作为一个快速总结:是否有替代方法来实现 function/plugin-task/function/plugin-task 的顺序排序,而不求助于将函数本身转换为自定义任务?
So as a quick summary: are there alternatives to achieving a sequential ordering of function/plugin-task/function/plugin-task, without resorting to converting the functions to custom tasks themselves?
简短回答: 不,要保持执行顺序,您需要使用 g运行t 任务而不是普通的 JavaScript 函数来定义顺序。
顺序排序是按照taskList
数组中定义的每个alias-task的顺序进行的。例如当使用 grunt.registerTask
:
grunt.registerTask('foo', [ 'a', 'b', 'c' ]);
鉴于上面的伪示例和 运行宁 foo
任务将 运行 任务 a
首先,然后是任务 b
,依此类推(即任务 b
不会 运行 直到任务 a
完成;任务 c
不会 运行 直到任务 b
完成).
然而,这并不意味着不能将普通 JavaScript 函数与 g运行t custom Tasks.
结合使用带解决方案的长答案:
There does not seem to be a great way to share data between Grunt tasks...
您可以使用 Object
来存储数据。第一个示例中的伪代码意味着您希望 configureUglifiy
函数:
- 动态配置
Uglify
任务 - return数据(一个
Object
)由configureUglifiy
自身生成。 - 然后将 returned 数据作为参数传递给
updateJsScriptTags
函数。
因此,不是从 configureUglifiy
函数中 returning 一个 Object
。您可以将它存储在另一个 Object
中,然后在 updateJsScriptTags
函数中访问它。
在下面的要点中,请注意 shared
对象,其中 property/key 名为 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']);
};
注意 // <-- Do stuff here to determine configuration of uglify task.
的注释将与我提供的 Gruntfile.js 要点的逻辑类似你的另一个问题
总结
- 应通过将任务添加到
TaskList
数组来定义顺序(根据上面的 简短回答 部分) - 必要时可以通过 g运行t 自定义任务调用函数。但请记住,自定义任务是一个函数,因此只有在确实有必要时才将逻辑分离到它自己的函数中。你会发现你的 Gruntfile.js 读起来更好。
当一个 task/function 动态获取数据以在其他 tasks/functions 之间共享时考虑将其存储在
Object
而不是 return 从函数中获取值使用return
关键字。尽可能将逻辑分成单独定义的任务,并尽量避免在一个任务中做太多事情。例如,在您在名为
minifyJS
的问题中提供的第一个自定义任务中,您试图在一个任务中做两件事。 IE。您正在配置和 运行ning 您的 uglify 任务(构成一个任务),同时更新 JS 脚本标签(构成另一个任务)。理想情况下,这应该是两个独立的不同任务。
我在上面提供的伪 Gruntfile.js
目前没有采纳我在第 2 点和第 4 点中给出的建议。通过一些重构 Gruntfile.js
会更像这样(注意函数 no不再存在,而是将它们的逻辑与调用它们的自定义任务相结合):
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']);
};