Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] 提供 CSS 预处理器编译能力 #600

Open
wjq990112 opened this issue Mar 7, 2023 · 8 comments
Open

[RFC] 提供 CSS 预处理器编译能力 #600

wjq990112 opened this issue Mar 7, 2023 · 8 comments

Comments

@wjq990112
Copy link

wjq990112 commented Mar 7, 2023

背景

#514

配置项

在公共配置的中新增一项配置:

css

  • 类型:object
  • 默认值:undefined

css.preprocessorsOptions

  • 类型:Record<string, any>
  • 默认值:undefined

配置预处理器额外的配置项。

css.postcssOptions

umd.postcssOptions,兼容。

css.autoprefixer

umd.autoprefixer,兼容。

css.theme

umd.theme,兼容。

同时在 esm/cjs/umd 的子配置项下均可覆盖公共配置,但覆盖方式为了兼容 umd 目前已有的 postcssOptions 等选项,因此去掉 css 这一层级。

// .fatherrc.ts
import { defineConfig } from 'father';

export default defineConfig({
  css: {
    preprocessors: {
      less: {},
    },
    postcssOptions: {},
  },
});

同时,也支持在 esm/cjs 的子配置项中覆盖。

// .fatherrc.ts
import { defineConfig } from 'father';

export default defineConfig({
  esm: {
    preprocessors: {
      less: {},
    },
    postcssOptions: {},
  },
});

产物

Bundless 的产物目前不会对引入 CSS 预处理器的 import 语句做转换,因此还需要额外的 JS 编译流程将 import 语句转换成 CSS:

- import './App.less';
+ import './App.css';

同时 CSS 预处理器的代码也应该被编译成 CSS:

源码:

@class-prefix-button: ~'adm-button';

.@{class-prefix-button} {
  display: inline-block;
  &:focus {
    outline: none;
  }
}

产物:

.adm-button {
  display: inline-block;
}
.adm-button:focus {
  outline: none;
}

如何实现

初步了解发现可以通过在 builder/bundless/loaders 中实现 CSS 预处理器相关的 transformer 即可。

由于需要额外的 JS 编译流程将 import 语句转换成 CSS,因此可能需要修改 js-loader 中的部分代码,在配置项开启时使用 babel | esbuild | swc 插件将 import 语句进行转换。

@PeachScript
Copy link
Member

