Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

postcss-copy

geut3.8kMIT7.1.0

A postcss plugin to copy all assets referenced in CSS to a custom destination folder and updating the URLs.

postcss, css, postcss-plugin, copy, assets

readme

postcss-copy

Build Status Build status Coverage Status Dependency Status devDependency Status

An async postcss plugin to copy all assets referenced in CSS files to a custom destination folder and updating the URLs.

Sections
Install
Quick Start
Options
Custom Hash Function
Transform
Using postcss-import
About lifecyle and the fileMeta object
Roadmap
Credits

Install

With npm do:

$ npm install postcss-copy

Quick Start

Using postcss-cli

// postcss.config.js
module.exports = {
    plugins: [
        require('postcss-copy')({
            dest: 'dist'
        })
    ]
};
$ postcss src/index.css

Using Gulp

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var postcssCopy = require('postcss-copy');

gulp.task('buildCss', function () {
    var processors = [
        postcssCopy({
            basePath: ['src', 'otherSrc']
            dest: 'dist'
        })
    ];

    return gulp
        .src(['src/**/*.css', 'otherSrc/**/*.css'])
        .pipe(postcss(processors))
        .pipe(gulp.dest('dist'));
});

Options

basePath ({string|array} default = process.cwd())

Define one/many base path for your CSS files.

dest ({string} required)

Define the dest path of your CSS files and assets.

template ({string | function} default = '[hash].[ext][query]')

Define a template name for your final url assets.

  • string template
    • [hash]: Let you use a hash name based on the contents of the file.
    • [name]: Real name of your asset.
    • [path]: Original relative path of your asset.
    • [ext]: Extension of the asset.
    • [query]: Query string.
    • [qparams]: Query string params without the ?.
    • [qhash]: Query string hash without the #.
  • function template
    var copyOpts = {
      ...,
      template(fileMeta) {
          return 'assets/custom-name-' + fileMeta.name + '.' + fileMeta.ext;
      }
    }

preservePath ({boolean} default = false)

Flag option to notify to postcss-copy that your CSS files destination are going to preserve the directory structure. It's helpful if you are using postcss-cli with the --base option or gulp-postcss with multiple files (e.g: gulp.src('src/**/*.css'))

ignore ({string | string[] | function} default = [])

Option to ignore assets in your CSS file.

Using the ! key in your CSS:
.btn {
    background-image: url('!images/button.jpg');
}
.background {
    background-image: url('!images/background.jpg');
}
Using a string or array with micromatch support to ignore files:
// ignore with string
var copyOpts = {
    ...,
    ignore: 'images/*.jpg'
}
// ignore with array
var copyOpts = {
    ...,
    ignore: ['images/button.+(jpg|png)', 'images/background.jpg']
}
Using a custom function:
// ignore function
var copyOpts = {
    ...,
    ignore(fileMeta, opts) {
        return (fileMeta.filename.indexOf('images/button.jpg') ||
                fileMeta.filename.indexOf('images/background.jpg'));
    }
}

hashFunction

Define a custom function to create the hash name.

var copyOpts = {
    ...,
    hashFunction(contents) {
        // borschik
        return crypto.createHash('sha1')
            .update(contents)
            .digest('base64')
            .replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '')
            .replace(/^[+-]+/g, '');
    }
};

transform

Extend the copy method to apply a transform in the contents (e.g: optimize images).

IMPORTANT: The function must return the fileMeta (modified) or a promise using resolve(fileMeta).

var Imagemin = require('imagemin');
var imageminJpegtran = require('imagemin-jpegtran');
var imageminPngquant = require('imagemin-pngquant');

var copyOpts = {
    ...,
    transform(fileMeta) {
        if (['jpg', 'png'].indexOf(fileMeta.ext) === -1) {
            return fileMeta;
        }
        return Imagemin.buffer(fileMeta.contents, {
            plugins: [
                imageminPngquant(),
                imageminJpegtran({
                    progressive: true
                })
            ]
        })
        .then(result => {
            fileMeta.contents = result;
            return fileMeta; // <- important
        });
    }
};

Using copy with postcss-import

postcss-import is a great plugin that allow us work our css files in a modular way with the same behavior of CommonJS.

One thing more... postcss-import has the ability of load files from node_modules. If you are using a custom basePath and you want to track your assets from node_modules you need to add the node_modules folder in the basePath option:

myProject/
|-- node_modules/
|-- dest/
|-- src/

Full example

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var postcssCopy = require('postcss-copy');
var postcssImport = require('postcss-import');
var path = require('path');

gulp.task('buildCss', function () {
    var processors = [
        postcssImport(),
        postcssCopy({
            basePath: ['src', 'node_modules'],
            preservePath: true,
            dest: 'dist'
        })
    ];

    return gulp
        .src('src/**/*.css')
        .pipe(postcss(processors, {to: 'dist/css/index.css'}))
        .pipe(gulp.dest('dist/css'));
});

About lifecyle and the fileMeta object

The fileMeta is a literal object with meta information about the copy process. Its information grows with the progress of the copy process.

The lifecyle of the copy process is:

  1. Detect the url in the CSS files
  2. Validate url
  3. Initialize the fileMeta:

     {
         sourceInputFile, // path to the origin CSS file
         sourceValue, // origin asset value taked from the CSS file
         filename, // filename normalized without query string
         absolutePath, // absolute path of the asset file
         fullName, // name of the asset file
         path, // relative path of the asset file
         name, // name without extension
         ext, // extension name
         query, // full query string
         qparams, // query string params without the char '?'
         qhash, // query string hash without the char '#'
         basePath // basePath found
     }
  4. Check ignore function
  5. Read the asset file (using a cache buffer if exists)
  6. Add content property in the fileMeta object
  7. Execute custom transform
  8. Create hash name based on the custom transform
  9. Add hash property in the fileMeta object
  10. Define template for the new asset
  11. Add resultAbsolutePath and extra properties in the fileMeta object
  12. Write in destination
  13. Write the new URL in the PostCSS node value.

