Skip to content

Commit

Permalink
Merge pull request #172 from hwaphon/feature/css-compress-optimize
Browse files Browse the repository at this point in the history
feat(plugin-compiler): 优化 CSS 压缩逻辑
  • Loading branch information
hwaphon authored Mar 25, 2024
2 parents d37e15e + 6abc138 commit 3cbacd3
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 5 deletions.
14 changes: 14 additions & 0 deletions packages/plugin-compiler/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,14 @@ export const CompilerCliConfig: ICliConfig = {
desc: '支持配置自定义函数, 返回 true 代表可以重命名, false 代表不可以重命名'
},

// 动态类名检测关闭逻辑,支持自定义函数 或 boolean,返回 true 表明即使模版中存在动态绑定 class,仍然对当前模板进行类名压缩
// 返回 false 表明走默认的存在动态绑定 class 不压缩的逻辑
// (filePath: string) => boolean
disableDynamicClassDetection: {
name: '关闭动态类名检测',
desc: '支持布尔值和支持配置自定义函数。如果设置为函数,返回 true 代表存在动态类名绑定时可以走类名压缩, 返回 false 表明走默认的存在动态绑定 class 不压缩的逻辑'
},

// 处理完成回调, 可获取 类名映射
// (classNameMappings: Map<string, string>) => void
success: {
Expand Down Expand Up @@ -818,6 +826,12 @@ const compressCssClassNameSchema = z
.args(z.string(), z.string())
.returns(z.boolean())
.optional(),
disableDynamicClassDetection: z
.function()
.args(z.string())
.returns(z.boolean())
.or(z.boolean())
.optional(),
success: z
.function()
.args(z.map(z.string(), z.string()))
Expand Down
72 changes: 67 additions & 5 deletions packages/plugin-compiler/src/experiments/cssClassnameCompress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
WebpackWrapper
} from '@morjs/utils'
import { customAlphabet } from 'nanoid'
import path from 'path'
import parser from 'postcss-selector-parser'
import { CompilerUserConfig, COMPILE_COMMAND_NAME } from '../constants'

Expand Down Expand Up @@ -91,7 +92,8 @@ export class CSSClassNameCompressPlugin implements Plugin {
include: [],
exclude: [],
except: [],
alphabet: ''
alphabet: '',
disableDynamicClassDetection: false
}

hasClassNameFilter: boolean
Expand Down Expand Up @@ -232,7 +234,9 @@ export class CSSClassNameCompressPlugin implements Plugin {
if (!node.attrs[attr]) continue
if ((node.attrs[attr] as unknown as boolean) === true) continue

const names = ((node.attrs[attr] || '') as string).trim().split(' ')
const names = this.splitBySpaceAndBraces(
((node.attrs[attr] || '') as string).trim()
)
const newNames: string[] = []

// 遍历并替换
Expand Down Expand Up @@ -301,6 +305,39 @@ export class CSSClassNameCompressPlugin implements Plugin {
})
}

/**
* 根据空格和大括号将输入字符串分割成数组。
* @param {string} input - 待分割的字符串。
* @returns {string[]} 分割后的字符串数组。
*/
splitBySpaceAndBraces(input) {
// 正则表达式,匹配 {{}} 或者空格
const regex = /{{.*?}}|\s+/g
let match
let lastIndex = 0
const result = []

// 循环匹配正则表达式
while ((match = regex.exec(input)) !== null) {
// 如果匹配到的不是空格,且不是字符串的开始位置,则将之前的字符串加入结果数组
if (match.index > lastIndex) {
result.push(input.slice(lastIndex, match.index))
}
// 如果匹配到的是 {{}},则将其加入结果数组
if (match[0].startsWith('{{')) {
result.push(match[0])
}
// 更新上次匹配的最后位置
lastIndex = match.index + match[0].length
}

// 如果最后一个匹配后还有剩余的字符串,将其加入结果数组
if (lastIndex < input.length) {
result.push(input.slice(lastIndex))
}

return result
}
/**
* 从已知的 axml 文件列表中查找可以处理的
*/
Expand All @@ -316,13 +353,25 @@ export class CSSClassNameCompressPlugin implements Plugin {
}
}

/**
* 去除文件路径的后缀
* @param {string} filePath - 要处理的文件路径
* @returns {string} 去除后缀的文件路径
*/
removeExtension(filePath) {
// 使用 path.parse() 解析文件路径
const parsedPath = path.parse(filePath)
// 返回去除后缀的路径,它由目录和文件名组成
return path.join(parsedPath.dir, parsedPath.name)
}

/**
* 检查文件是否有效
* @param {string} filePath 文件路径
*/
checkFileValid(filePath: string = ''): boolean {
if (!filePath) return false
return this.validFiles.has(filePath.split('.')[0])
return this.validFiles.has(this.removeExtension(filePath))
}

/**
Expand All @@ -333,7 +382,7 @@ export class CSSClassNameCompressPlugin implements Plugin {
tryAddFile(filePath: string, fileContent: string): void {
if (this.checkFileBeforeAdd(filePath, fileContent)) {
// 不保存文件后缀名,用于同时支持判断 多种文件类型
this.validFiles.add(filePath.split('.')[0])
this.validFiles.add(this.removeExtension(filePath))
}
}

Expand All @@ -354,8 +403,21 @@ export class CSSClassNameCompressPlugin implements Plugin {
// 如果 axml 为内容,则 acss 应该也不应该由内容,此处不处理
if (!fileContent) return false

const dynamicClassDetection = () =>
!this.dynamicClassRegExp.test(fileContent)
const { disableDynamicClassDetection } = this.options
// 是否配置跳过动态类名检测,如果配置了,判断值类型进行正确处理
if (disableDynamicClassDetection) {
if (typeof disableDynamicClassDetection === 'function') {
const result = disableDynamicClassDetection(filePath)
// 返回 false,代表仍然需要检测内容中是否存在动态类名情况
if (!result) return dynamicClassDetection()
}

return true
}
// 检查文件中是否包含动态的 class 拼接
return !this.dynamicClassRegExp.test(fileContent)
return dynamicClassDetection()
}

/**
Expand Down

0 comments on commit 3cbacd3

Please sign in to comment.