javascript - Grunt : minify js across project of multiple dirs, 以便每个目录的内容扁平化为单个缩小文件

标签 javascript node.js gruntjs minify

我有一个项目,其 javascript 文件的结构如下:

Hypothetical directory structure

我的目标:我想缩小/丑化这些 javascript 文件 在构建输出中,例如每个目录有 1 个缩小文件 .因此,例如,如果我将 js 存储在 bld/js 中的构建输出中,那么在 bld/js 中,我最终会得到文件:dir1.min.js(连接和缩小 fileA.js、fileB.js 的结果)。 js 以及/src/js/dir1/中的所有其他 js 文件)、dir2.min.js(连接和缩小 fileG.js 和 fileN.js 以及/src/dir2/中的所有其他 js 文件的结果) , 等等。

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

据我了解,在 grunt 中做事的主要方法是使用插件。所以我的第一个想法是使用插件来完成这项任务。有一个名为“npm-contrib-uglify”的插件,专门用于缩小。 https://github.com/gruntjs/grunt-contrib-uglify问题是 - 我的理解是,为了做我希望在这里做的事情(每个目录 1 min.js 文件),我需要为每个目录创建特定的任务。所以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。这是一个例子(注意我在几个地方使用伪代码,特别是为了获取目录列表,因为我没有访问机器的权限,也没有将语法提交给内存。但这应该给出的想法我的意思是:)
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 中编写这样的代码(所以我这样做违背了目的?)你真的可以参数化 grunt 插件的目标,比如 grunt-contrib-uglify 吗?我在使用许多插件时遇到了同样的问题,我有一些任务需要在许多不同的目录/文件中一遍又一遍地重复,但方式完全相同,所以我希望能够配置一个通用的目标我可以以编程方式调用不同的值(而不是对可能经常更改的特定目录或文件名的大量目标进行硬编码)。但这似乎不可能,所以我继续在 node.js 中实现。 我接近咕噜声的方式是否存在根本缺陷?如果是这样 - 你能提供一些替代的观点吗?

最佳答案

想法

am I just thinking about this in the completely wrong way?


不,我不认为你以错误的方式思考这个问题。质疑任何发展的原因/方式总是一件好事[时期]。这就是使我们长期成为更好的开发人员的原因。
无论您选择在构建过程中使用哪种解决方案/工具,无论是专用的任务运行器,例如 gruntgulp ,或更高级别的解决方案,例如 nodejs也许与 npm-scripts 结合使用,您仍然需要编写一些代码。当然,提到的所有这些方法之间的共同点是您必须使用 JavaScript 进行编码。

Is the whole point of grunt to avoid coding things like this in node.js (and so I'm defeating the purpose by doing this?


我不能说哪个解决方案/工具比另一个更好用(那太固执己见了),而且我个人有使用提到的所有这些工具开发构建过程的经验。通常,尽管我经常发现使用专用任务运行程序(grunt 或 gulp)比使用更自定义的方法(例如 npm-scripts)时减少了处理构建的开发时间。结合 nodejs .
通常,我也会为 grunt 找到一个非常棒的插件(例如 grunt-contrib-uglify ),然后经过一些修补后发现它满足了我 90% 的要求,但剩下的 10% 却惨遭失败。但是,在使用/集成任何开源包/模块时经常会出现这种情况……可以这么说,您仍然必须填补空白!

咕噜声鲜为人知的 gem
放弃前gruntjs并进入nodejs只有开发模式,(再次重申我对任何方法都没有偏见),我建议您检查一些 grunts 功能,例如:
  • custom-tasks
  • grunt.file.expand
  • grunt.config
  • grunt.task.run

  • 在使用 grunt 时,我发现利用上面列出的功能帮助我解决了我之前提到的剩余 10% 的需求。特别是自定义任务功能多次被证明非常有用。

    解决方案
    值得注意的是grunt-contrib-uglifymulti-task插入。 IE。它允许您配置多个Targets正如您在 uglify 中所展示的那样您问题中的配置。您已包含三个名为 dir1 的目标, dir2 , 和 dirN .
    事实是grunt-contrib-uglify是多任务并记住我之前列出的 grunt 功能......使用 grunt 满足您的要求的一种方法是:
  • 使用自定义任务来动态配置和运行 uglify 任务。
  • 使用 grunt.file.expand获取每个 .js 文件的父文件夹的路径。
  • filter路径数组仅包含唯一的目录路径。
  • 动态创建files uglify 的每个目标的配置任务。
  • 配置uglify使用 grunt.config 的具有多个目标的任务然后使用 grunt-task.run 运行任务.

  • 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
        //    (i.e. 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"]);
    };
    
    结果
    运行$ grunt通过 CLI 使用 Gruntfile.js上面有 src目录如下:
    .
    └── 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文件用于连接/丑化结果的名称.js文件。

    概括
  • Gruntfile.js 中使用的模式/方法(上图)可以根据需要对许多可用的插件进行修改。
  • 只要插件本身支持多任务,然后考虑使用 grunt 自定义任务来填补空白。

  • 我希望这可以帮助你。

    关于javascript - Grunt : minify js across project of multiple dirs, 以便每个目录的内容扁平化为单个缩小文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47323641/

    相关文章:

    javascript - C# bool 函数正在从服务器返回一个对象到客户端

    node.js - Nodejs Passport 认证挂了

    node.js - 如果 IIS 客户端证书身份验证正常,则检查 nodeJS Express

    python - Graphite statsd xaxis 每 2 秒

    javascript - JS : Keep variable values for onclick event attached inside for loop

    javascript - webdriverio - 无法找到具有类名的元素

    node.js - Gulp 环境和预处理

    css - Sass - 包含大量 css 文件的复杂文件夹结构

    node.js - 边看咖啡边看 Jade 文件,同时完成繁琐的任务

    javascript - 如果React Selectbox中的值与其他值匹配,如何默认获取选定的值?