external-svg-sprite-loader
external-svg-sprite-loader copied to clipboard
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?
Hmm I guess this is a new feature... I don't think it was possible to pass a function to use when I came up with this idea. This was necessary to fix several complex issues but I don't think it will work for this case...
I would like to tell you how to go forward but I can't really come up with any idea right now. Although, I can tell you that what you are trying to do won't work. Unfortunately, I am quite busy at the moment so I don't think I'll have time to look into this any time soon 😞
Side note: You can detect functions in JS using ruleUse instanceof Function. No need for toString trickery :p
Thanks @bensampaio! I was able to satisfy the requirements of my project by doing the following, so I no longer need to use Rule.use as a function. It would still be a nice feature to have though.
const spriteManifests = glob.sync(path.resolve(__dirname, "src/**/*sprite.js"));
spriteManifests.forEach(issuer => {
const fileName = issuer.split("/").pop().replace(".js", "");
rules.push({
test: /\.svg$/,
issuer: {
include: issuer
},
use: [{
loader: SvgStorePlugin.loader,
options: {
name: `dist/sprites/${fileName}.[contenthash].svg`,
iconName: "[name]"
}
}]
});
});