Giter Site home page Giter Site logo

bensampaio / external-svg-sprite-loader Goto Github PK

View Code? Open in Web Editor NEW
61.0 8.0 24.0 1.82 MB

A webpack loader and plugin that generate SVG sprites out of a collection of SVG files used in your JS and CSS files

License: MIT License

JavaScript 100.00%
svg-sprites webpack svg-files sprite

external-svg-sprite-loader's People

Contributors

alazurenko avatar alexsamby avatar bensampaio avatar dependabot[bot] avatar feego avatar jdewit avatar jurmous avatar michaelcpuckett avatar rolfbabijn avatar satazor avatar schinery avatar stowball avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

external-svg-sprite-loader's Issues

Add ability to read svgoptions inside loader options

I would like to be able to do this:

{
    loader: 'external-svg-sprite-loader',
    options: {
        name: 'img/svg-sprite.[hash].svg',
        prefix: '',
        svgo: {
            plugins: [
                { removeTitle: true },
                // Remove stuff related to colors because they are unecessary
                { removeStyleElement: true },
                { removeAttrs: { attrs: '(fill|stroke|class)' } },
            ],
        }
    },
},

I think that changing https://github.com/Karify/external-svg-sprite-loader/blob/master/index.js#L52 to account for query.svgo would do it. Thoughts?

Can't run in storybook

Hello! I ran into a problem when starting a storybook with a Сheckbox src/components/base/Checkbox component that uses external-svg-sprite-loader.

Storybook webpack config - ./.storybook/main.js

I get in the console:

`
info => Using base config because react-scripts is not installed.
74% optimizing SvgStorePluginF:\Projects\webpack-broker\node_modules\external-svg-sprite-loader\lib\SvgStorePlugin.js:113
throw error;
^

TypeError: Cannot read property 'replace' of null
at SvgDocument.toSymbol (F:\Projects\webpack-broker\node_modules\external-svg-sprite-loader\lib\SvgDocument.js:158:36)
at SvgSprite.generate (F:\Projects\webpack-broker\node_modules\external-svg-sprite-loader\lib\SvgSprite.js:114:48)
at SvgStorePlugin.generateSprites (F:\Projects\webpack-broker\node_modules\external-svg-sprite-loader\lib\SvgStorePlugin.js:108:24)
at SyncHook.eval [as call] (eval at create (F:\Projects\webpack-broker\node_modules\tapable\lib\HookCodeFactory.js:19:10), :12:1)
at SyncHook.lazyCompileHook (F:\Projects\webpack-broker\node_modules\tapable\lib\Hook.js:154:20)
at Compilation.seal (F:\Projects\webpack-broker\node_modules\webpack\lib\Compilation.js:1322:23)
at compilation.finish.err (F:\Projects\webpack-broker\node_modules\webpack\lib\Compiler.js:675:18)
at hooks.finishModules.callAsync.err (F:\Projects\webpack-broker\node_modules\webpack\lib\Compilation.js:1261:4)
at AsyncSeriesHook.eval [as callAsync] (eval at create (F:\Projects\webpack-broker\node_modules\tapable\lib\HookCodeFactory.js:33:10), :20:1)
at AsyncSeriesHook.lazyCompileHook (F:\Projects\webpack-broker\node_modules\tapable\lib\Hook.js:154:20)
at Compilation.finish (F:\Projects\webpack-broker\node_modules\webpack\lib\Compilation.js:1253:28)
at hooks.make.callAsync.err (F:\Projects\webpack-broker\node_modules\webpack\lib\Compiler.js:672:17)
at _done (eval at create (F:\Projects\webpack-broker\node_modules\tapable\lib\HookCodeFactory.js:33:10), :9:1)
at _err1 (eval at create (F:\Projects\webpack-broker\node_modules\tapable\lib\HookCodeFactory.js:33:10), :32:22)
at _addModuleChain (F:\Projects\webpack-broker\node_modules\webpack\lib\Compilation.js:1185:12)
at processModuleDependencies.err (F:\Projects\webpack-broker\node_modules\webpack\lib\Compilation.js:1097:9)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] storybook: start-storybook
npm ERR! Exit status 1
`
The error is reproduced on - https://github.com/maximryabov22011988/webpack-broker
Branch - preparation_before_merge

