vue-loader icon indicating copy to clipboard operation
vue-loader copied to clipboard

CSS Modules "сustom Inject name" it works incorrectly (lost index)

Open PowerfulPony opened this issue 5 years ago • 4 comments

Version

15.7.1

Reproduction link

https://github.com/PowerfulPony/vue-loader-css-modules-mixing-selector-error

App.vue

<template>
  <div id="app">
    <div :class="cssModuleA.root">Module A: Green</div>
    <div :class="cssModuleA.uniqNameA">Uniq A: Green</div>
    <div :class="cssModuleB.root">Module B: Yellow</div>
    <div :class="cssModuleB.uniqNameB">Uniq B: Yellow</div>
    <div :class="cssModuleC.root">Module C: Red</div>
    <div :class="cssModuleC.uniqNameC">Uniq C: Red</div>
  </div>
</template>

<style module="cssModuleA">
.root {
  background: green;
}
.uniqNameA {
  background: green;
}
</style>

<style module="cssModuleB">
.root {
  background: yellow;
}
.uniqNameB {
  background: yellow;
}
</style>

<style module="cssModuleC">
.root {
  background: red;
}
.uniqNameC {
  background: red;
}
</style>

Steps to reproduce

  1. Create module A, place a selector with the name X in it.
  2. Create module B, place a selector with the name X in it.

What is expected?

It is expected that the name for the A.X class will be Hash_0, and for the B.X class Hash_1. So it was in version 14. *

<div id="app">
  <div class="App_root_1N-C8_0">Module A: Green</div>
  <div class="App_uniqNameA_1Obkq_0">Uniq A: Green</div>
  <div class="App_root_1N-C8_1">Module B: Yellow</div>
  <div class="App_uniqNameB_cJTiO_1">Uniq B: Yellow</div>
  <div class="App_root_1N-C8_2">Module C: Red</div>
  <div class="App_uniqNameC_X4xZM_2">Uniq C: Red</div>
</div>

What is actually happening?

The names of the output selectors are identical Hash.

<div id="app">
  <div class="App_root_1N-C8">Module A: Green</div>
  <div class="App_uniqNameA_1Obkq">Uniq A: Green</div>
  <div class="App_root_1N-C8">Module B: Yellow</div>
  <div class="App_uniqNameB_cJTiO">Uniq B: Yellow</div>
  <div class="App_root_1N-C8">Module C: Red</div>
  <div class="App_uniqNameC_X4xZM">Uniq C: Red</div>
</div>

Because of this, it is impossible to use different modules in the same vue file, with identical class names. Since, according to the cascade, the rules described in both cases will overlap.


https://vue-loader.vuejs.org/guide/css-modules.html#custom-inject-name

I encountered this problem when I decided to update the project on vue-cli 3. *, since it uses 15. * version

Incorrect operation can be seen in the attached repository. For clarity, 6 elements with different colors are used, 3 of which have the same class (although it should be different).

I noticed that the modules work out correctly, but due to the lack of an index, a cascade occurs.

I did not find a quick way to return a lost index to the output.

Using localIdentName [N] also does not fix the problem.

PowerfulPony avatar Aug 08 '19 17:08 PowerfulPony

Maybe someone will need a temporary solution that is close to the original getLocalIdent but has index and module at its disposal

loaderOptions

css: {
  localIdentName: '[path][name][module]-[local]-[hash:base26:5]',
  getLocalIdent(context, localIdentName, localName) {
    const { resourceQuery, resourcePath } = context;
    const { index, module } = loaderUtils.parseQuery(resourceQuery);

    const selector = loaderUtils.interpolateName(context, localIdentName, {
      context: context.rootContext,
      content: resourcePath + resourceQuery + localName,
    })
      .replace(/\[local\]/gi, localName)
      .replace(/\[module\]/gi, typeof module === 'boolean' ? '' : module)
      .replace(/\[index\]/gi, index)
      .replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
      .replace(/^((-?[0-9])|--)/, '_$1');

    return selector;
  },
}

PowerfulPony avatar Aug 08 '19 20:08 PowerfulPony

in version 14, the index was passed to helpers.js here https://github.com/vuejs/vue-loader/blob/v14/lib/helpers.js#L254

PowerfulPony avatar Aug 08 '19 22:08 PowerfulPony

I think the thing helpers.js did, can be achieved in the genCSSModulesCode function: https://github.com/vuejs/vue-loader/blob/master/lib/codegen/styleInjection.js#L32

Nakroma avatar Nov 14 '19 13:11 Nakroma

I have the same issue, is there any solution for version 15.9.8?

This seems to be a config for css-loader?!

Maybe someone will need a temporary solution that is close to the original getLocalIdent but has index and module at its disposal

loaderOptions

css: {
  localIdentName: '[path][name][module]-[local]-[hash:base26:5]',
  getLocalIdent(context, localIdentName, localName) {
    const { resourceQuery, resourcePath } = context;
    const { index, module } = loaderUtils.parseQuery(resourceQuery);

    const selector = loaderUtils.interpolateName(context, localIdentName, {
      context: context.rootContext,
      content: resourcePath + resourceQuery + localName,
    })
      .replace(/\[local\]/gi, localName)
      .replace(/\[module\]/gi, typeof module === 'boolean' ? '' : module)
      .replace(/\[index\]/gi, index)
      .replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
      .replace(/^((-?[0-9])|--)/, '_$1');

    return selector;
  },
}

pbender87 avatar Jul 26 '22 09:07 pbender87