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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.