postcss-copy
v7.1.0
Published
A postcss plugin to copy all assets referenced in CSS to a custom destination folder and updating the URLs.
Downloads
7,932
Readme
postcss-copy
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:
Detect the url in the CSS files
Validate url
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 }
Check ignore function
Read the asset file (using a cache buffer if exists)
Add
content
property in the fileMeta objectExecute custom transform
Create hash name based on the custom transform
Add
hash
property in the fileMeta objectDefine template for the new asset
Add
resultAbsolutePath
andextra
properties in the fileMeta objectWrite in destination
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