Grunt:跨多个dirs项目缩小js,使每个dir的内容变成一个缩小的文件

我有一个项目,与JavaScript文件结构如下所示:

假设的目录结构

我的目标:我想在构build输出中缩小/丑化这些JavaScript文件例如每个目录有一个缩小的文件 。 例如,如果我将js存储在bld / js中的构build输出中,那么在bld / js中,我将以文件dir1.min.js(连接并缩小fileA.js,fileB的结果)结束。 js和/ src / js / dir1 /中的所有其他js文件),dir2.min.js(fileG.js和fileN.js的连接和缩小结果,以及/ src / dir2 /中的所有其他js文件的结果) , 等等。

现在 – 我正在使用grunt框架来生成构build ,并且必须在grunt文件中执行此操作。 我是grunt,node.js和javascript的新手。 我想解释我的思维过程来解决这个问题,并想知道是否有人更熟悉这些框架可以告诉我,如果我的方法/思考是错的。

据我所知,做咕噜的主要方式是使用插件。 所以我的第一个想法是使用一个插件来完成这个任务。 有一个名为“npm-contrib-uglify”的插件,专门用于缩小。 https://github.com/gruntjs/grunt-contrib-uglify问题是 – 我的理解是做我希望在这里做的(每个目录1 min.js文件),我需要创build具体每个目录的任务。 所以init看起来像这样:

grunt.initConfig({ uglify: { dir1: { files: { 'dest/js/dir1.min.js': ['src/js/dir1/**.js'] } }, dir2: { files: { 'dest/js/dir2.min.js': ['src/js/dir2/**.js'] } }, ... dirN: { files: { 'dest/js/dirN.min.js': ['src/js/dirN/**.js'] } }, } }); 

如果我只有一两个目标,而且项目格式要保持不变,我想我可以忍受这个。 但是这个项目中有很多项目,更重要的是项目结构会发生变化, 我希望能够将dirs添加到我的项目中,而不必每次都通过添加新目标来更新grunt文件。 我希望有一个参数化任务的方法 – 也就是说,有一个通用的目标,说'对于某些目录,将该目录中的所有.js文件缩小到某些.min.js文件',然后我可以通过编程调用目标每个目录 – 但这似乎不可能。