Is it possible to fix it?

Cannot read property 'split' of undefined

Some svg documents don't have viewbox property

C:\projects\...\node_modules\external-svg-sprite-loader\lib\SvgDocument.js:94
        const parts = viewBox.split(' ');
                             ^
TypeError: Cannot read property 'split' of undefined

Clearer errors when trying to use the latest version with Webpack 4

Hi!

I just spent quite a while trying to debug the errors that were thrown when trying to use this loader. When using emit: true, it wouldn't compile due to .tap not being found as a property of undefined.

I wasn't sure what was happening, but I saw that the line that was causing the error was wrapped in if (options.emit), so I tried setting emit: false, which gave me all sorts of non-explicit errors about stuff not being found in the icons' objects themselves, such as getOptions.

I was about to give up when I had the idea to check the old release notes to discover that Webpack 4 stopped being supported in 7.0.0.

Since Vue 2 & Vue CLI 4 force me to use Webpack 4 for the moment, I downgraded to version 6 and everything worked out of the box, to my relief... and slight frustration at having spent so long for something that could've been so obvious.

It would be really nice if that was clear in the docs that Webpack <5 is unsupported, and also if, before anything else, there was an error message that explicitly mentioned the Webpack incompatibility and suggested the version to use if unable to update Webpack.

For example:

This version of external-svg-sprite-loader (7.x.x) requires at least Webpack version 5.x.x or later. You are using Webpack 4.x.x. Please update Webpack. If unable to update Webpack, please use external-svg-sprite-loader version 6.x.x, the latest version that supported your version of Webpack.

That's really long-winded though. There would probably be a smarter and more concise way to do this.

It would especially help Vue users who, through their use of Vue 2 and Vue CLI 4, may not be able to update to Webpack 5, and might even not be aware that their Webpack version is outdated due to it being obfuscated by Webpack CLI and it not being upgradable (AFAIK) unless the project is ported to Vue 3.

Edit: Also wanted to compliment you on the code. It's easy to read, well-organized, and there are helpful comments. You don't see that kind of quality often, and I really appreciated it while looking for the problem.

Unable to run it in the local

@bensampaio

Getting error as below

_`module.js:549
throw err;
^

Error: Cannot find module 'webpack/lib/Chunk'
at Function.Module._resolveFilename (module.js:547:15)
at Function.Module._load (module.js:474:25)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object. (/Library/WebServer/Documents/external-svg-sprite-loader/lib/SvgStorePlugin.js:3:15)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module.load (module.js:497:3)`

am i missing something. i couldn't find Chunk in my webpack installation in node_modules

Alternative (simpler) way to address the images inside the sprite (no math)

The external-svg-sprite-loader module addresses the individual images by doing math and resizing for the images. This (among other things) also distorts the image proportion when the image is rendered without width/height attributes of e.g. <img src="...#view-xyz"/>.

FYI, there is an alternative (and probably simpler) approach used by svg-sprite-loader:

<svg ...>
  <defs>
    <style>
      .sprite-symbol-usage {display: none;}
      .sprite-symbol-usage:target {display: inline;}
    </style>
    <symbol viewBox="0 0 100 114" id="img1">...</symbol>
    <symbol viewBox="0 0 50 50" id="img2">...</symbol>
  </defs>
  <use id="view-img1" xlink:href="#img1" class="sprite-symbol-usage" />
  <use id="view-img2" xlink:href="#img2" class="sprite-symbol-usage" />
</svg>

There is no math/resizing here, and also we can see that all the images render at (0, 0) with their native width and height; the images are invisible due to .sprite-symbol-usage class.

But when the sprite file is addressed as e.g. <img src="sprite.svg#view-img2"/>, then, due to :target pseudo-class, the selected <use/> becomes visible.

P.S.
The full demo:

