Grunt:跨多个目录的项目缩小js,以便每个目录的内容扁平化为单个缩小文件

2023-12-10

我有一个项目,其中的 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 文件的结果) , 等等。

Now - 我正在使用 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...
           }
        }
    }
}

现在 - 我不是要求你为我解决这个问题,而且我知道上面的内容不会编译。相反,我的问题是——我是否以完全错误的方式思考这个问题?grunt 的全部意义在于避免在 Node.js 中编写类似的代码(所以我这样做就违背了目的?)您真的可以参数化 grunt 插件(例如 grunt-contrib-uglify)的目标吗?我在许多插件中遇到了同样的问题,我有一些任务需要在许多不同的目录/文件中一遍又一遍地重复,但以完全相同的方式,所以我希望能够配置一个通用的我可以以编程方式调用不同值的目标(而不是对可能经常更改的特定目录或文件名硬编码大量目标)。但这似乎不可能,所以我继续在 node.js 中实现。我处理 grunt 的方式有什么根本性的缺陷吗?如果是这样,你能提供一些替代的观点吗?


Thoughts

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

不,我不认为你以错误的方式思考这个问题。质疑总是一件好事why/how对于任何发展[时期]。从长远来看,这使我们成为更好的开发人员。

无论您选择在构建过程中使用哪种解决方案/工具,无论是专用的任务运行程序,例如grunt or gulp,或者更高级别的解决方案,例如nodejs也许结合npm 脚本,你仍然需要编写一些代码。当然,提到的所有这些方法之间的共同点是您必须使用以下代码进行编码JavaScript.

