3

I have an issue with css order that compiles with webpack.

I currently use these packages in dependencies:

  • "css-loader": "^0.28.4",
  • "style-loader": "^0.18.2",
  • "sass-loader": "^6.0.6",
  • "sass-resources-loader": "^1.3.0",
  • "webpack": "^3.5.5",

Here is my webpack.config.js

const { alias } = require('./webpack/common.js');

const path = require('path');
const webpack = require('webpack');
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const nodeEnv = process.env.NODE_ENV || 'development';
const isProd = nodeEnv === 'production';

const sourcePath = path.join(__dirname, './src');
const staticPath = path.join(__dirname, './dist');

const commonCssOptions = {
  sass: {
    loaders: ['sass-loader', 'sass-resources-loader'],
  },
  context: path.resolve(__dirname, '.'),
  output: {
    path: 'dist',
  },
};

const plugins = [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    minChunks: Infinity,
    filename: 'vendor.bundle.js',
  }),
  new webpack.DefinePlugin({
    'process.env': { NODE_ENV: JSON.stringify(nodeEnv) },
  }),
  new webpack.NamedModulesPlugin(),
  new ExtractTextPlugin({ filename: 'css/bundle.css', disable: false, allChunks: true }),
  new webpack.ContextReplacementPlugin(
    /moment[/\\]locale/,
    /(en-gb)\.js/
  ),
];

if (isProd) {
  plugins.push(
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.LoaderOptionsPlugin({
      minimize: true,
      debug: false,
      options: commonCssOptions,
    })
  );
} else {
  const dashboard = new Dashboard();
  plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.LoaderOptionsPlugin({
      options: commonCssOptions,
    }),
    new DashboardPlugin(dashboard.setData)
  );
}

module.exports = {
  devtool: isProd ? false : 'cheap-module-source-map',
  entry: {
    js: './src/index.js',
    vendor: [
      'babel-polyfill',
      'bootstrap-loader',
      'classnames',
      'react',
      'react-dom',
      'react-redux',
      'redux',
      'react-router',
      'react-router-dom',
      // 'moment',
    ],
  },
  output: {
    path: staticPath,
    publicPath: '/',
    filename: '[name].bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.html$/,
        exclude: /node_modules/,
        use: {
          loader: 'file-loader',
          query: {
            name: '[name].[ext]',
          },
        },
      },
      {
        test: /\.s?css$/,
        exclude: /node_modules/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2,
              modules: true,
              localIdentName: '[name]__[local]_[hash:base64:5]',
            },
          },
          {
            loader: 'sass-loader',
            options: {
              includePaths: [
                path.join(__dirname, './components-lib/src/assets/styles'),
              ],
            },
          },
          {
            loader: 'sass-resources-loader',
            options: {
              resources: [
                './components-lib/src/assets/styles/_variables.scss',
                './components-lib/src/assets/styles/_mixins.scss',
              ],
            },
          },
          'postcss-loader',
        ],
      },
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: [
          'babel-loader',
        ],
      },
      {
        test: /\.(woff|woff2|eot|ttf|svg)(\?.*$|$)/,
        loader: 'file-loader',
        query: {
          name: '[name].[ext]',
        },
      },
    ],
  },
  resolve: {
    extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.jsx', '.js'],
    modules: [
      'node_modules',
      sourcePath,
    ],
    alias,
  },
  plugins,
  devServer: {
    contentBase: './src',
    historyApiFallback: true,
    host: '0.0.0.0',
    port: 3000,
    compress: isProd,
    inline: !isProd,
    hot: !isProd,
    quiet: true,
    stats: {
      assets: true,
      children: false,
      chunks: false,
      hash: false,
      modules: false,
      publicPath: false,
      timings: true,
      version: false,
      warnings: false,
      colors: {
        green: '\u001b[32m',
      },
      performance: {
        hints: false,
      },
    },
  },
  externals: {
    cheerio: 'window',
    'react/lib/ExecutionEnvironment': true,
    'react/lib/ReactContext': true,
  },
};

On initial load I have wrong css order

enter image description here

But on hot reload the order becomes correct

enter image description here

My component library is a git submodule (if it is important)

2 Answers 2

1

I've noticed that including HotModuleReplacementPlugin will change CSS order on occasion, still trying to figure out why.

Sign up to request clarification or add additional context in comments.

Comments

0

I think because of the way things get re-written, the ordering is bound to change i.e. the new stuff will be at the bottom. I've also noticed Webpack not being able to guarantee the order of css. I wasn't able to find a 'webpack' solution and i'm not sure if there is one. Probably bot what you wanted to hear, sorry!

The only way i've solved it was by either using smaccs/BEM notation and/or ensuring writing css rarely/never over-writes other css. For example, if you need to use a 'modifier' to change a background from white to red, then that is actually two modifiers and the default 'base' class doesn't have a background set at all. This way you can guarantee ordering doesn't matter. TBH, this turned out to be a more readable and maintainable way of writing css, but i digress!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.