几点想法:

  1. 预处理器的包有额外尺寸,建议默认不集成任何预处理器,用户依赖里装了什么就处理什么(比如装了 less 才能编译 *.less
  2. preprocessor => style.preprocessors(或者不要复数?没想好),子项用于启用 + 传递预处理器配置项(比如 style.preprocessors.less 的类型可以是 { implemention: xxx, lessOptions: xxx },与 lessLoader 类似)
  3. umd.theme 可以作为基础公共配置了,自动组装给 2 的配置项
  4. 要不要支持类似 style.keepSource 的选项,继续平行输出原始样式表文件,这点没想好;纠结的点在于,输出是 antd v4 的实践,会被大量组件库借鉴,但 antd v5 又抛弃了该实践,支持又变得守旧,可能背后的问题是:构建工具是否应该从根源上推大家用 CSS-in-JS 的动态主题方案
  5. 怎么约束用户的用法,比如:不能引入三方包的 less/sass/stylus

@wjq990112
Copy link
Author

wjq990112 commented Mar 7, 2023

  1. 预处理器的包有额外尺寸,建议默认不集成任何预处理器,用户依赖里装了什么就处理什么(比如装了 less 才能编译 *.less)

可以借鉴 Vite 的解决方案,预处理器作为运行时依赖,当配置项开启但缺少预处理器依赖时,抛出异常

  1. preprocessor => style.preprocessors(或者不要复数?没想好),子项用于启用 + 传递预处理器配置项(比如 style.preprocessors.less 的类型可以是 { implemention: xxx, lessOptions: xxx },与 lessLoader 类似)

good idea,这点我觉得也可以参考 Shared Options | Vite

  1. umd.theme 可以作为基础公共配置了,自动组装给 2 的配置项

get

  1. 要不要支持类似 style.keepSource 的选项,继续平行输出原始样式表文件,这点没想好;纠结的点在于,输出是 antd v4 的实践,会被大量组件库借鉴,但 antd v5 又抛弃了该实践,支持又变得守旧,可能背后的问题是:构建工具是否应该从根源上推大家用 CSS-in-JS 的动态主题方案

社区中对 CSS-in-JS 的争论仍然非常多,我不认为 father 作为构建这一层的工具,应该输出观点给到上层,或者说,对于非标准中的内容,father 本身应该是没有观点的,应该是见仁见智的。我觉得 CSS-in-JS 即使已经是 mui/antd 所推崇的组件库样式解决方案,但这只是冰山一角,太多的组件库仍然在使用传统的样式解决方案,且 CSS 变量出现后传统的样式解决方案也没有明显的短板。如果 father 在这个问题上携带观点,从技术产品的纬度上来看,会失去这部分使用传统样式解决方案的组件库的市场,我认为是不值得的

  1. 怎么约束用户的用法,比如:不能引入三方包的 less/sass/stylus

这里的用户指的是 father 的用户,还是使用 father 构建的组件库的用户?
如果是前者,或许可以在 father doctor 中加一条规则;如果是后者,貌似没有什么解决方案,后者的行为确实是不可控的
除了不能引入三方包的 less/sass/stylus 的这个问题,另外需要约束用户可能还有两个问题:

  • 不能使用 CSS Modules
  • 不能在多个 less/sass/stylus 文件中引入同一份 less/sass/stylus 文件

不能使用 CSS Modules 的问题应该比较好解决,使用了 CSS Modules 的语法直接报错
不能重复引入的避免打包产物冗余的问题,我觉得应该也比较好解决,有了 CSS 变量之后,在 less/sass/stylus 中引入 vars 文件的操作已经基本上用不到了,全局公共的样式管理可以按照 antdm 的方式来做,理论上已经可以避免打包产物冗余的问题,father 可以给一份指南

@fz6m
Copy link
Member

fz6m commented Mar 7, 2023

预处理转换 less / scss 到 css 不难,但原文件中的 import 'style.less' 是很难转到 import 'style.css' 的,esbuild 是二进制的工具,不支持改 AST ,否则相当于用 AST 工具(如 babel 再读一遍),这就失去了打包快速的意义,此时选择 bundleless 不是好的选择。

一个逃生口是 swc 作为转译器是用 rust 写一个 swc 插件支持重写 .less -> .css (注意静态导入 import '' 和动态导入 import('') 两种场景),做好之后可以 at 我一下 🌹

@wjq990112
Copy link
Author

预处理转换 less / scss 到 css 不难,但原文件中的 import 'style.less' 是很难转到 import 'style.css' 的,esbuild 是二进制的工具,不支持改 AST ,否则相当于用 AST 工具(如 babel 再读一遍),这就失去了打包快速的意义,此时选择 bundleless 不是好的选择。

这点我觉得可以注明 SLA,明确告知用户会有构建速度上的损耗,没办法既要又要
同时默认使用的 transformer 是 babel,所以我理解这方面的影响还好

@wjq990112
Copy link
Author

@PeachScript @fz6m
RFC updated.

@fz6m
Copy link
Member

fz6m commented Mar 11, 2023

尽量用 rust ,以后都是 rust 的发展趋势,用 js 写的生命周期过一年两年就被迭代掉了还要改。

@wjq990112
Copy link
Author

wjq990112 commented Mar 11, 2023

尽量用 rust ,以后都是 rust 的发展趋势,用 js 写的生命周期过一年两年就被迭代掉了还要改。

Maybe it is too difficult for me.

@wjq990112
Copy link
Author

尽量用 rust ,以后都是 rust 的发展趋势,用 js 写的生命周期过一年两年就被迭代掉了还要改。

先渐进式实现吧,把 babel 的实现了再看看实现 swc/esbuild 的能力,我看到 #535 有自定义 esbuild 插件的需求,或许需要跟这个能力一起实现。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants