father icon indicating copy to clipboard operation
father copied to clipboard

是否有必要添加对样式的处理?比如Windi CSS?

Open yee94 opened this issue 2 years ago • 16 comments

想问下,在组件类型的包编译过程中,对于样式的处理,最佳实践应该是什么样的?

目前在Bundless模式下,对于样式文件的处理方式就是直接复制到对应目录,目前一切运转正常。

但其实还是有部分小的问题,比如scss、less等预处理的 @import 中的别名路径,以及社区中出现的 Windi CSSUno CSS 这类原子化样式能力,均需要编译后生成。

当然也是可以在额外再运行命令处理。

但是面对这类的问题,想请教下作者的看法是什么样的?是否有必要整合进来?或者插件的方式来处理?

yee94 avatar Sep 13 '22 13:09 yee94

+1,遇到一样的问题

heiyexing avatar Sep 14 '22 02:09 heiyexing

对于 Less 之类传统预处理器,我理解把样式文件交给实际项目去编译更合适,主要原因:

  1. Bundless 不打包、没法处理样式文件的依赖,比如 a.lessb.less@import 'pkg/es/style/index.less',那产出的 a.cssb.css 如果包含依赖就有产物冗余、甚至样式冲突,如果不包含依赖就会样式丢失
  2. 产出原始 Less 文件使用的项目更容易定制变量,代价是项目编译会稍增成本

对于 Windi CSS 之类的原子化 CSS,我没有调研过,但它似乎更适用于 Bundle 模式而不是 Bundless

PeachScript avatar Sep 14 '22 02:09 PeachScript

蹲个解法

旧版本配置

export default {
  esm: {
    type: 'babel',
  },
  cjs: {
    type: 'babel',
  },
  lessInBabelMode: {
    modifyVars: {
      '@ant-prefix': 'xxxxx',
    },
    javascriptEnabled: true,
  },
};

目的是为了让组件和项目中的做样式隔离。因为组件基于 antd 做的二次封装(很大的组件,直接就是一个页面),项目中也用了 antd。 期望项目中的配置不影响组件。(没错,一个项目中是两套设计。但是封装的组件是给多个不同的项目接入使用的)

import { Button } from 'like-antd'; 
import "like-antd/dist/styles/button.css"

xiaohuoni avatar Oct 25 '22 03:10 xiaohuoni

按照平常的开发没有任何配置, 在dumi2.0中,加入了tailwind发现打包后并没有生效:

@tailwind base;
@tailwind components;
@tailwind utilities;
...

postcss.config.js

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  }
}

在打包后dist文件中只有在less中保留了@tailwind base;上面那三行;

.fatherrc.ts

import { defineConfig } from 'father';

export default defineConfig({
  // more father config: https://github.com/umijs/father/blob/master/docs/config.md
  esm: {
    transformer: "babel",
    output: "dist",
  },
  umd: {
    extractCSS: true,
    output: "dist",
    postcssOptions: {
      autoCSSModules: true
    },
  },
});

ClearLuvMoki avatar Dec 01 '22 12:12 ClearLuvMoki

@ClearLuvMoki

  1. father 4 的 esm 是 bundless 模式,不会处理非 js 文件
  2. father 4 的 umd 是 bundle 模式,会处理样式文件,但 PostCSS 配置需要配在单独的配置项里:https://github.com/umijs/father/blob/master/docs/config.md#postcssoptions
  3. 组件库是否应该使用 tailwind 我觉得是个需要考虑的问题,可能应用研发才是适合它的场景

PeachScript avatar Dec 01 '22 12:12 PeachScript

感谢!

ClearLuvMoki avatar Dec 01 '22 12:12 ClearLuvMoki

对于 Less 之类传统预处理器,我理解把样式文件交给实际项目去编译更合适,主要原因:

  1. Bundless 不打包、没法处理样式文件的依赖,比如 a.lessb.less@import 'pkg/es/style/index.less',那产出的 a.cssb.css 如果包含依赖就有产物冗余、甚至样式冲突,如果不包含依赖就会样式丢失
  2. 产出原始 Less 文件使用的项目更容易定制变量,代价是项目编译会稍增成本

对于 Windi CSS 之类的原子化 CSS,我没有调研过,但它似乎更适用于 Bundle 模式而不是 Bundless

偏个题,ant-design-mobile 不是你所说的将样式文件交个实际项目去编译的方案,请教一下是如何解决产物冗余问题的?(以及 Ant Design v4 中某个具体组件的 CSS,我理解这种形式也会出现产物冗余)

因为我理解产出 Less/Sass 源文件让实际项目去引入的方式主要是为了服务上古时期的主题定制功能的,通过 less/sass-loader 替换变量来实现。现在完全可以使用 CSS 变量来代替,也就不再需要 Less/Sass 源文件让实际的项目去引入了(是否还有其他场景需要实际的项目引入 Less/Sass 源文件?)。

从用户视角来看,组件库应该为用户屏蔽尽可能多的额外操作。比如逻辑和样式分离,用户需要单独引入 Less/Sass 源文件的行为是我认为不太合理的,因为用户的实际项目中完全可能使用不同的样式预处理方案,甚至可能不使用样式预处理方案。比如组件库使用的是 Less,而实际项目本身使用的是 Sass,如果需要单独引入 Less/Sass 源文件,用户不仅需要在实际项目中额外添加一套样式预处理器配置,还可能因此影响用户在样式预处理器上的技术选型(如用户希望在 Less 文件中引入组件库提供的 Sass 源文件等情况)。

