Umi: 通用 css modules 方案

Created on 6 Nov 2018  ·  22Comments  ·  Source: umijs/umi

使用

a.css

.a { color: red; }

b.css

.b { color: red; }

a.js

import styles from './a.css';
import './b.css';

打包 a.js,输出 css,

.a___6ESeB { color: red; }
.b { color: red }

方案

分两步,

一、通过 babel 插件处理 js 里的 css/less/sass/scss 引用

比如:

import styles from './a.css';
import './b.css';

转换为:

import styles from './a.css?cssModules';
import './b.css';

至于为啥不转换为 import styles from 'css-loader?modules!./a.css';,因为还有 postcss、extract css、css-hot-loader 等需要处理,而且 postcss 的 options 里还有函数,不能通过字符串的方式传递。

二、module.rules 里处理带 ?cssModules query 的资源,走 css modules

示例:

const rule = webpackConfig.module
  .rule('css')
  .test(/\.css$/);

applyCSSRules(
  rule.oneOf('CSSModules').resourceQuery(/cssModules/),
  { cssModules: true, less: true },
);
applyCSSRules(
  rule.oneOf('noCSSModules'),
  { cssModules: false, less: true },
);

兼容考虑

由于会有 break change,所以通过额外的配置项 autoCSSModules 开启,等 umi@3 时默认开启。

参考

type(discussion)

Most helpful comment

给 umi 项目添加以 styleName 为类名转化的方法(默认使用less文件)

  • 1 yarn add babel-plugin-react-css-modules postcss-less
  • 2 在~/config/config.js中添加
  ...
  extraBabelPlugins: [
    [
      'react-css-modules',
      {
        'exclude': 'node_modules',
        'generateScopedName': '[name]__[local]___[hash:base64:5]',
        'filetypes': {
          '.less': {
            'syntax': 'postcss-less',
          },
        },
      },
    ],
  ],
  ...
  • 3 在jsx文件中 import './style.less'

All 22 comments

style里面的样式要不要考虑一起处理了o( ̄︶ ̄)o

@sorrycc 为什么不使用cssModulesWithAffix解决呢?

export default {
  disableCSSModules: true,
  cssModulesWithAffix: true,
}

因为如果根据 import 来区分,当遇到

import styles from './a.css';
import './a.css';

的情况下(即需要 defaults import,又需要 side effect import):

  • 我们不能简单通过css文件名来判断其是否会污染全局的环境
  • 产生的代码,会有一份无 module 前缀的,一份有 module 前缀的 class name

这种表现,会比较奇怪。

import styles from './a.css';
import './a.css';

这不是正确的用法吧。

@sorrycc 这的确不是正确的用法。

但是一楼提的方案有如下问题:

  • 误用的用法不容易被检查出来。
  • 编译产生的副作用(类名的变化)依赖于调用方,看起来不是很合理。

create-react-app 这种通过文件名是否带.module.(scss|less|css)来区分的方案更合理,唯一的缺点就是文件名长了点。

误用的用法不容易被检查出来

误用后没有效果不就知道了吗?

编译产生的副作用(类名的变化)依赖于调用方,看起来不是很合理。

我觉得是合理的。create-react-app 处理 svg 也是这个逻辑,比如 import { ReactComponent } from './a.svg' 会被处理成 React 组件,import './a.svg' 则是导出文件。webpack 的 loader 就是为了让文件针对不同场景有不同输出。

@sorrycc https://github.com/mrmckeb/typescript-plugin-css-modules

有些第三方插件默认对 .module.css 开启 css-module 支持。如果我们支持了它,那么我们可以免参数配置使用第三方插件(比如我在全局的 typescript language service 配置一下,每个项目都共用一套配置,当然也会有本地的配置,只不过这方便了我们切换不同版本来查看效果嘛),这也是一个选择 .module.css 的一个理由吧。


import styles from './a.css';
import './a.css';

不是一个合理的做法,那么我们应该禁止掉这种做法,最好的方法应该就是用明显的特征把它区分开,比如文件名(参考 mjs 和 js)

至于 svg 的那个例子,我觉得那个场景不同,那个是为了支持多种用途同时使用,所以才引入的这种语法,而我们 css 是明显不希望同时使用 default import 和 named import 的

