usemin и переписывание URL-адресов изображений в файлах CSS поставщика с помощью Grunt

grunt-usemin помогает мне трансформироваться

<link href="/dependencies/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="/dependencies/nanoscroller/bin/css/nanoscroller.css" rel="stylesheet" />
<link href="/dependencies/dropzone/downloads/css/dropzone.css" rel="stylesheet" />

в идеально комбинированный и минимизированный js:

<link href="scripts/8e1991c7.libraries.js" rel="stylesheet" />

После concat, cssmin и uglify у меня почти идеальная структура папок, за исключением изображений и их расположения.

Вот моя проблема:

Все файлы css этих поставщиков включают расположение изображений. Плохо то, что все они находятся в разных местах. Некоторые из них используют изображения внутри папки css, тогда как другие используют внутри папки img.

Как я могу настроить grunt usemin для перезаписи всех URL-адресов изображений?


person Cemo    schedule 31.10.2013    source источник


Ответы (6)


1) Обратные изображения. Добавьте пути к изображениям в задачу rev.

rev: {
    dist: {
        files: {
            src: [
                '<%= yeoman.dist %>/static/scripts/{,*/}*.js',
                '<%= yeoman.dist %>/static/styles/{,*/}*.css',
                '<%= yeoman.dist %>/static/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
            ]
        }
    }
}

2) Добавьте пути к файлам, которые включают расположение изображений, в задачу usemin.

usemin: {
    html: ['<%= yeoman.dist %>/{,*/}*.html'],
    css: ['<%= yeoman.dist %>/static/styles/{,*/}*.css'],
    options: {
        assetsDirs: ['<%= yeoman.dist %>','<%= yeoman.dist%>/static/images'],
    }
}

3) Запустить хрюканье.

