grunt-contrib-cssmin:css 源映射在开发工具中显示为空

grunt-contrib-cssmin: css source map appears empty in dev tools

我正在使用带有 cssmin 的 grunt 来缩小和连接 css 文件。 Css 文件很好地连接和缩小,但是当我尝试在“Sources”选项卡下的 chrome 开发工具中查看非缩小文件时,文件显示为空。 这是我的 cssmin 任务:

cssmin: {
    options: {
        report: 'gzip',
        keepSpecialComments: 0,
        sourceMap: true,
        outputSourceFiles: true
    },
    target: {
        files: {
            'web/assets/dist/css/vendors.min.css': [
                'bower_components/bootstrap/dist/css/bootstrap.min.css',
                'bower_components/chosen/chosen.min.css',
                'bower_components/slabText/css/slabtext.css',
                'bower_components/video.js/dist/video-js.css',
                'bower_components/video.js/dist/video-js.css'
            ],
            'web/assets/dist/css/app.min.css': [
                'app/Resources/assets/css/jumbotron-narrow.css',
                'app/Resources/assets/css/custom.css',
            ],
        }
    }
},

在 chrome 下启用了源映射设置。 web/assets/dist/css/app.min.css.map 看起来像这样:

{
    "version":3,
    "sources":["app/Resources/assets/css/jumbotron-narrow.css","app/Resources/assets/css/custom.css"],
    "names":[],
    "mappings":"AAeA,QAdA,KAeI,eAAgB,KADpB,QA6BA,WAEI,cAAe,IAAI,MAAM,QA7C7B,KACI,YAAa,KCUb,YAAa,eAAkB,WDHnC,QAFA,QACA,WAEI,cAAe,KACf,aAAc,KASlB,WACI,WAAY,EACZ,cAAe,EACf,YAAa,KAIjB,QACI,YAAa,KACb,MAAO,KACP,WAAY,IAAI,MAAM,QAI1B,yBACI,WACI,UAAW,OAGnB,qBACI,OAAQ,KAAK,EAIjB,WACI,WAAY,OAGhB,gBACI,QAAS,KAAK,KACd,UAAW,KAIf,WACI,OAAQ,KAAK,EAEjB,gBACI,WAAY,KAIhB,oCAII,QAFA,QACA,WAEI,cAAe,EACf,aAAc,EAGlB,QACI,cAAe,KAGnB,WACI,cAAe,GC3EvB,WACI,YAAa,eACb,IAAK,iCAAkC,mBAG3C,WACI,YAAa,YACb,IAAK,8BAA+B,mBAOxC,GACI,WAAY,KACZ,eAAgB,UAChB,YAAa,EACb,YAAa,YAAe,WAC5B,YAAa,EAAI,EAAI,IAAI,KAG7B,4BACI,QAAS,MACT,YAAa,KACb,aAAc,KACd,cAAe,IAGnB,UACI,UAAW,MACX,WAAY,KAIhB,oBACI,MAAO,IAGX,sBACI,gBAAiB,KACjB,YAAa,EAGjB,cACI,aAAc,QAIlB,iCACI,QAAS"
 } 

来自我的 package.json 的版本:

 "grunt-contrib-cssmin": "^0.12.0",

我做错了什么?

编辑: 首先,尝试在 Gruntfile.jsoptions 中指定一个 root,如下所示:

// ...
cssmin: {
  options: {
    // ...
    root: 'web/assets/dist/css/' // <-- Add this too.
  },
  target: {
    // ...
  }
  /...

问题

grunt-contrib-cssmin 生成的 sourceMap 文件错误地指定了 sources 数组中的路径。结果sourceMap应该如下:

app.min.css.map

{
  "version":3,
  "sources":[
    "../../../../app/Resources/assets/css/jumbotron-narrow.css",
    "../../../../app/Resources/assets/css/custom.css"
  ],
  "names":[],
  "mappings":"AAeA,QAdA,KAeI,eAAgB,KADpB,QA6BA,WAEI,cAAe,IAAI,MAAM,QA7C7B,KACI,YAAa,KCUb,YAAa,eAAkB,WDHnC,QAFA,QACA,WAEI,cAAe,KACf,aAAc,KASlB,WACI,WAAY,EACZ,cAAe,EACf,YAAa,KAIjB,QACI,YAAa,KACb,MAAO,KACP,WAAY,IAAI,MAAM,QAI1B,yBACI,WACI,UAAW,OAGnB,qBACI,OAAQ,KAAK,EAIjB,WACI,WAAY,OAGhB,gBACI,QAAS,KAAK,KACd,UAAW,KAIf,WACI,OAAQ,KAAK,EAEjB,gBACI,WAAY,KAIhB,oCAII,QAFA,QACA,WAEI,cAAe,EACf,aAAc,EAGlB,QACI,cAAe,KAGnB,WACI,cAAe,GC3EvB,WACI,YAAa,eACb,IAAK,iCAAkC,mBAG3C,WACI,YAAa,YACb,IAAK,8BAA+B,mBAOxC,GACI,WAAY,KACZ,eAAgB,UAChB,YAAa,EACb,YAAa,YAAe,WAC5B,YAAa,EAAI,EAAI,IAAI,KAG7B,4BACI,QAAS,MACT,YAAa,KACb,aAAc,KACd,cAAe,IAGnB,UACI,UAAW,MACX,WAAY,KAIhB,oBACI,MAAO,IAGX,sBACI,gBAAiB,KACjB,YAAa,EAGjB,cACI,aAAc,QAIlB,iCACI,QAAS"
}

注意 sourceRoot 前缀 ../../../../ 添加到 sources 数组中的每个路径。

SourceMap Specification 中的一个部分显示:

Resolving Sources

If the sources are not absolute URLs after prepending of the “sourceRoot”, the sources are resolved relative to the SourceMap (like resolving script src in a html document).

如果指定 root 路径,(如最初提到的),不能解决问题,则表明规范的这一部分未被遵守grunt-contrib-cssmin.


备用解决方案

如果最初建议的修复不起作用,则考虑添加一个自定义 Task 来调用一个函数,该函数修复 sourceMap(s)[=111 之后的每个 sources 路径=] 由 grunt-contrib-cssmin 创建。

你可以这样做:

Gruntfile.js

module.exports = function (grunt) {

  grunt.initConfig( {
    cssmin: {
      options: {
        report: 'gzip',
        keepSpecialComments: 0,
        sourceMap: true,
        outputSourceFiles: true
      },
      target: {
        files: {
          'web/assets/dist/css/vendors.min.css': [
            'bower_components/bootstrap/dist/css/bootstrap.min.css',
            'bower_components/chosen/chosen.min.css',
            'bower_components/slabText/css/slabtext.css',
            'bower_components/video.js/dist/video-js.css'
          ],
          'web/assets/dist/css/app.min.css': [
            'app/Resources/assets/css/jumbotron-narrow.css',
            'app/Resources/assets/css/custom.css'
          ]
        }
      }
    }
  });

  /**
   * Helper function prefixes sources paths in sourceMap files with a sourceRoot.
   *
   * `grunt-contrib-cssmin` does not apply the correct sourceRoot for each
   * path in the `sources` Array. See github issue #248 for further info:
   * (https://github.com/gruntjs/grunt-contrib-cssmin/issues/248)
   * 
   * @param {String} filePath - The path to the sourceMap to fix.
   * @param {String} sourceRootPrefix - The sourceRoot prefix e.g. ../../
   */
  function prefixSourceMap(filePath, sourceRootPrefix) {
    var json = grunt.file.readJSON(filePath);
    json.sources = json.sources.map(function (_path) {
      return sourceRootPrefix + _path;
    });
    grunt.file.write(filePath, JSON.stringify(json));
  }

  // Register Task to invoke function for fixing paths in each sourceMap file.
  grunt.registerTask('fixSourceMaps', 'Fix paths in each sourceMap', function () {
    prefixSourceMap('web/assets/dist/css/vendors.min.css.map', '../../../../');
    prefixSourceMap('web/assets/dist/css/app.min.css.map', '../../../../');
  });

  grunt.loadNpmTasks('grunt-contrib-cssmin');

  grunt.registerTask("default", [
    'cssmin',
    'fixSourceMaps' // <-- Must be after cssmin tasks.
  ]);
};

备注

  1. 名为 fixSourceMaps 的自定义 grunt.registertask 为每个 sourceMap 文件调用 prefixSourceMap 函数来修复。

  2. 两个参数传递给prefixSourceMap函数,即:

    • filePath - 要修复的 sourceMap 的路径。
    • sourceRootPrefix - sourceRoot 前缀,例如../../
  3. 为了修复 sourceMap 文件(vendors.min.css.mapapp.min.css.map),sourceRootPrefix 参数指定为 ../../../../ - 由于生成的 .min.css 文件与其目录中原始 unminified.css 文件之间的关系,这被指定为四个级别结构。

如果您要添加另一组 .css 文件以缩小您的 cssmin.target.files 任务,其中生成的 .min.css 文件与 之间的关系unminified.css 文件不是四层,您需要指定不同的 sourceRootPrefix 值。

例如,假设在 cssmin.target.files 中,以下 css 将被缩小:

// ...
target: {
  files: {
    //...
    'web/assets/quux.min.css': [ // <-- Two levels deep
      'path/to/file/foo.css',
      'path/to/file/baz.css'
    ],
    // ...
  }
}
// ...

由于结果 quux.min.css 保存在两层目录中,因此 sourceRootPrefix 参数作为 '../../' 传递给 prefixSoureMap 函数。例如:

//...
grunt.registerTask('fixSourceMaps', 'Fix paths in each sourceMap', function () {
  prefixSourceMap('web/assets/quux.min.css.map', '../../');
  //...
});
//...

如上评论所述,我的 Gruntfile 中有 2 个问题:

  • 缺少 root 指令,如@RobC
  • 所解释
  • 网络服务器无法访问原始资产,因此我将它们移动到虚拟主机的网络根目录下的某个位置。就我而言 web/assets。这是我正在执行的 cssmin 任务:

    cssmin: {
        options: {
            root: 'web/assets/dist/css/',
            report: 'gzip',
            keepSpecialComments: 0,
            sourceMap: true,
            outputSourceFiles: true
        },
        target: {
            files: {
                'web/assets/dist/css/app.min.css': [
                    'web/assets/css/jumbotron-narrow.css',
                    'web/assets/css/custom.css',
                ],
            }
        }
    },