webpack打包後css命名衝突問題

最近在寫一個vue項目,無心間出現了這樣一個小問題。css

一個單頁面應用,有視圖a和a.css,視圖b和b.css。而後通過webpack打包的時候,a.css b.css都會一次性加載進來,這樣若是第一次只顯示視圖a,b.css中的樣式和a.css中有衝突的話,就會影響視圖a的顯示。html

其實這個問題很簡單嘛,就是給a.css和b.css各自一個命名空間就好啦,保證css中的class名稱不會重複。vue

emmmmm... 感受有點太粗暴?webpack

仍是想了解一下有什麼官方解決方案,而後就進行了以下探究。web

方法一:vue的style scope

<style> 標籤加入 scope 屬性,這樣它的 CSS 只做用於當前組件中的元素。vue經過PostCss來實現這樣的功能。算法

其原理在於爲style scope中的class定義屬性選擇器,同時在使用該class的標籤中添加該屬性。所以,style scope中定義的class只能在當前組件中使用。 例如:性能

// 轉化前
<style scoped>
.example {
  color: red;
}
</style>

<template>
  <div class="example">hi</div>
</template>

// 轉化後
<style>
.example[data-v-f3f3eg9] {
  color: red;
}
</style>

<template>
  <div class="example" data-v-f3f3eg9>hi</div>
</template>

仔細想一想,這種方法和以前咱們本身的簡單粗暴的方法好像並無什麼本質上的區別。插件

而且存在一些缺點:code

  1. 因爲本質是使用屬性選擇器,所以性能不太好
  2. 若是在style scope中定義的是class 或者id其實還好。要是定義p標籤這種,會特別特別慢。
  3. 若是存在.a .b這樣的後代類定義,那麼將要去匹配.a的每個.b後代,並給.b加屬性。若是.a的後代是一個遞歸子組件,則會很是影響性能。

方法二:CSS modules

<style> 標籤加入 module 屬性。component

配置:想要使用css modules須要在webpack配置文件中配置:

options: {
   cssModules: {
      // 設置命名格式
      localIdentName: '[name]---[local]---[hash:base64:5]',
      camelCase: true
   }
}

此時在通過webpack編譯時,會將css module中的class按照預設的命名規則生成統一的名字,用於區分使用。 例如:

// components/Button.css 
.normal { /* normal 相關的全部樣式 */ }
.disabled { /* disabled 相關的全部樣式 */ }
/* components/Button.js */

import styles from './Button.css';
console.log(styles);
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`

// 轉化後生成的html爲
<button class="button---normal---abc53">Submit</button>

其中 button---normal---abc53 是 CSS Modules 按照 webpack中的 localIdentName 規則自動生成的 class 名。其中的 abc53 是按照給定算法生成的序列碼。這樣能夠保證css名稱的一致性。

其實這種方法本質上和上述方法一致,保證css中class的惟一性,所有打包到一個css文件中,在加載的時候一次性所有加載。

方法三:webpack按需加載

感受最完美的方法應該是webpack按需加載css

可是想要抽出vue中的css的話須要使用ExtractTextPlugin插件,此插件沒法實現css的按需加載

相關文章
相關標籤/搜索