[Enhance] 更好的 css modules classname 压缩方案
Closed this issue · 4 comments
rax 在开发和生产用的 modules.localIdentName
配置都是 [folder]--[local]--[hash:base64:7]
,导致 rax 产物中的 css 文件的 classname 很长,比如 .QueryForm--input--2crH3Qq
css-loader
官方推荐的 modules.localIdentName
production 配置为 [hash:base64]
,在这个基础上,还有一种方案,压缩效果可能会更好
假设文件路径是 src/components/QueryForm/index.module.less
根据文件路径生成 hash:"filehash"
假设该文件内容为:
.foo { ... }
.bar { ... }
按照 classname 在文件中的顺序, foo 会转成 "a"
,bar 会转成 "b"
最终的 classname 为
.filehash-a { ... }
.filehash-b { ... }
实测效果:gzip 前后都可以减少 20%+ 的 css 文件体积
代码实现已经写好了,如果方案没什么问题的话,我可以提个 PR 过来,或者把这个加到 rax 文档里
ok,可以直接 PR
我最近试了下开启了 "experiments": {"minifyCSSModules": true},但实际在 ssr 场景下使用过程中遇到2个问题 @fengzilong
- 构建漏了 ssr 的场景,node 产物里的 css 类名文件没有被压缩
- css modules 嵌套写法导致的压缩结果可能比原来还差的情况下,举个例子:
css modules 的写法
.header {
// header css
.title {
title css
}
}
他最后生成的 css 文件为:
.header {
// header css
}
.header .title {
// title css
}
按照现有的压缩规则,没有对同一文件下的同一类名返回同一压缩结果,所以转化完之后是这样的:{ header: 'aaaaa bbbbb', title: 'ccccc' } ,所以嵌套结构越深,最后生成的压缩类名反而可能比原来的cssModules 命名要长,导致 ssr 下的主文档反而变大了
当然是不推荐 css modules 再用嵌套的写法的,但是每个人都有自己的习惯,难以在协同时规范,老项目也很难去做统一的这种治理。
目前项目中我这边本地先做了修复尝鲜了,希望后续可以有官方版本优化支持一下 ssr 的场景,或者我这边提 PR 也可
感谢试用,问题 get
- SSR 场景构建产物我理解不需要 CSS?因为在 web 产物里面已经有一份 CSS 了,node 端直接去 web 产物里面读取即可
- 嵌套这个确实没有考虑到,这个点应该可以优化的,每次构建时,遇到同一个文件&同一个 classname,从缓存里面读取,不重新生成,我看看怎么改
我调试下来,rax ssr 构建时和 web 构建是隔离的,每个 target 的构建流程都是单独的一个 config 流,因为现在这个压缩插件只在 web 构建流程中,少了 ssr 的构建,所以最后生成的产物没有被压缩
@fengzilong
我这边在插件的代码上是这么改的,如果开启了 ssr,就把 ssr 构建流程上也加上这个插件:
function minifyCSSModulesClassnamePlugin({ onGetWebpackConfig, context }) {
const { command, rootDir, userConfig = {} } = context;
const { targets = ['web'], web = {} } = userConfig;
...
(web.ssr ? [...targets, 'ssr'] : targets).forEach((target) => {
const minify = createMinify();
onGetWebpackConfig(target, (config) => {
configCSSModulesOptions(config, {
getLocalIdent,
});
});
...