On roadmap

nothing for now :)

Credits

  • Thanks to @conradz and his rework plugin rework-assets my inspiration in this plugin.
  • Thanks to @MoOx for let me create the copy function in his postcss-url plugin.
  • Thanks to @webpack, i take the idea of define templates from his awesome file-loader
  • Huge thanks to @TrySound for his work in this project.

License

MIT

changelog

Change Log

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

Unreleased

7.1.0 - 2017-06-30

Fixed

  • Wrong encode in paths with spaces: #54

7.0.0 - 2017-05-06

Added

  • preservePath option to work with gulp or postcss-cli and their --base option

Changed

  • breaking change: The src option is ambiguous to the real objective, so I changed it to basePath
  • basePath (old src) is now optional and the default path is process.cwd()

Removed

  • relativePath and inputPath in favor of simplify the API of postcss-copy

6.2.1 - 2016-12-07 [YANKED]

6.2.0 - 2016-12-06

Added

  • cache for the write process to don`t overwrite the output file (fixed race condition)

6.1.0 - 2016-12-02

Fixed

  • concurrent tests and cache function for the transform process
  • hash parameter content

6.0.0 - 2016-11-30

Changed

  • execution of transform function: run before of the hash function (#49)

5.3.0 - 2016-10-10

Fixed

  • sould not repeat the transform process when the source is the same (related #46)

5.2.0 - 2016-09-18

Fixed

  • relativePath must return a valid dirname

5.1.0 - 2016-09-18

Fixed

  • a regression in the relativePath usage :bug:

5.0.1 - 2016-07-20

Added

  • CI for node v6

Fixed

  • revert update of eslint and path-exists since the new versions does not work with node v0.12

5.0.0 - 2016-07-20

Added

  • Query string attributes in the fileMeta: query, qparams and qhash
  • sourceInputFile attribute in the fileMeta
  • sourceValue attribute in the fileMeta

Changed

  • Change default template to [hash].[ext][query] (Breaking change)

4.0.2 - 2016-04-22

Fixed

  • issue with the ignore option

4.0.1 - 2016-04-21

Removed

  • warning for ignore files

4.0.0 - 2016-04-18

Added

  • Coverage support

Changed

  • Best ignore behaviour. Pass the fileMeta to the ignore function. #33
  • Change default template with '[hash].[ext]'.
  • Replace minimatch by micromatch.
  • Use keepachangelog format.

3.1.0 - 2016-02-23

Added

  • Appveyor support @TrySound
  • Cache support wth watcher ability. Before nothing copy if dest exists @TrySound

Changed

  • Refactory source code @TrySound
  • Refactory tests. Replace tape by ava @TrySound
  • Improve package.json @TrySound
  • Update dependencies and devDependencies @TrySound

Fixed

  • Fix path resolving

3.0.0 - 2016-02-12

Changed

  • replace keepRelativePath by relativePath custom function

2.6.3 - 2016-02-12 [YANKED]

2.6.2 - 2016-02-12 [YANKED]

2.6.1 - 2016-02-11

Fixed

  • replace _extend by Object.assign

2.6.0 - 2016-02-10 [YANKED]

2.5.0 - 2016-02-09

Added

  • minimatch support for ignore option

2.4.1 - 2016-02-09 [YANKED]

2.4.0 - 2016-02-01

Fixed

  • Correct parse/replace url - issue #4

2.3.9 - 2015-12-10

Fixed

2.3.8 - 2015-11-07 [YANKED]

2.3.7 - 2015-11-07

Added

  • add conventional changelog

2.3.6 - 2015-11-06 [YANKED]

2.3.5 - 2015-11-06 [YANKED]

2.3.4 - 2015-11-06 [YANKED]

2.3.3 - 2015-11-06 [YANKED]

2.3.2 - 2015-11-06

Changed

  • rename transformPath to inputPath

2.3.1 - 2015-11-06 [YANKED]

2.3.0 - 2015-11-05

Changed

  • Refactory source code

2.2.13 - 2015-10-06 [YANKED]

2.2.12 - 2015-10-06

Fixed

  • fix error with the parse url (pathname) when the directories has empty spaces

2.2.11 - 2015-10-06

Changed

  • Update travis
  • Update readme with vertical section contents and more examples

Fixed

  • Minor error using postcss-copy with postcss-import

2.2.10 - 2015-09-18

Changed

  • return early when processing data/absolute/hash urls

2.2.9 - 2015-09-16

Added

  • new tests to check the correct multiple url parser

Fixed

  • error with multiple urls in one line, e.g fonts of bootstrap

2.2.2 - 2015-09-14

Changed

  • simple refactory in copyFile func

Fixed

  • issue allow extra rules before/after url #1

2.2.1 - 2015-09-14 [YANKED]

2.2.0 - 2015-09-14

Added

  • new option/feature: transform and add test for it
  • eslint in test script

2.1.7 - 2015-09-13 [YANKED]

2.1.3 - 2015-09-07 [YANKED]

2.1.1 - 2015-09-07 [YANKED]

2.1.0 - 2015-09-07 [YANKED]

2.0.1 - 2015-09-07 [YANKED]

2.0.0 - 2015-09-07

Changed

  • Switch to PostCSS Async
  • Remove the fs-extra dependency

1.1.3 - 2015-09-06 [YANKED]

1.1.2 - 2015-09-05 [YANKED]

1.1.0 - 2015-09-05

  • First release tagged!