Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve svg sprites #13

Merged
merged 7 commits into from
Apr 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 73 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Image sizes can often get reduced between 20-60%, but this is not the only thing
* `jpeg`, `png`, `svg`, `webp` and `gif` images are supported and enabled by default but can be particularly disabled
* Provides [options](#query-params) to force inlining a single file or include the raw optimized image directly in your html (e.g. for svgs)
* Converts jpeg/png images to [`webp` if wanted](#webp) for an even smaller size
* Provides the possibility to use [`svg sprites` if wanted](#sprite) for a better performance when using the same icons multiple times (e.g. in a list)

## Table of contents

Expand Down Expand Up @@ -113,7 +114,7 @@ You can use both variants directly on an image in the `src` attribute or in your
### Query params

There are some cases where you don't want to reference a file or get a base64 data-uri but you actually want to include the raw file directly into your html.
Specially for svgs because you can't style them with css if they are in a `src` attribute on an image.
Especially for svgs because you can't style them with css if they are in an `src` attribute on an image.

So there are additional options you can specify as query params when you import the images:

Expand Down Expand Up @@ -202,20 +203,71 @@ The inlining will only get applied to exactly this import, so if you import the
#### ?sprite

If you need to style or animate your SVGs [?include](#?include) might be the wrong option, because that ends up in a lot of DOM elements, especially when using the SVG in list-items etc.
In that case you can use `?sprite` which uses [svg-sprite-loader](https://github.com/kisenka/svg-sprite-loader) to render and inject an SVG sprite in the page automatically.
You just refer to images via `<svg><use xlink:href="#id"></use></svg>`
In that case, you can use `?sprite` which uses [svg-sprite-loader](https://github.com/kisenka/svg-sprite-loader) to render and inject an SVG sprite in the page automatically.

```javascript
import React from 'react';
import MyIcon from './icons/my-icon.svg?sprite';

export default () => (
<div>
my page..
<MyIcon />
</div>
);
```

All props passed to the imported sprite will get applied to the `<svg>` element, so you can add a class normally with `<MyIcon className="icon-class" />`.

The `svg-sprite-loader` object also gets exposed if you want to build your own component:

```javascript
import React from 'react';
import icon from './icons/icon.svg?sprite';

export default () => (
<svg viewBox={icon.viewBox}>
<use xlink:href={icon.id} />
</svg>
<div>
my page..
<svg viewBox={icon.viewBox}>
<use xlinkHref={`#${icon.id}`} />
</svg>
</div>
);
```

To also make this work for server-side rendering, you need to add these changes to your `_document.jsx` file (read [here](https://github.com/zeit/next.js#custom-document) if you don't have this file yet):

```javascript
// ./pages/_document.js
import Document, { Head, Main, NextScript } from 'next/document';
import sprite from 'svg-sprite-loader/runtime/sprite.build';

export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const pageProps = renderPage();
const spriteContent = sprite.stringify();

return {
spriteContent,
...pageProps,
};
}

render() {
return (
<html>
<Head>{/* your head if needed */}</Head>
<body>
<div dangerouslySetInnerHTML={{ __html: this.props.spriteContent }} />
<Main />
<NextScript />
</body>
</html>
);
}
}
```

## Configuration

This plugin uses [img-loader](https://www.npmjs.com/package/img-loader) under the hood which is based on [mozjpeg](https://github.com/imagemin/imagemin-mozjpeg), [optipng](https://github.com/imagemin/imagemin-optipng), [gifsicle](https://github.com/imagemin/imagemin-gifsicle) and [svgo](https://github.com/imagemin/imagemin-svgo).
Expand Down Expand Up @@ -260,7 +312,7 @@ The output path that should be used for images. This can be used to have a custo
Type: `string`<br>
Default: `'[name]-[hash].[ext]'`

Filename of the optimized images.
The filename of the optimized images.
Make sure you keep the `[hash]` part so they receive a new filename if the content changes.

#### optimizeImagesInDev
Expand Down Expand Up @@ -341,6 +393,19 @@ If you don't want next-optimized-images to handle svg images and icons (because

If you want svg images and icons to be handled but _not_ optimized, you can set this value to `null`.

#### svgSpriteLoader

Type: `object`<br>
Default:
```javascript
{
runtimeGenerator: require.resolve(path.resolve('node_modules', 'next-optimized-images', 'svg-runtime-generator.js')),
}
```

When using the [svg sprite option](#sprite), [`svg-sprite-loader`](https://github.com/kisenka/svg-sprite-loader) gets used internally.
You can overwrite the configuration passed to this loader here.

#### webp

Type: `object`<br>
Expand All @@ -358,7 +423,7 @@ If you want webp images to be handled but _not_ optimized, you can set this valu

The options specified here are the **default** values.

So if the are good enough for your use-case, you don't have to specify them to have a shorter and cleaner `next.config.js` file.
So if they are good enough for your use-case, you don't have to specify them to have a shorter and cleaner `next.config.js` file.

```javascript
// next.config.js
Expand Down
30 changes: 20 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const path = require('path');

/**
* Converts possible configuration values for an image optimizer.
*
Expand Down Expand Up @@ -160,16 +162,6 @@ const withOptimizedImages = (nextConfig) => {
config.module.rules.push({
test: getHandledFilesRegex(mozjpeg, optipng, pngquant, gifsicle, svgo),
oneOf: [
// ?sprite: add icon to sprite
{
resourceQuery: /sprite/,
use: [
{
loader: 'svg-sprite-loader',
options: getOptimizerConfig(svgSpriteLoader),
},
],
},
// ?include: include the image directly, no data uri or external file
// ?inline: force inlining an image regardless of the defined limit
...getResourceQueryLoaders('img-loader', imgLoaderOptions, urlLoaderOptions),
Expand All @@ -196,6 +188,24 @@ const withOptimizedImages = (nextConfig) => {
],
},

// ?sprite: add icon to sprite
{
resourceQuery: /sprite/,
use: [
{
loader: 'svg-sprite-loader',
options: getOptimizerConfig(svgSpriteLoader, {
runtimeGenerator: require.resolve(path.resolve(__dirname, 'svg-runtime-generator.js')),
}),
},
].concat(imgLoaderOptions.svgo !== false ? [
{
loader: 'img-loader',
options: imgLoaderOptions,
}
] : []),
},

// default behavior: inline if below the definied limit, external file if above
{
use: [
Expand Down
Loading