webpack里使用hash的坑

背景:
我在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 靠譜不?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容