web-dev-qa-db-fra.com

Comment arrêter FOUC lors de l'utilisation de CSS chargé par Webpack

Je reçois FOUC lors du chargement de CSS à l'intérieur de mon point d'entrée lors de l'utilisation de webpack. Si je supprime mon css d'être chargé par webpack et l'inclus juste dans mon fichier html en tant que lien normal, le problème avec FOUC disparaît.

Remarque: Ce n'est pas seulement avec bootstrap, j'ai testé avec Foundation et Materialise avec les mêmes résultats

Le code affiché ci-dessous n'est qu'un exemple de test de mon problème d'utilisation de Bootstrap.

Code HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<div class="container">
    <div class="jumbotron">
        <h1>Navbar example</h1>
    </div>
</div> <!-- /container -->

<script src="build/bundle.js"></script>
</body>
</html>

point d'entrée principal bootstrap.js

import "../node_modules/bootstrap/dist/css/bootstrap.css";
import bootstrap from 'bootstrap'

$(document).ready(function () {
   console.log('bootstrap loaded')
});

webpack.config.js

var path = require('path');
const ProvidePlugin = require('webpack/lib/ProvidePlugin');
const webpack = require("webpack");

module.exports = {
  entry: './src/bootstrap.js',
  output: {
    path: path.join(__dirname, 'build'),
    filename: 'bundle.js'
  },
    resolve: {
        extensions: ['', '.js']
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery",
            'window.jQuery': 'jquery'
        })
    ],
  devtool: 'inline-source-map',
  module: {
      resolve: {
          modulesDirectories: ['node_modules']
      },
    loaders: [
      {
        test: path.join(__dirname, 'src'),
        loader: 'babel-loader',
          query: {
              presets: ['es2015']
          }
      },
        { test: /\.css?$/, loader: 'style!css'},
        { test: /\.html$/, loader: 'html' },
        { test: /\.(png|gif|jpg)$/, loader: 'url', query: { limit: 8192 } },
        { test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url', query: { limit: 10000, mimetype: 'application/font-woff2' } },
        { test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url', query: { limit: 10000, mimetype: 'application/font-woff' } },
        { test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'file' },
    ]
  }
};
27
dan

ExtractTextWebpackPlugin vous permettra de sortir votre CSS en tant que fichier séparé plutôt que de l'intégrer dans votre bundle JS. Vous pouvez ensuite inclure ce fichier dans votre code HTML, ce qui, comme vous l'avez dit, empêche le flash de contenu non stylisé.

Je recommanderais de ne l'utiliser que dans des environnements de production, car cela empêche le chargement à chaud de fonctionner et rend votre compilation plus longue. J'ai mon webpack.config.js configuré pour appliquer le plug-in uniquement lorsque process.env.NODE_ENV === "production"; vous obtenez toujours le FOUC lorsque vous effectuez une construction de développement/exécutez le serveur de développement, mais je pense que c'est un compromis équitable.

Pour plus d'informations sur la façon de configurer cela, jetez un œil à Guide de SurviveJS .


Mise à jour: Comme indiqué dans les commentaires, ExtractTextWebpackPlugin a maintenant été remplacé par mini-css-extract-plugin - vous devez utiliser cela à la place.

25
Joe Clay

Un peu tard pour la fête, mais voici comment je fais.

Bien que je reconnaisse les mérites de l'extrait-texte-plugin, il est en proie à un bogue de reconstruction qui perturbe l'ordre CSS et est difficile à configurer. Et définir des délais d'attente dans js n'est pas quelque chose que quiconque devrait faire (c'est moche et n'est pas garanti à 100% pour empêcher fouc) ...

Mon index.html est donc:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
    <style>
      #app { display: none }
    </style>
    <title></title>
  </head>
  <body>
    <div id="app"></div>
    <script src="scripts/bundle.js"></script>
  </body>
</html>

Ensuite, dans client.js à la fin, j'ajoute:

include "./unhide.css";

... et unhide.css contient une seule ligne:

#app { display: block }

Voila, vous ne voyez rien jusqu'à ce que l'application entière soit chargée.

9
user3361481

C'est janky, mais j'enveloppe ReactDom.render () dans un setTimeout () dans mon fichier racine index.js.

setTimeout(ReactDOM.render(...), 0)

3
wkoutre