a.svg:

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <style>
      .sprite-symbol-usage {display: none;}
      .sprite-symbol-usage:target {display: inline;}
    </style>
    <symbol viewBox="0 0 16 16" id="img1" fill="none">
      <path d="M15 8C15 8 11.9 11.5 8 11.5C4.1 11.5 1 8 1 8C1 8 4.1 4.5 8 4.5C11.9 4.5 15 8 15 8Z" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
    </symbol>
    <symbol viewBox="0 0 16 16" id="img2" fill="none">
      <path d="M15.5 6.5V13.5C15.5 14.6 14.6 15.5 13.5 15.5H3.5C2.4 15.5 1.5 14.6 1.5 13.5V6.5" stroke="black" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
    </symbol>
  </defs>
  <use id="view-img1" xlink:href="#img1" class="sprite-symbol-usage" />
  <use id="view-img2" xlink:href="#img2" class="sprite-symbol-usage" />
</svg>

a.html:

<img src="a.svg#view-img2" />

SvgStorePlugin fails if there are any other unrelated errors in the build

Hey! I've run into an issue when there's some sort of error in my build (for example, an eslint error that comes via eslint-loader), then SvgStorePlugin fails. That's probably because webpack does not emit if there are any errors.

Versions (ask if anything else may be of importance):

"webpack": "^5.16.0"
"external-svg-sprite-loader": "^7.1.1"

Stack trace:

/home/mihkel/dev/garage/wordpress-base/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:223
                    if (typeof source._name === 'string') {
                                      ^

TypeError: Cannot read property '_name' of null
    at SvgStorePlugin.replaceSpritePathsInModuleWithInterpolatedPaths (/home/mihkel/dev/garage/wordpress-base/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:223:39)
    at SvgStorePlugin.fixSpritePathsInModules (/home/mihkel/dev/garage/wordpress-base/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:97:22)
    at Hook.eval [as call] (eval at create (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:19:10), <anonymous>:5:16)
    at Hook.CALL_DELEGATE [as _call] (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/tapable/lib/Hook.js:14:14)
    at Compilation.seal (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/lib/Compilation.js:2096:37)
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/lib/Compiler.js:1054:20
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/lib/Compilation.js:1925:4
    at _next4 (eval at create (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:23:1)
    at eval (eval at create (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:68:1)
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:332:11
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/neo-async/async.js:2830:7
    at Object.each (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/neo-async/async.js:2850:39)
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:311:18
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/neo-async/async.js:2830:7
    at Object.each (/home/mihkel/dev/garage/wordpress-base/node_modules/webpack/node_modules/neo-async/async.js:2850:39)
    at /home/mihkel/dev/garage/wordpress-base/node_modules/webpack/lib/FlagDependencyExportsPlugin.js:46:16

Excluding </view>

Is there a way to exclude the view tags from being built? We're not really using it and would like to save the space if possible. Thanks

If `ExtractedModule` is null the code fails to compile

See https://github.com/karify/external-svg-sprite-loader/blob/90e052a7463a934927dc12f0d156d5ff67fd4a50/lib/SvgStorePlugin.js#L118

I get the following error:

TypeError: Right-hand side of 'instanceof' is not an object
    at chunk.modules.forEach (node_modules\external-svg-sprite-loader\lib\SvgStorePlugin.js:118)

I the extract-text-webpack-plugin must have change because it does not appear to export ExtractedModule any longer.

Adding an additional statement like this, at the top of the file, would solve this issue.

if (!ExtractedModule) {
  try {
    ExtractedModule = require('extract-text-webpack-plugin/dist/lib/ExtractedModule').default;
  }
  catch (e) {
    ExtractedModule = null;
  }
}

Webpack-dev-server support?

First of all, great plugin!

However, it doesn't seem to work with webpack-dev-server because that runs on a separate domain. Is there any chance you can add an option to inject the SVG into the page via AJAX so that we can work around this?

"TypeError: loaders is not iterable" after upgrade to v4

After upgrading to external-svg-sprite-loader version 4, my app is now throwing the follow error when I run Webpack (version 4.25.1):

TypeError: loaders is not iterable
    at SvgStorePlugin.injectSpritesIntoRules (.../node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:177:35)
    at SvgStorePlugin.apply (.../node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:51:14)
    at webpack (.../node_modules/webpack/lib/webpack.js:47:13)
    ...

I followed the external-svg-sprite-loader version 4 upgrade instructions but I must be missing something because I haven't been able to figure this out.

My webpack.config.js now looks like this (abbreviated):

const SvgStorePlugin = require("external-svg-sprite-loader");

module.exports = (env, argv) => {
  return {
    module: {
      rules: [
        {
          test: /\.svg$/,
          include: path.resolve(__dirname, "node_modules/foo-bar/images"),
          use: {
            loader: SvgStorePlugin.loader,
            options: {
              name: "foo/bar-sprite.svg",
              iconName: argv.mode === "development" ? "[name]" : "[name]-[hash:5]"
            }
          }
        },
        {
          test: /\.svg$/,
          include: path.resolve(__dirname, "src/images"),
          use: {
            loader: SvgStorePlugin.loader,
            options: {
              name: "svgs/sprite.svg",
              iconName: argv.mode === "development" ? "[name]" : "[name]-[hash:5]"
            }
          }
        }
      ]
    },
    plugins: [
      new SvgStorePlugin()
    ]
  }
}

angular13 not generate sprite file

when i want to use this loader in angular13, it not operation properly
below is my webpack configeration
image

page show like this
image

loader is working,but not generate sprite file,how can i fix this problem?

Can not generate svg sprite?

I used this plugin to generate svg sprite when it appeared, the following question. Some values can not be generated and become NaN. I can not find what is the reason, can you solve this problem?

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <symbol id="icon-loading-7726d"></symbol>
        <symbol id="icon-error-b67ed"></symbol>
        <symbol id="icon-logo-b2031"></symbol>
        <symbol id="icon-chat-e3544"></symbol>
        <symbol id="icon-check-circle-o-71bb6"></symbol>
        <symbol id="icon-check-circle-25051"></symbol>
    </defs>
    <view id="view-icon-loading-7726d" viewBox="0 0 NaN 50"></view>
    <view id="view-icon-error-b67ed" viewBox="NaN 0 NaN 50"></view>
    <view id="view-icon-logo-b2031" viewBox="NaN 0 NaN 50"></view>
    <view id="view-icon-chat-e3544" viewBox="NaN 0 NaN 50"></view>
    <view id="view-icon-check-circle-o-71bb6" viewBox="NaN 0 NaN 50"></view>
    <view id="view-icon-check-circle-25051" viewBox="NaN 0 NaN 50"></view>
    <use id="icon-loading-7726d" xlink:href="#icon-loading-7726d" width="NaN" height="50" x="0" y="0"></use>
    <use id="icon-error-b67ed" xlink:href="#icon-error-b67ed" width="NaN" height="50" x="NaN" y="0"></use>
    <use id="icon-logo-b2031" xlink:href="#icon-logo-b2031" width="NaN" height="50" x="NaN" y="0"></use>
    <use id="icon-chat-e3544" xlink:href="#icon-chat-e3544" width="NaN" height="50" x="NaN" y="0"></use>
    <use id="icon-check-circle-o-71bb6" xlink:href="#icon-check-circle-o-71bb6" width="NaN" height="50" x="NaN" y="0"></use>
    <use id="icon-check-circle-25051" xlink:href="#icon-check-circle-25051" width="NaN" height="50" x="NaN" y="0"></use>
</svg>

SVGO Options

I've noticed you accept svgoOptions as a parameter but haven't seen any documentation. I'm currently running svgo locally before pushing to the repo with svgo --disable=removeViewBox --enable=removeTitle but not sure how I'd pass this to external-svg-sprite-loader.

Any guidance would be appreciated.

Thanks

Odd behavior when generating a manifest file

I'm generating multiple sprites with the following options:

{
    name: 'sprites/global.[hash:8].svg',
    iconName: '[name]',
}
{
    name: 'sprites/brand-one.[hash:8].svg',
    iconName: '[name]',
}
{
    name: 'sprites/brand-two.[hash:8].svg',
    iconName: '[name]',
}

In addition, I'm using webpack-assets-manifest to generate a manifest.json, which maps plain file names to generated, hashed file names. webpack-assets-manifest creates a file like this:

{
  "global.svg": "/static/sprites/global.bc0840f3.svg",
  "brand.svg": "/static/sprites/brand-one.b71064f3.svg"
}

The problem is that the contents of the manifest.json file contains only a single brand.svg entry, which is named wrong (should be sprites/brand-one.svg) and in addition to that, it lacks the file sprites/brand-two.svg.

I was not able to find out what the actual problem is, but could it be that external-svg-sprite-loader is emitting files in a not-so-optimal format or something similar?

The correct output of the manifest.json file would be:

{
  "sprites/global.svg": "/static/sprites/global.bc0840f3.svg",
  "sprites/brand-one.svg": "/static/sprites/brand-one.b71064f3.svg",
  "sprites/brand-two.svg": "/static/sprites/brand-one.b71064f3.svg"
}

Of course, this could also be a bug in webpack-assets-manifest, but I thought I may ask here first to be sure it's not a problem with external-svg-sprite-loader or my configuration or something. What is a bit confusing is the fact that the key in the manifest.json is called brand.svg and not brand-one.svg, which is weird, because brand.svg is not something I have configured anywhere at all.

Outputting stringified object

.foo {
  background: url("data:image/svg+xml,module.exports = %7B symbol: './sprite.260eb415c771c8a967d00f1e5992e300.bundle.svg%23icon-logo-c2a81', view: './sprite.260eb415c771c8a967d00f1e5992e300.bundle.svg%23view-icon-logo-c2a81', viewBox: '0 0 111.9 57.29', toString: function () %7B return this.view; %7D %7D;");
}

My svg sprite is getting generated, but when I require svgs (in both css and js), I get back a string (see above). Any idea why?

Hash output filename?

You've given us an option to specify the output sprite name, but is there any chance you can run it through interpolateName so that we can use a hash? This is important for cache-busting.

[hash] is not stable

I've run into an issue with the usage of [hash]. It's not stable, i.e. it does not produce consistent results. Multiple builds -> different hashes. This breaks long term caching.

I'm also running into a problem where client and server compilation passes are running in different processes and produce different hashes for the exact same code.

The results in the SSR pass emitting incorrect asset paths that then break client hydration (React).

I'm going to suggest a fix for this.

Bad behavior when using multiple instances of the plugin

When using multiple plugin instances when compiling, e.g.: doing a client & server build, there's some unexpected behavior. The reason is that my last PR added state to the SvgSprite class which is shared among the different plugin instances. This causes the updated flag to be out-of-sync, which in turn causes the replacements to be skipped.

To solve this issue, we need to move all this "stateful" flags to the SvgStorePlugin instead. I will be making a PR soon.

Support and compatibility with Webpack 4 regarding mini-css-extract-plugin

First off, thanks for taking ownership of the package, maintaining and upgrading it for webpack 5. Thank a lot!

We ran into problems with external-svg-sprite-loader@6 and [email protected] when running it wih webpack@4. I've noticed there was a fix for the latest major version 7.x, but it seems this fix was not implemented in the 6.x branch; which seems to me as if 6.x is not maintained anymore.

/node_modules/external-svg-sprite-loader/lib/SvgSprite.js:191
source = source.replace(originalResourcePathRegExp, resourcePath);
                ^
TypeError: source.replace is not a function

I understand that maintaining two separate versions is a lot of work but I hope you are considering adding the fix to the v6 version too, as [email protected] supports webpack@4 as well afaik.

Thanks for your input on this issue!

It doesn't generate svg sprite

I use next plugin's injections in my webpack.config

in rules:
{ test: /\.svg$/, use: [ { loader: SvgStorePlugin.loader, options: { name: 'sprite.svg', }, }, ], },
in plugins:
new SvgStorePlugin({}),

So, when I run project, I haven't got any sprite.svg file. By the way, urls in css correctly replaces with sprite.svg#id=.....

Where is the problem?

Using `webpack-chain` breaks default options

Hello,

I am setting up a Vue.js project using Vue CLI 3.8.4. Therefore I have to use webpack-chain to configure this plugin. Because oneOf in webpack-chain sets an options prop on the rule, (as undefined) SvgStorePlugin#injectSpriteIntoRule errors:

ypeError: Cannot read property 'name' of undefined
    at SvgStorePlugin.injectSpriteIntoRule (/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:151:43)

Basically this check:

if (!('options' in rule)) {
  rule.options = {};
}

Isn't enough.

I'm able to work around it by setting my own name in my config like this:

webpackChainConfig.module
      .rule('svg')
        .uses.clear()
        .end()
...
        .oneOf('sprite')
          .test(/sprite/)
            .use('external-svg-sprite-loader')
              .loader(SvgStorePlugin.loader)
              .options({
                name: 'img/sprite.svg',
              })
            .end()

Public path is not respected

Hi!

I'm trying to use this plugin but I'm having an issue with publicPath. The sprite is generated correctly but the svg output for each icon do not contain the /build/ prefix:

{ symbol: '/img/tf-svg-sprite.svg#tf-facebook-d5046',
  view: '/img/tf-svg-sprite.svg#view-tf-facebook-d5046',
  viewBox: '0 0 56.693 56.693',
  toString: [Function: toString] }

should be:

{ symbol: '/build/img/tf-svg-sprite.svg#tf-facebook-d5046',
  view: '/build/img/tf-svg-sprite.svg#view-tf-facebook-d5046',
  viewBox: '0 0 56.693 56.693',
  toString: [Function: toString] }

This causes img/tf-svg-sprite.svg to be downloaded and fails with 404.

Adding the public path to getUrlToSymbol and getUrlToView works, but I'm not sure if this is the correct fix.

Styles are not interpreted in `<use>` Tag

The colors of my icons are missing as the styles not seem to be interpreted for the icons with classNames.

<symbol> definition in the sprite:

<symbol xmlns="http://www.w3.org/2000/svg" id="icon-logo-d32ed" viewBox="0 0 957.31 481.44">
  <defs>
    <style>.cls-1{fill:#7cd6df}</style>
  </defs>
  <path class="cls-1" d="OMITTED"/>
  <!-- More paths -->
</symbol>

<view> definition in the sprite:

<view xmlns="http://www.w3.org/2000/svg" id="view-icon-logo-d32ed" viewBox="0 0 99.48 50"/>

<use> definition in the sprite:

<use xmlns="http://www.w3.org/2000/svg" id="icon-logo-d32ed" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#icon-logo-d32ed" width="99.48" height="50" x="0" y="0"/>

<svg> in the page:

<svg><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="/static/img/sprite.svg#icon-logo-d32ed"></use></svg>

Is there a way to not lose the styles in the page?

x='NaN'

<use id="strelka" xlink:href="#strelka" width="78.75" height="50" x="NaN" y="0">
<use id="test_stand" xlink:href="#test_stand" width="33.25" height="50" x="NaN" y="0">
<use id="tractor" xlink:href="#tractor" width="33.25" height="50" x="NaN" y="0">
<use id="tractor_car" xlink:href="#tractor_car" width="33.25" height="50" x="NaN" y="0">
<use id="train" xlink:href="#train" width="33.25" height="50" x="NaN" y="0">

"external-svg-sprite-loader": "^3.3.0"

404 error

sometime get 404 error, then rebuid is ok

Duplicate IDs in sprites

I ran into a frustrating issue that might be particular to my SVG files (exported by Sketch); the bug was caused by putting them all together as a single sprite file. I looked at SVGO options but wasn't able to solve it. Would like to figure out if there's a better/permanent fix so others don't have this issue...

The symptom was that my icons were coming out all duplicated — the first one loaded seemed to be repeating for every image instance.

The cause was that the <path> elements inside each <symbol> had repeating IDs — see below how id="a" repeats (with the corresponding <use> reference to #a). The original Sketch exports, before the SVGO parsing, had IDs of id="path-1" instead of all id="a", but that still would have broken when combined into one XML file.

<symbol id="icon-play-a6b2d" viewBox="0 0 24 24">
  <defs>
    <path d="..." id="a"/>
  </defs>
  <use xlink:href="#a" transform="translate(2)" fill-rule="evenodd"/>
</symbol>
<symbol id="icon-pause-c28a5" viewBox="0 0 24 24">
  <defs>
    <path d="..." id="a"/>
  </defs>
  <use xlink:href="#a" transform="translate(4 1)" fill-rule="evenodd"/>
</symbol>
... repetition continues

I was able to fix my particular issue by going through the individual symbols in createDefs within SvgDocument.js and doing a simple .replace to create unique IDs based on the index (see below). This worked with my SVG, but I'd be nervous it might mess up more complicated SVG documents?

    static createDefs(...contents) {
      contents = contents.map( (symbol, index) => {
        const id = `a-${index}`
        return symbol.replace('xlink:href="#a"', `xlink:href="#${id}"`).replace('id="a"/>', `id="${id}"/>`)
      })
        return `<defs>${contents.join('')}</defs>`;
    }

Module build failed: TypeError: Cannot match against 'undefined' or 'null'.

image

The .svg file is exists, fine and works with other loaders (for example https://www.npmjs.com/package/svg-sprite-loader).

ERROR in ./src/assets/svg/anchor.svg Module build failed: TypeError: Cannot match against 'undefined' or 'null'. at Object.loader (/Users/macbookpro/Projects/ulmart-mobile.mobile/node_modules/external-svg-sprite-loader/index.js:37:39) @ ./src/app/app.module.js 13:10-45 @ ./src/main.js @ multi (webpack)-dev-server/client?http://0.0.0.0:9008 main.js

In external-svg-sprite-loader/index.js on line 37 you've got this:
const { addDependency, cacheable, resourcePath, options: { output: { publicPath } } } = this;,
but there is no options in webpack object, there is _compilation.outputOptions.publicPush, so you need to replace this line with this one
const { addDependency, cacheable, resourcePath, _compilation.outputOptions: { outputOptions: { publicPath } } } = this; and everything will work.

Please, tell me if i`am not right.

Deprecation warning for Chunk.modulesIterable

When using this loader / plugin with webpack 5 we get the following warning:

[DEP_WEBPACK_CHUNK_MODULES_ITERABLE] DeprecationWarning: Chunk.modulesIterable: Use new ChunkGraph API

The build passes but this should be fixed in order to use this loader / plugin with future webpack versions.

Duplicated IDs in icon sprite

Hi everyone,

i have a problem with duplicated ids inside the icon sprite. So, for example in the icon sprite there is following symbol:
<symbol id="arrow-down" viewBox="0 0 42 24"><path d="M0 3.1L2 .9 21.1 19 40 .9l2 2.2-20.9 20L0 3.1z"/>

Scrolling down the icon sprite, there is a <use>-Tag with the same id:
<use id="icon-arrow-down" xlink:href="#icon-arrow-down" width="35" height="20" x="10" y="10"></use>.

Having duplicated ids is invalid html and therefore validators will complain...

Is it possible to create an icon sprite without the <use>-Tags, means just an icon sprite with symbols?
Or to remove the id attribute from the <use>-Tags?

Looking forward to some help! Thanks!

The module removes "fill" attribute when converting to symbol

A bugreport here:

https://github.com/karify/external-svg-sprite-loader/blob/842c04a092665b724a25c9c4ff36b974808a0821/lib/SvgDocument.js#L170

Due to this explicit whitelist of attributes,

<svg width="16" height="16" viewBox="0 0 16 16" fill="none" ...>

becomes

<symbol id="..." viewBox="0 0 16 16">

I.e. fill="none" is removed and thus the image changes.

Maybe we can just copy all attributes (or blacklist some) instead of whitelisting? Because fill may not be the only one attribute...

Error when defining Rule.use as a function

I'm trying to define Rule.use as a function instead of an array, so that I can gain access to the issuer string and use that information to generate my sprite names:

{
  test: /\.svg$/,
  issuer: {
    include: /sprite\.js$/
  },
  use: (info) => ([
    {
      loader: "file-loader",
      options: { name: "[name].[contenthash].[ext]" }
    },
    {
      loader: SvgStorePlugin.loader,
      options: {
        name: `sprites/${info.issuer.split("/").pop()}.sprite.svg`,
        iconName: "[name]"
      }
    }
  ])
}

Unfortunately, this results in the following error:

Module build failed (from ./node_modules/external-svg-sprite-loader/lib/loader.js):
TypeError: Cannot read property 'addIcon' of undefined

I tried hacking the SvgStorePlugin.js file to add support for the function syntax:

injectSpritesIntoRules(rules) {
    for (const rule of rules) {
        const { oneOf: oneOfRules, rules: subRules, use: ruleUse } = rule;

        let loaders = ruleUse || [rule];
        
        // Check to see if ruleUse is a function
        if (ruleUse && {}.toString.call(ruleUse) === '[object Function]') {
          loaders = ruleUse();
        }

But sprite still ends up being undefined in loader.js:

function loader(content) {
    const { addDependency, resource, resourcePath } = this;

    // Get callback because the SVG is going to be optimized and that is an async operation
    const callback = this.async();

    // Parse the loader query and apply the default values in case no values are provided
    const { iconName, publicPath, sprite, svgoOptions } = Object.assign({}, DEFAULT_LOADER_OPTIONS, loaderUtils.getOptions(this));

    console.log(sprite); // undefined :(

I'd be willing to submit a pull request if I can figure this out, but I'm stuck. Any ideas?

Access all the sprites in the SvgStore plugin

I have a use-case where I need to get access to produced sprites after a webpack build, that is, every sprite metadata.

At the moment, there's getSpritesWithInterpolateName that accomplishes what I want except that it returns [] in DEV because I'm not using [hash] in development.

I will make a PR that adds this new method.

Usage in HTML / Pug files?

This loader looks great and I can get it to build the SVG files just fine.

However, I'm unsure how to use this within my HTML / Pug files? I can't see an example showing this at all.

Because the ID's are generated from their original file names and then made unique, I'm unable to reference them. e.g. If I have an SVG like 'mark.svg', I'm unable to do:

<svg class="c-splash__mark">
<use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="svg/sprite.svg#mark"></use>
</svg>

...because the resulting ID is something like '-mark-97878'.

I can see how to use this in JS, but would be great to see an example with just straight HTML. I'm actually using Pug templates though.

Or, is there an option to keep the ID's the same as the original filenames? That way I already know how to link to it.

Apologies if this is not an 'issue' per se, but thought it might help give some more thought to the documentation in the process?

Thank you!

consistency with others loaders in manifest.json

external-svg-sprite-loader helps me save a good clean sprite.[hash:8].svg file!
I've tried to use it with webpack-manifest-plugin and webpack-assets-manifest to generate a manifest.json, used to find the corresponding compiled /path/to/sprite.svg -> /path/to/sprite.[hash:8].svg

But I can not obtain the good filename and path to my sprite.svg file. Note that webpack-manifest-plugin and webpack-assets-manifest generate the good filenames when used with other loaders.

my config:

   loader: ExternalSvgSprite.loader,
   options: {
         name: 'img/sprite.[hash:8].svg', 
    }

what I would like to see in my manifest.json file:

{
  "img/sprite.svg": "img/sprite.8ef417c3.svg",
}

what I get with webpack-manifest-plugin, left part should not have the hash part. :

{
  "img/sprite.8ef417c3.svg": "img/sprite.8ef417c3.svg",
}

what I get with webpack-assets-manifest, left part should be img/sprite.svg :

{
  "sprite.svg": "img/sprite.8ef417c3.svg",
}

I'm not able to know if it's really a problem with external-svg-sprite-loader, but as the results are not consistent I ask here.

OriginalSource location

It appears that webpack changed since you published.

Error: Cannot find module 'webpack/lib/OriginalSource'
    at Function.Module._resolveFilename (module.js:469:15)
    at Function.Module._load (module.js:417:25)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/tauren/repos/exp/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:4:24)

I believe you need to import webpack-sources/lib/OriginalSource in SvgStorePlugin.js.

However, after change this, I'm getting another error:

/Users/tauren/repos/exp/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:40
    constructor({
               ^

TypeError: Cannot match against 'undefined' or 'null'.
    at new SvgStorePlugin (/Users/tauren/repos/exp/node_modules/external-svg-sprite-loader/lib/SvgStorePlugin.js:40:16)
    at module.exports (/Users/tauren/repos/exp/internals/webpack/webpack.base.babel.js:87:5)

This is resolved by explicitly passing true in the webpack plugins config:

 new SvgStorePlugin(true)

Support webpack 2

It passed some time since 2.2 final release was published. Currently, this plugin does not work on 2.2:

Error: Cannot find module 'webpack/lib/OriginalSource'

Add publicPath option

As I described here, there's problems when we use a output.publicPath with different scheme/host/port (CDN).

It would be useful to have a publicPath option that, if defined it would be used instead of output.publicPath.

I will be doing a PR adding this feature if you agree!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.