person Frank Fang    schedule 02.12.2013
comment
Привет, не могли бы вы объяснить, как работает assetsDirs? Пробовал просматривать документацию/примеры, и мне все еще не совсем понятно. - person carlinyuen; 20.03.2014
comment
Извините за поздний ответ, но как эта конфигурация помогает минимизировать зависимости от Bower? - person Cemo; 23.05.2014
comment
@Cemo Это не направлено на минимизацию зависимостей Bower, а на переписывание путей к измененным изображениям в файлах html / css. - person Frank Fang; 14.07.2014
comment
Я просмотрел ваш вопрос и понимаю, что мой ответ вообще не решает вашу проблему. Я исправляю эту проблему, копируя все изображения в папку и заменяя все ссылки :( - person Frank Fang; 14.07.2014

Я решил проблему, используя следующее.

useminPrepare: {
    html: 'src/index.html',
    options: {
        dest: 'build',
        flow: {
            html: {
                steps: {
                    js: ['concat', 'uglifyjs'],
                    css: ['cssmin']
                },
                post: {}
            }
        }
    }
},
cssmin: {
    options: {
        root: 'src'
    }
}

Во-первых, мы переопределяем useminPrepare flow, удаляя задачу concat из потоков css. Это необходимо, потому что concat уничтожит информацию об относительном пути. Поскольку cssmin сам объединит несколько файлов вместе, отдельная задача concat только вредна. (https://github.com/yeoman/grunt-usemin/issues/225)

Наконец, мы сообщаем cssmin, где находится «корень» вашего проекта из Gruntfile. Это помогает cssmin переписать относительные URL-адреса, которые он находит относительно этого «корневого» каталога.

person Justin    schedule 28.01.2014
comment
Это выглядит как чистое решение для css и изображений, поставляемых в вашем проекте, но я не думаю, что оно решает проблему поставляемых поставщиком css, ссылающихся на предоставленные поставщиком изображения. - person JBCP; 05.02.2014
comment
Скажем, у вас есть поставщик css/images в src/vendor/blah, где blah/style.css ссылается на image.png. Пока vendor/blah/image.png копируется в каталог сборки, он будет работать отлично. Это связано с тем, что скомпилированный css будет переписан со ссылкой на vendor/blah/image.png, а не только на image.png, с которым столкнулся @Cemo. - person Justin; 05.02.2014
comment
У меня есть приложение/bower_components/select2/{select2.css|select2.png}. select2.css объединяется cssmin в app/{rev}.vendor.css. Используя ваше решение, я столкнулся с двумя проблемами: во-первых, cssmin предполагает, что png все еще находится в том же каталоге, что и файл css, он не понимает, что png все еще находится в bower_components/select2. Во-вторых, независимо от того, что я указал в качестве корня, я получаю абсолютный путь к системному каталогу моей локали в файле css. - person JBCP; 06.02.2014
comment
Похоже, вы все еще используете задачу concat до запуска cssmin. Если запущен только cssmin, мои относительные URL-адреса переписываются как «bower_components/select2/select2.png». - person Justin; 06.02.2014
comment
Я удалил concat, но я посмотрю на это снова. - person JBCP; 06.02.2014
comment
У меня был установлен поток в usemin, а не в useminPrepare. Теперь я заменяю пути, но они заменяются моим абсолютным путем к файловой системе, а не относительным путем от корня. Я буду продолжать экспериментировать, так как это мое идеальное решение. - person JBCP; 07.02.2014
comment
Использование root: '‹%= yeoman.app %›' решило мою проблему. Это решение определенно немного сложно настроить, если вы не знаете внутреннюю работу usemin и cssmin, но оно также определенно самое чистое и дает вам самые простые артефакты сборки. Спасибо! - person JBCP; 07.02.2014
comment
Без сомнения, для полной настройки требуется минута. Пожалуйста, отредактируйте мой ответ, указав все, что, по вашему мнению, поможет понять суть. - person Justin; 07.02.2014
comment
Я добавил несколько строк уточнения. Это может быть немного педантичным сейчас, но теперь это должно быть довольно ясно. Отличное исправление, кстати, я бы проголосовал за него несколько раз, если бы мог. - person JBCP; 07.02.2014

Что исправило обновление CSS background-image для меня, так это добавление шаблона CSS в options, который находит все ссылки на активы в CSS и заменяет их обновленными активами.

// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
  ...
  ...
  options: {
    ...
    ...
    // This is so we update image references in our ng-templates
    patterns: {
      js: [
        [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the JS to reference our revved images']
      ],
      css: [
        [/(assets\/images\/.*?\.(?:gif|jpeg|jpg|png|webp|svg))/gm, 'Update the CSS to reference our revved images']
      ]
    }
  }
},
person Gur Dotan    schedule 27.08.2014
comment
Это в сочетании с assetDirs заставило меня работать. - person DeezCashews; 03.06.2015
comment
Это был последний кусок, который мне был нужен. Спасибо! - person Rex Schrader; 05.09.2015

Я немного покопался и нашел пару задач, которые, похоже, выполнят свою работу: https://github.com/yeoman/grunt-filerev и https://github.com/richardbolt/grunt-cssurlrev. Единственная проблема заключается в том, что вам придется вручную настраивать пути внутри вашего Gruntfile, например:

grunt.initConfig({
    filerev: {
      images: {
        src: ['img1.png', 'img2.png'],
        dest: 'tmp'
      }
    },
    cssurlrev: {
      dist: {
        src: ['public/css/*.css']
      },
    }
});

Насколько мне известно, нет плагина, который выполняет эту задачу автоматически.

person Ben    schedule 31.10.2013
comment
Спасибо. Этот плагин немного глючит, поэтому мне пришлось реализовать аналогичный. - person Cemo; 01.11.2013

Пришлось реализовать новую задачу. Это моя предварительная реализация.

grunt.registerMultiTask('rewriteCssUrl', 'rewrite url in css', function () {
  var options = this.options({
     assets: grunt.filerev ? grunt.filerev.summary : {},
     postFilter: function identity(input){ return input}
  });

  var self = this;
  var assets = options.assets;

  self.filesSrc.forEach(function (file) {
     var css = grunt.file.read(file);
     var original = css;

     css = css.replace(/(?:src=|url\(\s*)['"]?([^'"\)]+)['"]?\s*\)?/gm, function (match, src) {
        var key = path.join(path.dirname(file), src);
        var asset = assets[path.normalize(key)];
        var val =  options.postFilter(asset);
        return match.replace(src, val || match);
     });

     if(original !== css) {
        grunt.log.writeln('✔ '.green + file + (' was changed.').grey);
        grunt.file.write(file, css);
     }
  });
});
person Cemo    schedule 01.11.2013

Мой подход к этой проблеме заключался в том, чтобы в основном создать отдельный styles/select2/select2.css для каждого стиля поставщика, а затем все соответствующие изображения могут быть скопированы Grunt в styles/select2 (не беспокоясь об относительных путях или перезаписи и т. д.) как часть скрипта. То есть:

приложение/index.html

<!-- build:css(.tmp) styles/select2/select2.css -->
<link rel="stylesheet" href="bower_components/select2/select2.css">
<!-- endbuild -->

Gruntfile.js

Добавьте новую задачу copy, которая будет копировать стили поставщиков в каталог .tmp, прежде чем они будут свернуты с помощью cssmin:

    copy: {
        // this copies bower_components/*.css into .tmp so they can be compiled
        styles: {
            expand: true,
            cwd: '<%= yeoman.app %>',
            dest: '.tmp/',
            src: [
                'styles/{,*/}*.css',
                'bower_components/**/*.css'
            ]
        },
        dist: ...

А затем, как только они будут свернуты, скопируйте соответствующие активы (в данном случае я предполагаю, что это просто изображения PNG и GIF):

        // and once we have compiled all of our stylesheets, we need to also copy over any necessary image files
        distAssets: {
            expand: true,
            cwd: '<%= yeoman.app %>/bower_components',
            dest: '<%= yeoman.dist %>/styles',
            src: [
                '**/*.png',
                '**/*.gif'
            ]
        }
    },

Наконец, добавьте новые задачи в задачу build:

grunt.registerTask('build', [
    'clean:dist',
    'replace:dist',
    'copy:styles',  // -- added
    'useminPrepare',
    // ... etc ...
    'copy',
    'rev',
    'usemin',
    'copy:distAssets'  // -- added
]);
person jevon    schedule 18.02.2014