所以我决定避开这个插件,只依靠node.js. 有一个叫npm-uglify的npm模块。 https://www.npmjs.com/package/uglify-js 。 我想我可以做我自己的定制grunt任务,循环通过源目录,并调用每个嵌套目录uglify-js。 这里是一个例子(注意我在几个地方使用伪代码,尤其是获取dir列表,因为我没有机器访问权限,也没有提供内存的语法,但是这应该给出我的意思是做:)

 var fs = require('fs'); var uglifyJs = require('uglify-js'); 

 grunt.registerTask('minifyMyJs', function(myJsSrcDir) { // myJsSrcDir is an abs. path to the src dir for (dir in myJsSrcDir): // go through all the dirs.. realize I should use fs.readdir, but just use pseudocode here to give the idea var minifiedOutputFileName = fs.basename(dir); // to get dir1 from /src/js/dir1 var minified = uglifyJs.Minify(["**.js"]); fs.writeFile(minifiedOutputFileNam, result.code, function(err)) { if(err) { ... error checking... } } } } 

现在 – 我不是要求你为我解决这个问题,而且我知道上面不会编译。 相反,我的问题是 – 我只是以完全错误的方式思考这个问题? 为了避免在node.js中编写像这样的东西(所以我通过这样做来击败目的),是不是要咕whole一声呢?难道你真的可以参数化grunt插件的目标,比如grunt-contrib-uglify ? 我遇到了许多插件的同样的问题,我有一些任务,我需要一遍又一遍地跨越许多不同的目录/文件,但以完全相同的方式,所以我想能够configuration一个普通的目标我可以以编程方式调用不同的值(而不是为特定目录或文件名硬编码大量目标,这些目标或文件名可能会经常变化)。 但是这似乎不可能,所以我只是继续在node.js中实现。 我接近咕噜声的方式有什么根本性的缺陷吗? 如果是这样 – 你能提供一些替代的观点吗?

思考

我只是以完全错误的方式思考这个问题?

不,我不认为你是以错误的方式思考这个问题的。 质疑为什么/如何进行发展总是一件好事。 这是使我们更好地开发长期的原因。

无论您select哪种解决scheme/工具用于构build过程,无论是grunt或gulp这样的专用任务运行者,还是像nodejs这样的更高级别的解决scheme都可能与npm脚本结合使用,您仍然需要编写一些代码。 当然,所提及的所有方法之间的共同之处在于,您必须使用JavaScript进行编码。

为了避免在node.js中编写像这样的东西,是不是要咕噜咕噜呢(所以我通过这样做来击败目的?

对于我来说,哪个解决scheme/工具比其他解决scheme/工具的使用更好(这会太自以为是的),而且我个人也有使用上述所有工具开发构build过程的经验。 通常,虽然我经常发现使用专用任务运行器( gruntgulp )时,处理构build的开发时间比使用更加自定义的方法(如与nodejs结合的npm-scripts时要nodejs

通常情况下,我也会find一个非常棒的grunt插件(比如grunt-contrib-uglify ),然后在经过一番修改之后发现它符合我90%的要求,但在剩下的10%中失败了。 然而,在使用/集成任何开放源代码的封装/模块时通常都是这种情况…您仍然必须填补空白空间!


咕噜声不太为人所知的gem

在开始使用gruntjs之前,只进入nodejs开发模式(再次重申,我对这些方法没有任何偏见) ,我build议你签出一些grunts特性,比如:

  • 定制任务
  • grunt.file.expand
  • grunt.config
  • grunt.task.run

使用grunt时可能出现的情况是,我发现使用上面列出的function帮助我解决了前面提到的剩余10%的需求。 自定义任务特别被certificate是非常有用的多次。


值得注意的是, grunt-contrib-uglify是一个多任务插件。 也就是说,它允许您configuration多个目标,就像您在问题的uglifyconfiguration中演示的那样。 您已经包含三个名为dir1dir2dirN

由于grunt-contrib-uglify一项多任务的工作 ,并且牢记我之前列出的那些咕噜声的function…使用grunt满足您的需求的一种方法是:

  1. 使用自定义任务来dynamicconfiguration和运行uglify任务。
  2. 使用grunt.file.expand获取每个.js文件父文件夹的path。
  3. filterpath数组仅限于唯一的目录path。
  4. dynamic创builduglify任务的每个目标的filesconfiguration。
  5. 使用grunt.configconfiguration具有多个目标的grunt.config任务,然后使用grunt.config运行任务。

Grunfile.js

 module.exports = function (grunt) { 'use strict'; grunt.initConfig({ uglify: { // <-- Intentionally blank, will be dynamically generated. } }); /** * 1. Helper custom Task to dynamically configure and run the uglify task. */ grunt.registerTask('myUglify', 'Configures uglify task', function () { var srcDirGlob = 'src/js/**/*.js'; var destDir = 'dist/js/'; var config = {}; // 2. Get the paths to the parent diretory of each .js file. var paths = grunt.file.expand({ filter: 'isFile' }, srcDirGlob) .map(function (_path) { return _path.substring(0, _path.lastIndexOf("/")); }); // 3. Filter paths Array to only unique directory paths. paths.filter(function(_path, pos){ return paths.indexOf(_path) === pos; }) // 4. Dynamically create the `files` configuration for each Target. .forEach(function(_path, index) { var dirName = _path.substring(_path.lastIndexOf('/') + 1); var destPath = destDir + dirName + '.min.js'; var srcGlob = _path + '/*.js'; config[index] = { files: {} } config[index].files[destPath] = srcGlob; }); // NOTE: The dynamically created `config` object is now something like this: // // config: { // 0: { // files: { // 'dist/js/dir1.min.js': 'src/js/dir1/**.js' // } // }, // 1: { // files: { // 'dist/js/dir2.min.js': 'src/js/dir2/**.js' // } // }, // ... // } // 5. Configure the uglify task with multiple Targets // (ie the `config` object) and then run the Task. grunt.config('uglify', config); grunt.task.run(['uglify']); }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ["myUglify"]); }; 

结果

使用上面的src目录的Gruntfile.js通过CLI运行$ grunt ,如下所示:

 . └── src └── js ├── dir1 │  ├── fileA.js │  └── fileB.js ├── dir2 │  ├── fileG.js │  └── fileN.js └── dir3 ├── fileQ.js └── fileR.js` 

..将连接并uglify生成目录结构的.js文件,如下所示:

 . └── dist └── js ├── dir1.min.js ├── dir2.min.js └── dir3.min.js` 

注:源.js文件的父文件夹名称用于生成的连接/ uglified .js文件的名称。


概要

  • Gruntfile.js (上面)中使用的模式/方法可以根据需要修改许多可用的插件。
  • 只要插件本身支持多任务,然后考虑使用一个咕噜自定义任务填补空白。

我希望这可以帮助你。