使用通配符模式时,grunt-contrib-concat表现异常

5

我正在使用grunt,想要按照特定顺序(这是一个angular js应用程序,因此我希望首先进行模块定义,然后是其他所有内容)合并某个目录中的所有js文件。我的grunt concat目标如下:

concat: {

    mobile: {
        expand: true,
        cwd: "static/javascript/mobile/app/",
        src: ["main-module.js", "**/*-module.js", "**/*.js", "!static/javascript/mobile/dist/*"],
        dest: "static/javascript/mobile/app/dist/ngmobile.concat.js"
    }
}

上述配置看起来应该会将main-module.js和其他的module.js文件合并,然后再合并所有其它的文件,同时忽略dist文件夹中的所有内容。但是当使用 --verbose 参数运行grunt时,实际结果可能是:
Running "concat:mobile" (concat) task
Verifying property concat.mobile exists in config...OK
Files: static/javascript/mobile/app/main-module.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/main-module.js
Files: static/javascript/mobile/app/clients/clients-module.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/clients/clients-module.js
Files: static/javascript/mobile/app/reports/reports-module.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/reports/reports-module.js
Files: static/javascript/mobile/app/schedules/schedules-module.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/schedules/schedules-module.js
Files: static/javascript/mobile/app/services/services-module.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/services/services-module.js
Files: static/javascript/mobile/app/clients/addclient-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/clients/addclient-ctrl.js
Files: static/javascript/mobile/app/clients/clientprofile-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/clients/clientprofile-ctrl.js
Files: static/javascript/mobile/app/clients/clients-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/clients/clients-ctrl.js
Files: static/javascript/mobile/app/clients/clients-service.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/clients/clients-service.js
Files: static/javascript/mobile/app/common/directives.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/common/directives.js
Files: static/javascript/mobile/app/common/filters.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/common/filters.js
Files: static/javascript/mobile/app/common/header-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/common/header-ctrl.js
Files: static/javascript/mobile/app/common/navbarcollapse-directive.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/common/navbarcollapse-directive.js
Files: static/javascript/mobile/app/dist/ngmobile.concat.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/dist/ngmobile.concat.js
Files: static/javascript/mobile/app/main-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/main-ctrl.js
Files: static/javascript/mobile/app/main-service.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/main-service.js
Files: static/javascript/mobile/app/reports/reports-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/reports/reports-ctrl.js
Files: static/javascript/mobile/app/schedules/schedules-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/schedules/schedules-ctrl.js
Files: static/javascript/mobile/app/schedules/schedules-service.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/schedules/schedules-service.js
Files: static/javascript/mobile/app/services/addservice-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/services/addservice-ctrl.js
Files: static/javascript/mobile/app/services/serviceprofile-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/services/serviceprofile-ctrl.js
Files: static/javascript/mobile/app/services/services-ctrl.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/services/services-ctrl.js
Files: static/javascript/mobile/app/services/services-service.js -> static/javascript/mobile/app/dist/ngmobile.concat.js/services/services-service.js
Options: separator="\n", banner="", footer="", stripBanners=false, process=false
Reading static/javascript/mobile/app/main-module.js...OK
Writing static/javascript/mobile/app/dist/ngmobile.concat.js/main-module.js...ERROR
Warning: Unable to write "static/javascript/mobile/app/dist/ngmobile.concat.js/main-module.js" file (Error code: ENOTDIR). Use --force to continue.

Aborted due to warnings.

这告诉我它找到了我想要找的文件,然后尝试将它们写入(复制?)到dest中指定的文件路径。 我到底哪里做错了? :) 如果有人足够关心并想挽救一下我头上的几根头发,我会非常感激对我在这里做错了什么的指导。我想要将 src 中的所有文件合并到 dest 文件中。

编辑

如果我删除 expand 属性,输出看起来像:

Running "concat:mobile" (concat) task
Verifying property concat.mobile exists in config...OK
Files: main-module.js, clients/clients-module.js, reports/reports-module.js, schedules/schedules-module.js, services/services-module.js, clients/addclient-ctrl.js, clients/clientprofile-ctrl.js, clients/clients-ctrl.js, clients/clients-service.js, common/directives.js, common/filters.js, common/header-ctrl.js, common/navbarcollapse-directive.js, dist/ngmobile.concat.js, main-ctrl.js, main-service.js, reports/reports-ctrl.js, schedules/schedules-ctrl.js, schedules/schedules-service.js, services/addservice-ctrl.js, services/serviceprofile-ctrl.js, services/services-ctrl.js, services/services-service.js -> static/javascript/mobile/app/dist/ngmobile.concat.js
Options: separator="\n", banner="", footer="", stripBanners=false, process=false
>> Source file "main-module.js" not found.
>> Source file "clients/clients-module.js" not found.
>> Source file "reports/reports-module.js" not found.
>> Source file "schedules/schedules-module.js" not found.
>> Source file "services/services-module.js" not found.
>> Source file "clients/addclient-ctrl.js" not found.
>> Source file "clients/clientprofile-ctrl.js" not found.
>> Source file "clients/clients-ctrl.js" not found.
>> Source file "clients/clients-service.js" not found.
>> Source file "common/directives.js" not found.
>> Source file "common/filters.js" not found.
>> Source file "common/header-ctrl.js" not found.
>> Source file "common/navbarcollapse-directive.js" not found.
>> Source file "dist/ngmobile.concat.js" not found.
>> Source file "main-ctrl.js" not found.
>> Source file "main-service.js" not found.
>> Source file "reports/reports-ctrl.js" not found.
>> Source file "schedules/schedules-ctrl.js" not found.
>> Source file "schedules/schedules-service.js" not found.
>> Source file "services/addservice-ctrl.js" not found.
>> Source file "services/serviceprofile-ctrl.js" not found.
>> Source file "services/services-ctrl.js" not found.
>> Source file "services/services-service.js" not found.
Writing static/javascript/mobile/app/dist/ngmobile.concat.js...OK
File "static/javascript/mobile/app/dist/ngmobile.concat.js" created.

注意,上面代码片段中第三行“Files: ...”列出了我想要查找的所有文件,但是却说源文件没有找到。
编辑2:
Matt的解决方案解决了这个问题,下面是我的更新后的代码:
concat: {
    mobile: {
        dest: "static/javascript/mobile/app/dist/ngmobile-concat.js",
        src: (function () {
            var cwd = "static/javascript/mobile/app/";
            var files = ["*-module.js", "**/*-module.js", "**/*.js"];

            files = files.map(function (file) {
                return cwd + file;
            });

            files.push("! static/javascript/mobile/app/dist");

            return files;
        }())
    }
}
2个回答

4

我曾在一个Angular应用程序中遇到过这个问题,考虑了三个选项:

1)按照项目GitHub线程上的建议进行操作

你并不孤单。grunt-contrib-concat的GitHub项目上有一个长线程与此问题有关。这与cwddest的工作方式有关。

建议的解决方法发布在那里,将cwd属性移动到一个函数中,然后产生预期的结果,而不是ENOTDIR错误。

src: (function() {
  var cwd = 'src/js/';
  var arr = [];
  // determine file order here and concat to arr
  return arr.map(function(file) { return cwd + file; });
}())

我认为缺点是添加了一个函数到gruntfile中,通常它非常简单。如果您不是唯一维护应用程序的人,则可能会引起困惑。
2) 放弃cwd并使用<%= %>变量语法的静态方法
如果您的src和dest目录在整个gruntfile中保持一致,您可以通过以下方式定义src和dest目录:
myapp: {
  // configurable paths
  app: "static/javascript/mobile/app/",
  dist: "static/javascript/mobile/app/dist/"
}

如果您想让内容看起来更加“静态”,那么可以删除cwd属性并进行配置:

concat: {

    mobile: {
        expand: true,
        src: ["<%= myapp.app %>/main-module.js", "<%= myapp.app %>/**/*-module.js", "<%= myapp.app %>/**/*.js", "!<%= myapp.dist %>/*"],
        dest: "<%= myapp.dist %>/ngmobile.concat.js"
    }
}

对于我的大多数项目来说,这已经足够了。它简单、DRY,当我回来需要进行更改时易于理解。
值得一提的是:配置属性一开始可能有些难以阅读,因为有很多<%=%>的混乱,但是通过在我的编辑器中进行一些格式化可以改善这种情况。此外,另一个程序员很容易就能够阅读并知道你的意图。
3) 使用像usemin这样的插件
如果您还要进行缩小操作,可以考虑使用grunt-usemin等插件。
这种选择的缺点显而易见:usemin增加了复杂性,因为您现在需要管理和配置另一个插件,并且您需要格式化HTML以使用usemin功能。 Usemin配置起来可能很困难,如果您正在与团队合作,程序员或设计师修改usemin配置或HTML注释可能会很容易破坏事情。
优点是usemin会直接从HTML中生成grunt的复制、连接和压缩配置。因此,如果您在HTML中添加/删除脚本或更改加载顺序,您无需在grunt配置中进行任何操作,因为usemin将自动识别。

Matt!非常感谢你的帮助。我现在使用自调用匿名函数来返回文件列表,使用globbing已经让它正常工作了。我将用确切的代码更新我的原始问题,但是无法感谢你详细的回答。 - Greg
感谢您的建议。我更喜欢第一个,并将其写在一行中:['main-module.js', ...].map(function(file) {return 'src/js/'+file}) - Fancyoung

0
如果设置了“cwd”,grunt-contrib-concat只会复制文件,而不是连接它们。有一个巧妙的解决方法。只需要添加“rename”属性,并像下面那样返回“dest”名称即可。
rename: function (dest) {
              return dest;
        },

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接