postcss-copy

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

Downloads in past

Stats

StarsIssuesVersionUpdatedCreatedSize
postcss-copy
3837.1.07 years ago9 years agoMinified + gzip package size for postcss-copy in KB

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.extquery')

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 nodemodules. 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:
```js
{
    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
}
```
  1. Check ignore function
  2. Read the asset file (using a cache buffer if exists)
  3. Add ``content`` property in the fileMeta object
  4. Execute custom transform
  5. Create hash name based on the custom transform
  6. Add ``hash`` property in the fileMeta object
  7. Define template for the new asset
  8. Add ``resultAbsolutePath` and `extra`` properties in the fileMeta object
  9. Write in destination
  10. 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