在 Grunt 任务中读取文件名

Read filename in Grunt task

我已经将 G运行t 设置为使用 g运行t-replace,这样我就可以在几百 HTML 页中找到 div ,并将 div 中的文本替换为它所在的 HTML 文件的当前文件名。不过我不确定具体如何执行此操作。我尝试使用 window.loacation.href 但这只会在我 运行 任务时产生错误。

这是我的 Gruntfile.coffee:

module.exports = (grunt) ->
grunt.initConfig
    pkg: grunt.file.readJSON "package.json"
    gruntfile: "Gruntfile.coffee"

    replace:
        dist:
            options:
                patterns: [
                    match: "<div id'name_goes_here'></div>"
                    replacement: ->
                        "<div id'name_goes_here'>Filename: #{window.location.href}</div>"
                ]
            usePrefix: false
            files: [
                expand: true
                flatten: true
                src: [
                    "src/*.html"
                ],
                dest: "output/"
            ]

grunt.loadNpmTasks "grunt-replace";
grunt.registerTask "default", ["replace"];

作为旁注,我尝试将包含简单字符串的变量传递到替换字符串中,这有效并替换了所有 HTML 页面,因此 G运行任务肯定有效。而且替换是一个函数的原因是因为我计划在以后添加一些额外的东西,但现在只想让它工作。

如有任何帮助,我们将不胜感激。

编辑:更新 Gruntfile.js 中的正则表达式以处理 <div> 标签,除了 id 之外还可能包含属性。例如:

<!-- Also includes a class -->
<div id="QUUX" class="foo">...</div>

首先 gruntNode.js, so calling window.location.href will produce an error as the .html files to be processed are not loaded into a web browser. window.location.href is a convention of the BOM 上运行,通常只在浏览器环境中运行。

grunt-replace with standard Task configuration(s) does not provide a mechanism to obtain the filename being processed. However, as grunt-replace is a multi-task 插件,可以通过使用自定义函数动态创建 replace 任务对象来满足您的要求。


下面显示了如何实现:

Gruntfile.js

module.exports = function (grunt) {

  grunt.initConfig( {
    replace: {} // <-- // Intentionally empty, will be generated dynamically.
  });

  /**
   * Helper function dynamically creates config object for `replace` Task.
   * We dynamically generate this to obtain the filename and use that for
   * the `replacement` value.
   */
  function replaceHtml() {
    var glob = 'src/*.html',
      config = {};

    grunt.file.expand({ filter: 'isFile' }, glob).forEach(function (filePath) {
      var fileName = filePath.split('/').pop().split('.')[0];
      config[fileName] = {
        options: {
          usePrefix: false,
          patterns: [{
            // Regex pattern explained here: https://regex101.com/r/uJVMOI/3
            match: /(<div.*?id=\"QUUX\".*?>)[\s\S]+?(<\/div>)/g,
            replacement: '' + fileName + ''
          }]
        },
        files: [{
          expand: true,
          flatten: true,
          src: filePath,
          dest: 'output/'
        }]
      }
    });

    grunt.config('replace', config);
    grunt.task.run(['replace']);
  }

  grunt.loadNpmTasks('grunt-replace');
  grunt.registerTask("default", replaceHtml);
};

备注

  1. replace 任务的配置有意设置为空对象。

  2. replaceHtml 函数利用 grunt.file.expand to loop over each file found via the glob 模式 'src/*.html'

  3. 通过当前filePath.

  4. 得到fileName变量
  5. forEach 语句的每个循环中,都会生成一个 Target 并添加到 config 对象中。

  6. 当退出 forEach 循环时,config 对象通过使用 grunt.config, before finally calling grunt.task.run[=54 添加到 replace Task/Object =]

正则表达式

那么接下来的部分是做什么的?

patterns: [{
  match: /(<div.*?id=\"QUUX\".*?>)[\s\S]+?(<\/div>)/g,
  replacement: '' + fileName + ''
}]

match 部分使用正则表达式,进一步解释 here。它当前搜索以下实例:

<div id="QUUX">...</div>

所以,假设上面的代码片段位于一个名为 index.html 的文件中 - 那么生成的文件将显示为:

<div id="QUUX">index</div>

但是,如果在生成的文件中它应该读取(即它应该包含文件后缀 .html):

<div id="QUUX">index.html</div>

...那么您需要更改第 34 行中 fileName 变量的赋值。 17 在 Gruntfile.js 至:

var fileName = filePath.split('/').pop();

多次匹配

要执行多个匹配,只需将另一个模式对象添加到 patterns 数组。例如:

// ...
patterns: [{
  match: /(<div.*?id=\"QUUX\".*?>)[\s\S]+?(<\/div>)/g,
  replacement: '' + fileName + ''
}, {
  match: /(<div.*?id=\"FOOBAR\".*?>)[\s\S]+?(<\/div>)/g,
  replacement: '' + fileName + ''
}]
// ...

假设正在处理的文件名为 hello-world.html - 那么上面的示例将替换

的任何实例
<div class="foo" id="QUUX">...</div>

<div id="FOOBAR" class="foo">...</div>

<div class="foo" id="QUUX">hello-world</div>

<div id="FOOBAR" class="foo">hello-world</div>

分别。