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

Error when defining Rule.use as a function #62

Open
markplewis opened this issue Apr 5, 2019 · 2 comments
Open

Error when defining Rule.use as a function #62

markplewis opened this issue Apr 5, 2019 · 2 comments

Comments

@markplewis
Copy link

markplewis commented Apr 5, 2019

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?

@bensampaio
Copy link
Owner

bensampaio commented Apr 8, 2019

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

@markplewis
Copy link
Author

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]"
      }
    }]
  });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants