2017-08-27 35 views
1

我正在處理一個大型單頁應用程序,其中包含非常大的CSS &由Webpack生成的JS文件,當應用程序最初加載時會導致flash of unstyled content。爲了避免這種情況,我希望將CSS的關鍵部分打印到文檔的頭部,以便在瀏覽器處理CSS的其餘部分時,文檔不會顯示爲無風格。如何使用Webpack將關鍵CSS打印到index.html中?

這個CSS是用SASS編寫的,依賴於全局應用變量,因此webpack必須處理這些文件,然後將它們從SASS編譯到CSS,然後再將它們打印到文檔頭。

Webpack如何做到這一點?

回答

1

您需要使用ExtractTextPlugin才能從js文件中提取它並寫入單個文件,以便您可以將其鏈接到html頭部。

看看它如何與sass-loader一起使用。

const extractSass = new ExtractTextPlugin({ 
    filename: '[name].css', 
}) 

module: { 
    rules: [ 
     { 
     test: /\.(scss)$/, 
     use: extractSass.extract({ 
      use: [{ 
      loader: 'css-loader', options: { 
       sourceMap: true, 
       minimize: true 
      } 
      }, { 
      loader: 'sass-loader', options: { 
       sourceMap: true, 
       minimize: true 
      } 
      }], 
      // use style-loader in development 
      fallback: 'style-loader' 
     }) 
     } 
    ] 
    }, 
    plugins: [ 
    extractSass, 
    ] 
+0

但怎麼能只用於CSS的一部分?此外,這將加載作爲外部源的CSS,並且我希望它被打印到HEAD –

+0

您的js文件中的每個css和scss導入都將被鏈接到您提到的ExtractTextPlugin的css文件中。例如。所有用於entry.js文件的導入的css或scss文件都將寫入您指定給ExtractTextPlugin的css文件。請試試看,我相信它會起作用。 – wrufesh

+1

好吧,這樣可以讓我生成部分CSS,但它仍然會將其作爲外部資源加載。如何將其打印到HEAD以便立即可用? –

1

我做到了,是

  1. 分離重要的CSS到自己的資產與separate loader rule and ExtractTextPlugin instance的方式;
  2. 禁用默認注入html-webpack-plugin以手動在模板中注入資產;
  3. 非關鍵資產通過鏈接注入文件(example)。關鍵CSS使用compilation變量(example)內聯注入。

。您可以將邏輯放入HtmlWebpackPlugin選項中的函數中。示例在答案的最後。

這樣一來,人們幾乎可以完全控制資產的包含方式,如標籤,屬性,位置。

有幾個插件,也可能與內聯CSS和JS幫助,如

但他們帶走具有充分的靈活性控制格式,邏輯和輸出,並將其替換爲有限的配置選項。


實例配置

plugins: [ 
    //... 

    new HtmlWebpackPlugin({ 
     template: 'path-to-index-template', 
     inject: false, 

     injectCriticalCss(htmlWebpackPluginStats, compilation) { 
      return lodash(htmlWebpackPluginStats.files.chunks) 
       .map(chunk => chunk.css) 
       .flatten() 
       .filter(cssFilename => /^critical\b/.test(cssFilename)) 
       .map(cssFilename => `<style>${ 
        compilation.assets[cssFilename].source() 
       }</style>`) 
       .join('\n'); 
     }, 

     injectNonCriticalCss(htmlWebpackPluginStats) { 
      return lodash(htmlWebpackPluginStats.files.chunks) 
       .map(chunk => chunk.css) 
       .flatten() 
       .filter(cssFilename => !/^critical\b/.test(cssFilename)) 
       .map(cssFilename => `<link rel="preload" as="style" href="${ 
        cssFilename 
       }" onload="this.rel='stylesheet'"/>`) 
       .join('\n'); 
     }, 

     //... 
    }), 

    //... 
] 

,然後在模板

<html> 
<head> 

    <!-- ... --> 

    <%= htmlWebpackPlugin.options.injectCriticalCss(htmlWebpackPlugin, compilation) %> 

</head> 
<body> 

    <!-- ... --> 

    <%= htmlWebpackPlugin.options.injectNonCriticalCss(htmlWebpackPlugin) %> 

</body> 
</html> 
+0

很好的答案,謝謝。但你如何生成關鍵的CSS本身?我正在使用'html-critical-webpack-plugin',似乎它只有在'HtmlWebpackPlugin'完成它的工作後才能生成關鍵的CSS。 – MyTitle

+1

@MyTitle,就我而言,關鍵樣式是靜態的並且是已知的(當然,它們僅限於文件'critical.styl')。所以我有一個規則'{test:/^critical\.styl$/,use:extractCriticalStylesPlugin.extract(...)}',其中'extractCriticalStylesPlugin'是'ExtractTextPlugin'的一個實例,用於爲關鍵字生成一個單獨的css-asset CSS。如上所示,該資產在'style'標籤內被注入'injectCriticalCss'到index.html中。雖然我不認爲我可以用'html-critical-webpack-plugin'來設置它。 – stsloth