2017-08-27 36 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