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

Scope ID Hash Salting

Open SudoSloth opened this issue 4 years ago • 4 comments

What problem does this feature solve?

When hosting multiple instances of Vue (compiled and built with different versions, by different third-party developers, from uncontrolled environments, etc) in the same browser (For instance, in a micro-front-end environment) which are consumed dynamically by a host interface, it has been observed that styles from one application may bleed in to another when the individual applications are not built using the option productionMode: true.

In this scenario, it is preferred to test functionality of the prototype application in "Development" mode against other applications similarly built. We may also provide third-party developers with boiler-plate apps, so we can reasonably expect a common setup for the application directory structure, naming conventions and bundling to aid developers get up and running quickly. Generally, one would expect the production mode to be set via the environment arguments, but currently, in order for the styles to not bleed, we have to work around this issue by using the productionMode: true option.

Under these admittedly edge-case circumstances, it has been observed that the vue-loader functionality for creating the CSS scope ID needs to be a little more robust then it currently is, as under the conditions, it is possible to achieve css hash collision making for conflicting app styles.

What does the proposed API look like?

The simplest alteration to the code to prevent hash conflict would simply be to alter line 94 of /lib/index.js from:

index.js/

const id = hash(
  isProduction
    ? (shortFilePath + '\n' + source)
    : shortFilePath
)

into

const id = hash(shortFilePath + '\n' + source)

Adding the source to the hash routine, even during non-production routine would ensure that both the hash, and any conflicting apps would be identical (which in practice should be observably correct). A side effect might be that this may slow down the hash routine, and therefore, slow dev builds - though I have no metrics to back this up.

Another easily achievable option would be to provide a "salt" option for the hash routine to aid uniqueness.

index.d.ts, line 8

interface VueLoaderOptions {
    ...
    scopeIdHashSalt?: string
}

index.js, line 94

const hashValue = isProduction
    ? (shortFilePath + '\n' + source)
    : shortFilePath

const hashSalt = options.scopeIdHashSalt || ''

const id = hash(hashValue + hashSalt)

The value of this option is that I would expect it not to impact your current tests as much as the first example but is a sure-fire means of removing the chance of hash collisions unless the developer is extremely unlucky.

Another option might be simply to use a timestamp as a bit of salt - I tentatively suggest this might be enough but testing ID generation would be troublesome.

To the Vue developers: My apologies if you feel that this should have been a bug report - After reading the code for vue-loader I wasn't sure whether this qualified as bug or a feature, since the code looked to intentionally distinguish between production and development during the hash routine, and since salting your hash was not a feature already integrated I opted to use the feature request.

SudoSloth avatar Aug 19 '20 17:08 SudoSloth

Hey guys, it's been a few weeks now and I was wondering if there is any more information I can provide to you to help your understanding of the issue. Like I said, it is edge-case and I understand its probably not an immediate priority but it does affect those application which might render and use multiple vue applications, including mine, in the same dom which have differing styles. Thanks.

SudoSloth avatar Sep 10 '20 13:09 SudoSloth

We also need this feature.

kamilic avatar Jan 19 '22 01:01 kamilic

We also need this feature

Create-Peace avatar Jun 10 '22 09:06 Create-Peace

We're facing the same situation: a huge application with multiple micro frontends that share the same vue-based component library. This library exists in multiple versions and the micro frontend teams decide on their own which version to use. From my understanding, the vue-loader uses the path to generate the hash, resulting in the same data-v-id for the same component albeit being different versions and thus causing unwanted css overrides.

One workaround we're currently checking is to install this component library with a specific version via npm install <alias>@npm:<name>. With this approach, the micro frontend teams have the ability to install/wrap the library with their own custom folder name, resulting in unique data-v-ids. It works, but having above mentioned capability seems more straightforward to me.

philtim avatar Oct 11 '22 07:10 philtim