而 ant-design-mobile 的处理方式,用户只需要在实际项目中引入组件,不需要额外引入组件样式,因为组件本身在编译的过程中将 Less 编译成了 CSS,且通过 babel 插件将 .less 的 import 语句转换成了 .css。是否存在样式冗余没有实际验证,但从源码来看,似乎是通过规范避免了在不同组件的样式文件中引入同一份公共依赖的样式,而是将公共依赖的样式提至最顶层引入(ant-design/ant-design-mobile/blob/master/src/index.ts)。

回到 father 这个技术产品本身上,根据 README 中的描述,定位是 NPM 包研发工具,组件库也是 NPM 包的形式之一。我认为在组件库的开发过程中,样式处理是必不可少的内容,几乎无法绕过。同时我也观察到 bundless 的模式采用的是一个自研的 loader 机制(可能描述不准确,未深入了解),是否可以基于这个 loader 的机制提供配置,同时注明 SLA 供用户参考并选择。

以上为我个人愚见,若有不正确的内容,还请多指教。

wjq990112 avatar Feb 04 '23 18:02 wjq990112

2. PostCSS 配置

PostCSS 配置有示例吗,能提供一份来学习吗,谢谢

kentLin0 avatar Feb 22 '23 08:02 kentLin0

回到 father 这个技术产品本身上,根据 README 中的描述,定位是 NPM 包研发工具,组件库也是 NPM 包的形式之一。我认为在组件库的开发过程中,样式处理是必不可少的内容,几乎无法绕过。同时我也观察到 bundless 的模式采用的是一个自研的 loader 机制(可能描述不准确,未深入了解),是否可以基于这个 loader 的机制提供配置,同时注明 SLA 供用户参考并选择。

@wjq990112 你说的挺对的,很详细的讨论👍

father 是应该对不用 CSS Modules、没有重复引用、遵循 antd-mobile 或 antd 类似目录结构项目中的 Less/SASS 编译成 CSS;但先决条件太多很容易误用、产生不必要的问题,且考虑 CSS-in-JS 方案已经替代 Less 之类的方案成为组件库的首选,考虑到投入产出比,目前不会投入精力支持。

如果你有兴趣和精力的话,欢迎给 father 提交 PR 支持,如你所说 father 的 bundless 是 loader 机制(复用了 webpack 的 loader-runner)且可以注册,作此设计是因为最初的确打算支持上述场景,不过后来搁置了。

PeachScript avatar Feb 22 '23 09:02 PeachScript

我了解的 css in js 方案生成的类名不可控,在组件库里用的话,请问是有什么特殊配置可以固定类名吗?

haydenull avatar Feb 22 '23 09:02 haydenull

我了解的 css in js 方案生成的类名不可控,在组件库里用的话,请问是有什么特殊配置可以固定类名吗?

可以参考 antd v5 的做法,用固定 className + 动态 className 组合的形式;后续 father 会出 CSS-in-JS 相关的指南文档,目前还在调研中

PeachScript avatar Feb 22 '23 10:02 PeachScript

如果你有兴趣和精力的话,欢迎给 father 提交 PR 支持,如你所说 father 的 bundless 是 loader 机制(复用了 webpack 的 loader-runner)且可以注册,作此设计是因为最初的确打算支持上述场景,不过后来搁置了。

未来可能是 father 的深度用户之一,我非常有兴趣且有精力为 father 提供力所能及的能力支持。

wjq990112 avatar Feb 24 '23 03:02 wjq990112

father-plugin-less 暂时先自己写了一个plugin来处理less的编译。 沿用了2x的 lessInBabel的配置项.

innocces avatar May 16 '23 14:05 innocces

我的情况是这样的: 我的组件库是为公司的几个项目服务的,这些项目都使用 tailwind,father 在执行 bundless 打包时不会处理 tailwind 相关样式

我选择将 xx-ui 的 tailwind.config.js 作为包内容一起发布

然后在宿主项目的 tailwind.config.js 里这样配置

// 使用 ui 库里面 config 作为预设
presets: [require('@align-ui/tailwind.config')],
// 宿主项目执行 tailwind 扫描增加对 node_modules ui 库的扫描
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}', 'node_modules/@align-ui/**/*.{js,ts,jsx,tsx}'],

这样的话就不用考虑 ui 库的 tailwind 打包了


另外对于 ui 库中的其他样式,诸如 less、scss,我是将其单独打包成一个 umd 模式,这样就能实现 样式 bundle,在使用时直接在项目入口文件这样全局引入

import 'ui/index.min.css'

.fatherrc

import { defineConfig } from 'father';

export default defineConfig({
  // more father config: https://github.com/umijs/father/blob/master/docs/config.md
  esm: { output: 'dist' },
  umd: {
    entry: {
      // 单独创建一个 ui.ts 作为 css 打包的入口文件
      'src/ui': {},
    },
    output: 'dist',
  },
});

LeiYao123 avatar Apr 26 '24 07:04 LeiYao123

因为依赖了 antd3 版本的 less、打包成 umd 的产物时,lessLoader 需要 math: 'always' 配置项,请问在 father 里怎么设置? 在 dumi 里可以这么设置 https://d.umijs.org/config#lessloader 没问题。

warmhug avatar Jul 11 '24 08:07 warmhug

因为依赖了 antd3 版本的 less、打包成 umd 的产物时,lessLoader 需要 math: 'always' 配置项,请问在 father 里怎么设置? 在 dumi 里可以这么设置 https://d.umijs.org/config#lessloader 没问题。

自问自答吧~

umd: {
    name: 'xxx',
    chainWebpack(config) {
      // console.log('config: ', config.toString());
      // console.log('config: ', config.module.rule('less'));
      config.module
      .rule('less')
      .oneOf('css')
      .use('less-loader')
        .tap(options => {
          // console.log('options: ', options);
          options.lessOptions.math = 'always';
          return options;
        });
      return config;
    },
  }

warmhug avatar Jul 11 '24 12:07 warmhug