css 模块查询使用最新的 css-loader 打破了 css 规则

css modules query breaks css rules with latest css-loader

使用css-loader

{
        test: /\.s?css$/,
        use: [
          { loader: 'style-loader' },
          { loader: 'css-loader',
            query: {
              modules: true,
              localIdentName: '[name]-[local]-[hash:base64:8]'
            }
          },
          { loader: 'sass-loader'}
        ]
      }

这样配置的 css-loader 似乎无法在 class 名称下找到 css 规则。 div.profile 下列出的 css 规则未在屏幕上应用。 css-loader 版本。我代码中的 1.0.0 使用 Node 10.x 运行。切换 modules: false 可显示所需的样式。

代码贴在下面。

main.js:

require('babel-runtime/regenerator');
require('babel-register');                   
require('webpack-hot-middleware/client?reload=true');
require('./index.html');

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Webpack 4</title>
  </head>
  <body>
    <div class="profile">
      <img src="./images/400.jpg" alt="">
      <h1>Hello Webpack 4</h1>
      <div id="react-root"></div>
    </div>
    <script src="/main-bundle.js"></script>
  </body>
</html>

app.js:

import React from 'react';
import ReactDOM from 'react-dom';
import Counter from './counter';
import { AppContainer } from 'react-hot-loader';

const render = (Component) => {
  ReactDOM.render(
    <AppContainer>
      <Component />
    </AppContainer>,
    document.getElementById('react-root')
  );
};

render(Counter);

if (module.hot) {
  module.hot.accept('./counter', () => {
    render(require('./counter'));
  });
}

counter.js:

import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import { css } from 'emotion';
import styled from 'react-emotion';
import styles from './main.scss';

const Fancy = styled('h1')`
  color: ${props => props.wild ? 'hotpink' : 'gold'}
`;

const red = '#f00';

const className = css`
  color: ${red};
  font-size: 3rem;
`;

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    this.addCount = this.addCount.bind(this);
  }

  addCount() {
    this.setState(() => ({ count: this.state.count + 1 }));
  }

  render() {
    const isWild = this.state.count % 2 === 0;
    return (
      <div className={styles.counter}>
        <h1 onClick={this.addCount} className={className}>Count: {this.state.count}</h1>
        <Fancy wild={isWild}>react-emotion lib allows to hook styles to component names</Fancy>
      </div>
    );
  }
}

export default hot(module)(Counter);

main.scss:

body {
  background-color: #a1b2c3;
}

.profile {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100vh;

  img {
    border-radius: 50%;
    box-shadow: 0 0 20px #000;
  }

  h1 {
    font-family: 'source-code-pro', 'sans-serif';
    font-weight: 400;
  }
}

.counter {
  border: 3px solid green;
}

原因是 index.html 中的 .profile class 名称在 counter.js 范围之外。 css 模块通过 localIdentName 模式生成 class 名称,但是 .profile class 名称在 css 之前硬编码在 index.html 中counter.js 中的模块开始发挥作用。

在counter.js

import styles from './main.scss';
console.log('styles:', styles);

产出

styles: Object { profile: "main-profile-2P-yNf0J", counter: "main-counter-Pmp5YERO" }

如何将 main-profile-2P-yNf0J class 名称更改为 index.html 我仍然不清楚。