背景:
我在react項目里使用了css modules。按照在webpack中的標準配置流程,需要設置下css-loader:
{
test: /\.css$/,
loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'
}
然后很開心的把項目跑了起來,所有的css中的class都加了一段hash。
然后我把代碼傳到測試服務器上build,驚人的發現css的class有了不同的hash!
然后搜索了下原因,
<blockquote>
[hash] 是根據一個 compilation 對象計算得出的哈希值,如果 compilation 對象的信息不變,則 [hash] 不變
</blockquote>
<blockquote>
compilation 對象代表對某個版本進行一次編譯構建的過程,如果在開發模式下(例如用 –watch 檢測變化,實時編譯),則每次內容變化時會新建一個 complidation,包含了構建所需的上下文信息(構建器配置、文件、文件依賴)。
</blockquote>
簡單的說,每次代碼改動會造成hash的不同。但老子的代碼沒改!
然后又看到:
<blockquote>
I can also confirm that hashes are different on different OS. This is a logical consequence since Windows uses backslashes as path separator. It's probably also due to the fact that Windows uses CRLF for new lines. There's nothing we can do about it.
</blockquote>
所以hash還和不同的os相關(我的測試機為ubuntu,本地為windows)。
由于我的代碼是前后端渲染,不只和瀏覽器相關,node本身也要根據react來渲染出一個html出來,而其中className必須和靜態css中的className保持一致。當一套代碼跑在多個node上時,會存在html中className與css不同的風險。
那么這個問題該如何規避?
我把hash:base64:5直接改成了path。這樣就用文件的路徑做為class的唯一標識。但不好的地方,是路徑可能很長。
在css-loader中,也進行了一段說明,意識是可以自定義吐出的className:
<blockquote>
You can also specify the absolute path to your custom getLocalIdent function to generate classname based on a different schema. Note that this requires webpack >= v2.x. since to be able to pass function in.
</blockquote>
{
test: /\.css$/,
use: [
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
getLocalIdent: (context, localIdentName, localName, options) => {
return 'whatever_random_class_name'
}
}
}
]
}
這里需要webpack版本升級到2。
參考:
Hash changes if a filename is changed
你用 webpack 1.x 輸出的 hash 靠譜不?