在Grunt任务中读取文件名

时间:2017-10-03 10:51:58

标签: javascript html coffeescript gruntjs rename

我已经让Grunt设置为使用grunt-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页面替换为它,因此Grunt任务肯定有效。而替换是一个功能的原因是因为我计划在以后添加一些额外的东西,但只是想让它现在正常工作。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

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

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

首先gruntNode.js上运行,因此调用window.location.href会产生错误,因为要处理的.html文件未加载到网络浏览器中。 window.location.hrefBOM的约定,通常仅适用于浏览器环境。

带有标准任务配置的

grunt-replace不提供获取正在处理的文件名的机制。但是,由于grunt-replacemulti-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: '$1' + fileName + '$2'
          }]
        },
        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循环遍历通过glob模式'src/*.html'找到的每个文件。

  3. fileName变量是通过当前filePath获得的。

  4. forEach语句的每个循环期间,生成Target并将其添加到config对象。

  5. 退出forEach循环时,config对象通过utlizing grunt.config添加到replace任务/对象,最后调用grunt.task.run

  6. <强>正则表达式

    那么下面这部分是做什么的?

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

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

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

    因此,假设上面的代码段位于名为index.html的文件中 - 然后生成的文件将显示为:

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

    但是,如果在结果文件中它应该读取(即它应该包括文件后缀.html):

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

    ...然后你需要在第5行更改fileName变量的赋值。 17 Gruntfile.js到:

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

    多次匹配

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

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

    假设正在处理的文件名为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>
    

    分别