
A webpack plugin that converts a set of images into a spritesheet and SASS/LESS/Stylus mixins, using
spritesmith and spritesheet-templates
All ideas are shamelessly taken from gulp.spritesmith.
Example
Let's say you have the following folder structure
/
|-src
| |-ico
| | |-new.png
| | |-open.png
| | |-save.png
| | ...
| |-style.styl
| ...
|-webpack.config.js
Then you need to instantiate the plugin in the webpack config like this:
var path = require('path');
var SpritesmithPlugin = require('webpack-spritesmith');
module.exports = {
module: {
rules: [
{test: /\.styl$/, use: [
'style-loader',
'css-loader',
'stylus-loader'
]},
{test: /\.png$/, use: [
'file-loader?name=i/[hash].[ext]'
]}
]
},
resolve: {
modules: ["node_modules", "spritesmith-generated"]
},
plugins: [
new SpritesmithPlugin({
src: {
cwd: path.resolve(__dirname, 'src/ico'),
glob: '*.png'
},
target: {
image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl')
},
apiOptions: {
cssImageRef: "~sprite.png"
}
})
]
};
And then just use it
//style.styl
@import '~sprite.styl'
.close-button
sprite($close)
.open-button
sprite($open)
There are a few things to notice in config
- file-loader used for generated image
resolve
contains location of where generated image is
- cssImageRef is specified as '~sprite.png'
So the way generated image is accessed from the generated API now must be specified manually.
Config
-
src
- used to build a list of source images
cwd
should be the closest common directory for all source images;
glob
well... it is a glob
options
- optional. These options are passed down to the packages that handle the globbing of images. (We use gaze, which passes them down to globule, which also passes them down to node-glob.)
cwd
and glob
both will be passed directly to glob (and gaze
in watch mode), then the resulting list of files will be used as a list of source images
-
target
- generated files
image
- the target image's filename. Can be interpolated with loader-utils. I would recommend to use file-loader for interpolation though.
css
- can be one of the following
-
"full/path/to/spritesheet/api"
- for example path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl')
-
["full/path/to/spritesheet/api1", "full/path/to/spritesheet/api2"]
,
-
["full/path/to/spritesheet/api1", ["full/path/to/spritesheet/api2", spritesmithTemplatesOptions]]
spritesmithTemplatesOptions - is the second argument here
for example
...
css: [
path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl'),
[path.resolve(__dirname, 'src/spritesmith-generated/sprite.json'), {
format: 'json_texture'
}]
]
-
apiOptions
- optional
generateSpriteName
- a function. Takes a full path to a source image file and expected to return
name by which it will be referenced in API. Return value will be used as sprite.name
for
spritesheet-templates. Default behaviour is to
use filename (without dirname and extension)
spritesheet_name
, retina_spritesheet_name
- passed to spritesheet-templates (retina_spritesheet_name
only takes effect if apiOptions.retina
is also specified)
cssImageRef
- a path by which a generated image will be referenced in API. If target.image is interpolated, cssImageRef
should be interpolated the same way too.
handlebarsHelpers
- an object. Container for helpers to register to handlebars for our template
- Each key-value pair is the name of a handlebars helper corresponding to its function
- For example,
{half: function (num) { return num/2; }
will add a handlebars helper that halves numbers
- Note that handlebarsHelpers is global. If you have multiple instances of SpritesmithPlugin, helpers defined later will override helpers defined earlier.
-
spritesmithOptions
- optional. Options for spritesmith
-
retina
- optional, when specified, uses retina capabilities of spritesheet-templates. Can be either a suffix string (like '@2x') or an object consisting of three fields:
When used as a suffix string it applies to source files, a filename for retina spritesheet image and cssImageRef
apiOptions.generateSpriteName
will be applied to normalName
returned by retina.classifier
-
customTemplates
- optional. An object with keys and values corresponding to format names and template descriptions respectively.
Template description can be either a path/to/handlebars/template/file
or a template function
You can use templates registered here as format
in "target.css"
For example you can write something like this
var templateFunction = function (data) {
var shared = '.ico { background-image: url(I) }'
.replace('I', data.sprites[0].image);
var perSprite = data.sprites.map(function (sprite) {
return '.ico-N { width: Wpx; height: Hpx; background-position: Xpx Ypx; }'
.replace('N', sprite.name)
.replace('W', sprite.width)
.replace('H', sprite.height)
.replace('X', sprite.offset_x)
.replace('Y', sprite.offset_y);
}).join('\n');
return shared + '\n' + perSprite;
};
module.exports = {
...
plugins: [
new SpritesmithPlugin({
target: {
...
css: [
[path.resolve(__dirname, 'src/spritesmith-generated/sprite-1.css'), {
format: 'function_based_template'
}],
[path.resolve(__dirname, 'src/spritesmith-generated/sprite-2.css'), {
format: 'handlebars_based_template'
}]
]
},
customTemplates: {
'function_based_template': templateFunction,
'handlebars_based_template': path.resolve(__dirname, '../my_handlebars_template.handlebars')
},
...
})
]
}
-
logCreatedFiles
optional. When set to true
will console.log
a list of created files.
This scary readme file is a cry for help. If someone can improve it please do. Also the config itself is terrible, it could also use some improvement. I welcome any reasonable suggestions. Thank you.