grunt 的全部意义在于避免在 node.js 中编写类似的代码(所以我这样做就违背了目的?

我不应该说哪种解决方案/工具比另一种更好(这样就太固执己见了)就我个人而言,我有使用上述所有工具开发构建流程的经验。通常,尽管我经常发现使用专用任务运行程序时处理构建的开发时间会减少(grunt or gulp)比使用更自定义的方法(例如npm-scripts结合nodejs.

通常,我也会找到一个非常棒的插件grunt(例如grunt-contrib-uglify)然后经过一番修补后发现它满足了我 90% 的要求,但对于剩下的 10% 却惨遭失败。然而,在利用/集成任何开源包/模块时通常会出现这种情况……可以说,您仍然必须填补空白!


咕噜声鲜为人知的宝石

迫降前gruntjs并进入nodejs目前还只有开发模式,(再次重申我对任何方法都没有偏见),我建议您查看一些 grunts 功能,例如:

  • 自定义任务
  • grunt.file.expand
  • grunt.config
  • grunt.task.run

使用时可能出现过这样的情况grunt我发现利用上面列出的功能可以帮助我解决我之前提到的剩余 10% 的要求。多次证明,自定义任务功能非常有用。


Solution

值得注意的是grunt-contrib-uglify is a 多任务插入。 IE。它允许您配置多个Targets正如你在你的uglify你问题中的配置。您已包含三个名为dir1, dir2, and dirN.

事实是grunt-contrib-uglify is 多任务并记住我之前列出的重要功能...满足您的要求的一种方法是使用grunt is to:

  1. 使用自定义任务动态配置和运行 uglify 任务。
  2. Utilize grunt.file.expand获取每个 .js 文件的父文件夹的路径。
  3. filterpaths 仅包含唯一目录路径的数组。
  4. 动态创建files每个目标的配置uglify task.
  5. 配置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"]);
};

Results

Running $ grunt通过 CLI 使用Gruntfile.js上面有一个src目录如下:

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

..将连接和uglify the .js文件产生的目录结构如下:

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

注:源的父文件夹名称.js文件用于连接/丑化结果的名称.js file.


Summary

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

我希望这可以帮助你。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Grunt:跨多个目录的项目缩小js,以便每个目录的内容扁平化为单个缩小文件 的相关文章

  • CSS 内边框?

    我纯粹用 CSS 创建了左侧的按钮 它是一个div 中的一个div 然而 右侧的三个按钮是background属性于img标签 我这样做是为了按照以下说明模拟翻转效果here http kyleschaeffer com best prac
  • JS文件中的System.register是什么意思?

    在 Angular 2 中使用指令时 JS 文件中的 System register 是什么意思 我认为这个问题并不特定于 Angular2 中的指令 它是关于 ES6 TypeScript 和其他使用 SystemJS 的现代编译器的一般
  • 每n秒执行一次函数

    我制作了这个在 10 秒后点击链接的代码片段 function timeout window setTimeout function img left click 1000 setTimeout timeout 1000 timeout 我
  • 根据 MVC,哪种项目结构是正确的? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我注意到诸如flask通常有一个名为views容纳 app route def index return render template ind
  • setTimeout范围问题

    我在控制玩家重生的函数内部定义了一个 setTimeout 我正在创建一个游戏 var player death function this alive false Console log death var timer3 setTimeo
  • vuejs 模板和 asp.net 部分视图,好的做法吗?

    我在网站中使用 Vue js 并将模板添加到 html 代码中 并将 js 代码添加到单个 js 文件中 所以我不想使用 vue Vuefy Browserfy 方法 而是稍后捆绑并缩小我的 js 文件 由于我必须使用 Asp Net MV
  • Angular UI-Router:多个 URL 到单一状态

    我已经开始使用 Angular 的 ui router 并且我正在尝试弄清楚如何让多个 URL 引用单个状态 例如 orgs 12354 overview retyrns the same pages as org overview 我的
  • 为什么我需要使用 setState 回调来设置依赖于第一个项目的 setState 完成的第二个状态项目的状态?

    在此 componentDidUpdate 方法中 执行 setState 将引号设置为从 fetch 返回的内容后 我必须使用回调再次执行 setState 将 randomQuoteIndex 设置为调用 randomQuoteInde
  • 在express js中禁用http方法

    我正在我的 Express 应用程序上进行 nessus 测试 这是我得到的 基于每种方法的测试 HTTP 方法 ACL CHECKOUT COPY DELETE GET HEAD LOCK MERGE MKACTIVITY MKCOL 移
  • 如何防止输入文本中出现“后重音”

    我相信这是一个简单的问题 但在谷歌上搜索几个小时后我找不到任何答案 也许我无法在搜索中使用正确的单词 P 我有一个 javascript 方法 可以防止用户用数字以外的其他字符填充文本框 如下面的代码所示 它在 KeyDown 事件中使用
  • 对使用“new”创建的数组上“map”的行为感到困惑[重复]

    这个问题在这里已经有答案了 我对结果感到困惑mapping 使用创建的数组new function returnsFourteen return 14 var a new Array 4 gt undefined x 4 in Chrome
  • 我应该如何实现将状态保存到 localStorage?

    CODE var React require react var Recipe require Recipe jsx var AddRecipe require AddRecipe jsx var EditRecipe require Ed
  • Angular 2 将字符串转换为 md5 哈希

    我找到了ts md5 https www npmjs com package ts md5包 但在示例中它有一个hashStr方法 但现在不行了 类型上不存在属性 hashStr Md5 使用该错误后 该错误会记录在我的控制台中 我怎样才能
  • 在循环中调用 setTimeout 未按预期工作

    下面的 JavaScript 应该 在我看来 以 0 5 秒的间隔播放一系列音符 但它会将它们全部作为一个同时的和弦来演奏 知道如何修复它吗 function playRecording if notes length gt 0 for v
  • 从 Flask 运行 NPM 构建

    我有一个 React 前端 我想在与我的 python 后端 API 相同的源上提供服务 我正在尝试使用 Flask 来实现此目的 但我遇到了 Flask 找不到我的静态文件的问题 我的前端构建是用生成的npm run build in s
  • 此版本的 CLI 仅与 Angular 版本 5.0.0 或更高版本兼容错误

    我已经有 Angular 项目在 4 版本中运行 在安装新项目时 不幸的是我安装了 6 版本的 Angular cli 在以 4 版本运行的旧项目中运行 ngserve 命令时 这会引发错误 您的全局 Angular CLI 版本大于本地版
  • Javascript等待/异步执行顺序

    所以我试图把我的头脑集中在 Promise await async 上 我不明白为什么当 go 执行时 带有 finished 的警报会紧随 console log coffee 之后 当所有函数都使用等待 承诺时 为什么它只等待 getC
  • 什么时候可以使用Javascript,什么时候不可以?

    不使用太多 javascript jquery 是个好习惯吗 我们应该尽可能避免它 为了良好的可访问性 吗 什么时候可以使用 JavaScript 什么时候不能在网页设计和开发中使用 JavaScript 在什么场景 什么条件下 Updat
  • Array.of 与“[ ]”。何时使用 Array.of 而不是“[ ]”?

    当我发现时我正在读一些书Array of https developer mozilla org en docs Web JavaScript Reference Global Objects Array of 根据 MDN Array o
  • Safari 扩展将消息发送到特定选项卡

    有没有办法从全局页面发送消息到特定选项卡 我目前正在做的是 在创建选项卡时 注入的脚本会创建一个唯一的 ID 并将包含该编号的消息发送到全局页面 并且全局页面会保存该编号 如果全局页面需要发送一些数据到一个tab 即 tab 3 然后全局页

随机推荐