@sorrycc 这个功能大概什么时间上线

import '../common/less/barnd.less';

写法

@import "./default.less";
.banner {
    background: url(https://gw.alipayobjects.com/zos/rmsportal/okhVRKJXxQpbpKGtKneS.svg) no-repeat center top;
    background-size: contain;
    overflow: hidden;
    font-family: PingFang SC, Helvetica Neue For Number, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
    .page {
        max-width: 1248px;
    }
    .logo {
        background: url(https://gw.alipayobjects.com/zos/rmsportal/khXpcyRYlACLokoNTzwc.svg) no-repeat;
        width: 127px;
        height: 110px;
        margin: 86px auto 40px;
    }
    & &-anim {
        margin: 0 auto 64px;
        height: 600px;
        box-shadow: 0 20px 32px rgba(1, 4, 8, .12);
        background: #fff;
        border-radius: 8px;
        &-elem {
            .banner-bg {
                width: 100%;
                height: 100%;
                position: absolute;
                top: 0;
                left: 0;
                overflow: hidden;
                background-position: center;
                background-repeat: no-repeat;
            }
        }
    }
    .seeconf {
        &-wrap {
            text-align: center;
            color: @banner-text-color;
            .banner-button {
                margin: 64px 0 26px;
                .ant-btn {
                    height: 35px;
                    line-height: 35px;
                    border-radius: 35px;
                    background: #2354eb;
                    box-shadow: 0 7px 13px #91a5f2;
                    padding: 0 28px;
                    font-size: 12px;
                    a {
                        text-decoration: none;
                    }
                }
            }
        }
        &-en-name {
            margin: 140px 0 0;
            font-size: 12px;
            line-height: 32px;
        }
        &-title {
            margin: 16px 0 24px;
            font-size: 56px;
            line-height: 68px;
            text-indent: 2px;
            font-weight: 600;
            color: #02063D;
        }
        &-cn-name {
            font-size: 18px;
        }
    }
    &-button {
        .ant-btn {
            color: #fff;
            border: none;
        }
    }
}

编译后

/* stylelint-disable at-rule-empty-line-before,at-rule-name-space-after,at-rule-no-unknown */
/* stylelint-disable no-duplicate-selectors */
/* stylelint-disable */
/* stylelint-disable declaration-bang-space-before,no-duplicate-selectors,string-no-newline */
.barnd__banner___IkHrG {
  background: url(https://gw.alipayobjects.com/zos/rmsportal/okhVRKJXxQpbpKGtKneS.svg) no-repeat center top;
  background-size: contain;
  overflow: hidden;
  font-family: PingFang SC, Helvetica Neue For Number, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;
}
.barnd__banner___IkHrG .barnd__page___19R0U {
  max-width: 1248px;
}
.barnd__banner___IkHrG .barnd__logo___2J6Lp {
  background: url(https://gw.alipayobjects.com/zos/rmsportal/khXpcyRYlACLokoNTzwc.svg) no-repeat;
  width: 127px;
  height: 110px;
  margin: 86px auto 40px;
}
.barnd__banner___IkHrG .barnd__banner-anim___2XSRf {
  margin: 0 auto 64px;
  height: 600px;
  box-shadow: 0 20px 32px rgba(1, 4, 8, 0.12);
  background: #fff;
  border-radius: 8px;
}
.barnd__banner___IkHrG .barnd__banner-anim-elem___3AU3D .barnd__banner-bg___3d6h5 {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  background-position: center;
  background-repeat: no-repeat;
}
.barnd__banner___IkHrG .barnd__seeconf-wrap___1ZR80 {
  text-align: center;
  color: #5C6899;
}
.barnd__banner___IkHrG .barnd__seeconf-wrap___1ZR80 .barnd__banner-button___1EiwB {
  margin: 64px 0 26px;
}
.barnd__banner___IkHrG .barnd__seeconf-wrap___1ZR80 .barnd__banner-button___1EiwB .barnd__ant-btn___3dZj5 {
  height: 35px;
  line-height: 35px;
  border-radius: 35px;
  background: #2354eb;
  box-shadow: 0 7px 13px #91a5f2;
  padding: 0 28px;
  font-size: 12px;
}
.barnd__banner___IkHrG .barnd__seeconf-wrap___1ZR80 .barnd__banner-button___1EiwB .barnd__ant-btn___3dZj5 a {
  text-decoration: none;
}
.barnd__banner___IkHrG .barnd__seeconf-en-name___Yi2mc {
  margin: 140px 0 0;
  font-size: 12px;
  line-height: 32px;
}
.barnd__banner___IkHrG .barnd__seeconf-title___2BLq5 {
  margin: 16px 0 24px;
  font-size: 56px;
  line-height: 68px;
  text-indent: 2px;
  font-weight: 600;
  color: #02063D;
}
.barnd__banner___IkHrG .barnd__seeconf-cn-name___2QoLk {
  font-size: 18px;
}
.barnd__banner-button___1EiwB .barnd__ant-btn___3dZj5 {
  color: #fff;
  border: none;
}


/*# sourceMappingURL=p__index.chunk.css.map*/

还不是一样被便宜了。。。 你这也叫通用?

@rainbowMorelhahahah 这个还没上线吧

@rainbowMorelhahahah 这个还没上线吧

Issue on 6 Nov 2018 · 9 comments 我看时间 以为上线了

@sorrycc 有具体上线日期没?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

给 umi 项目添加以 styleName 为类名转化的方法(默认使用less文件)

  • 1 yarn add babel-plugin-react-css-modules postcss-less
  • 2 在~/config/config.js中添加
  ...
  extraBabelPlugins: [
    [
      'react-css-modules',
      {
        'exclude': 'node_modules',
        'generateScopedName': '[name]__[local]___[hash:base64:5]',
        'filetypes': {
          '.less': {
            'syntax': 'postcss-less',
          },
        },
      },
    ],
  ],
  ...
  • 3 在jsx文件中 import './style.less'

官方还是需要一个统一的方案的

给 umi 项目添加以 styleName 为类名转化的方法(默认使用less文件)

  • 1 yarn add babel-plugin-react-css-modules postcss-less
  • 2 在~/config/config.js中添加
  ...
  extraBabelPlugins: [
    [
      'react-css-modules',
      {
        'exclude': 'node_modules',
        'generateScopedName': '[name]__[local]___[hash:base64:5]',
        'filetypes': {
          '.less': {
            'syntax': 'postcss-less',
          },
        },
      },
    ],
  ],
  ...
  • 3 在jsx文件中 import './style.less'

老兄,sass怎么搞处理啊,我用了babel-plugin-react-css-modules postcss-scss,生成的类名还是对应不上。
另外sass的全局变量该怎么加入UMI呢

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

已在 umi@3 中实现。

给 umi 项目添加以 styleName 为类名转化的方法(默认使用less文件)

  • 1 yarn add babel-plugin-react-css-modules postcss-less
  • 2 在~/config/config.js中添加
  ...
  extraBabelPlugins: [
    [
      'react-css-modules',
      {
        'exclude': 'node_modules',
        'generateScopedName': '[name]__[local]___[hash:base64:5]',
        'filetypes': {
          '.less': {
            'syntax': 'postcss-less',
          },
        },
      },
    ],
  ],
  ...
  • 3 在jsx文件中 import './style.less'

哥们,问一下 我再项目中按照你这个配置,还需要配置其他吗 打包完以后styleName没有被处理,还是当成属性输出了

给 umi 项目添加以 styleName 为类名转化的方法(默认使用less文件)

  • 1 yarn add babel-plugin-react-css-modules postcss-less
  • 2 在~/config/config.js中添加
  ...
  extraBabelPlugins: [
    [
      'react-css-modules',
      {
        'exclude': 'node_modules',
        'generateScopedName': '[name]__[local]___[hash:base64:5]',
        'filetypes': {
          '.less': {
            'syntax': 'postcss-less',
          },
        },
      },
    ],
  ],
  ...
  • 3 在jsx文件中 import './style.less'

没有用,我的并没有生效哦

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tangzhengwen picture tangzhengwen  ·  4Comments

zhanchengkun picture zhanchengkun  ·  3Comments

Artoria-0x04 picture Artoria-0x04  ·  3Comments

kitebear picture kitebear  ·  3Comments

six-666 picture six-666  ·  3Comments