Skip to content

Commit 11ae5ce

Browse files
authored
Merge pull request #62 from sonofmagic/feature/add-vue-compiler
Feature/add vue compiler
2 parents 738bd9e + 3c2d2b9 commit 11ae5ce

File tree

33 files changed

+1049
-990
lines changed

33 files changed

+1049
-990
lines changed

.changeset/purple-hotels-itch.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"unplugin-tailwindcss-mangle": minor
3+
"@tailwindcss-mangle/core": minor
4+
"tailwindcss-patch": patch
5+
---
6+
7+
fix(tailwindcss-patch): monorepo basedir option

.vscode/launch.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
{
2-
// 使用 IntelliSense 了解相关属性。
2+
// 使用 IntelliSense 了解相关属性。
33
// 悬停以查看现有属性的描述。
44
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7+
{
8+
"command": "pnpm tw-extract",
9+
"name": "[vite-vue] tw-extract",
10+
"request": "launch",
11+
"type": "node-terminal",
12+
"cwd": "${workspaceFolder}/apps/vite-vue"
13+
},
714
{
815
"command": "pnpm start",
916
"name": "[scripts] postcss7-compat run",
@@ -117,4 +124,4 @@
117124
"cwd": "${workspaceFolder}/packages/core"
118125
}
119126
]
120-
}
127+
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"preinstall": "npx only-allow pnpm",
2222
"sync": "cnpm sync @tailwindcss-mangle/shared @tailwindcss-mangle/config tailwindcss-patch unplugin-tailwindcss-mangle @tailwindcss-mangle/core",
2323
"publish-packages": "pnpm run test && changeset version && changeset publish",
24-
"release": "bumpp -r --no-push --no-commit"
24+
"release": "changeset"
2525
},
2626
"devDependencies": {
2727
"@changesets/changelog-github": "^0.5.0",
@@ -31,7 +31,7 @@
3131
"@tailwindcss-mangle/shared": "workspace:*",
3232
"@tsconfig/recommended": "^1.0.6",
3333
"@types/lodash-es": "^4.17.12",
34-
"@types/node": "^20.14.2",
34+
"@types/node": "^20.14.5",
3535
"@vitest/coverage-v8": "^1.6.0",
3636
"bumpp": "^9.4.1",
3737
"cross-env": "^7.0.3",

packages/config/package.json

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,32 @@
22
"name": "@tailwindcss-mangle/config",
33
"version": "2.2.2",
44
"description": "The config and load function of tailwindcss-mangle",
5+
"author": "SonOfMagic <[email protected]>",
6+
"license": "MIT",
7+
"homepage": "https://github.com/sonofmagic/tailwindcss-mangle",
8+
"repository": {
9+
"type": "git",
10+
"url": "git+https://github.com/sonofmagic/tailwindcss-mangle.git"
11+
},
12+
"keywords": [
13+
"tailwindcss",
14+
"mangle",
15+
"patch",
16+
"core",
17+
"mangle",
18+
"shared",
19+
"utils"
20+
],
521
"exports": {
622
".": {
723
"types": "./dist/index.d.ts",
824
"import": "./dist/index.mjs",
925
"require": "./dist/index.cjs"
1026
}
1127
},
28+
"main": "./dist/index.cjs",
29+
"module": "./dist/index.mjs",
30+
"types": "./dist/index.d.ts",
1231
"typesVersions": {
1332
"*": {
1433
"*": [
@@ -17,9 +36,6 @@
1736
]
1837
}
1938
},
20-
"main": "./dist/index.cjs",
21-
"module": "./dist/index.mjs",
22-
"types": "./dist/index.d.ts",
2339
"files": [
2440
"dist"
2541
],
@@ -29,17 +45,6 @@
2945
"test": "vitest run --coverage.enabled",
3046
"test:dev": "vitest"
3147
},
32-
"keywords": [
33-
"tailwindcss",
34-
"mangle",
35-
"patch",
36-
"core",
37-
"mangle",
38-
"shared",
39-
"utils"
40-
],
41-
"author": "SonOfMagic <[email protected]>",
42-
"license": "MIT",
4348
"publishConfig": {
4449
"access": "public",
4550
"registry": "https://registry.npmjs.org/"
@@ -48,10 +53,5 @@
4853
"@tailwindcss-mangle/shared": "workspace:^",
4954
"c12": "^1.11.1",
5055
"dedent": "^1.5.3"
51-
},
52-
"homepage": "https://github.com/sonofmagic/tailwindcss-mangle",
53-
"repository": {
54-
"type": "git",
55-
"url": "git+https://github.com/sonofmagic/tailwindcss-mangle.git"
5656
}
5757
}

packages/core/package.json

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,32 @@
22
"name": "@tailwindcss-mangle/core",
33
"version": "2.2.2",
44
"description": "The core of tailwindcss-mangle",
5+
"author": "SonOfMagic <[email protected]>",
6+
"license": "MIT",
7+
"homepage": "https://github.com/sonofmagic/tailwindcss-mangle",
8+
"repository": {
9+
"type": "git",
10+
"url": "git+https://github.com/sonofmagic/tailwindcss-mangle.git"
11+
},
12+
"bugs": {
13+
"url": "https://github.com/sonofmagic/tailwindcss-mangle/issues"
14+
},
15+
"keywords": [
16+
"tailwindcss",
17+
"patch",
18+
"core",
19+
"mangle"
20+
],
521
"exports": {
622
".": {
723
"types": "./dist/index.d.ts",
824
"import": "./dist/index.mjs",
925
"require": "./dist/index.cjs"
1026
}
1127
},
28+
"main": "./dist/index.cjs",
29+
"module": "./dist/index.mjs",
30+
"types": "./dist/index.d.ts",
1231
"typesVersions": {
1332
"*": {
1433
"*": [
@@ -17,9 +36,6 @@
1736
]
1837
}
1938
},
20-
"main": "./dist/index.cjs",
21-
"module": "./dist/index.mjs",
22-
"types": "./dist/index.d.ts",
2339
"files": [
2440
"dist"
2541
],
@@ -30,51 +46,32 @@
3046
"test:dev": "vitest",
3147
"coverage": "vitest run --coverage"
3248
},
33-
"keywords": [
34-
"tailwindcss",
35-
"patch",
36-
"core",
37-
"mangle"
38-
],
39-
"author": "SonOfMagic <[email protected]>",
40-
"license": "MIT",
4149
"publishConfig": {
4250
"access": "public",
4351
"registry": "https://registry.npmjs.org/"
4452
},
4553
"dependencies": {
4654
"@ast-core/escape": "^1.0.1",
47-
"@babel/core": "^7.24.7",
48-
"@babel/helper-plugin-utils": "^7.24.7",
4955
"@babel/parser": "^7.24.7",
50-
"@babel/preset-typescript": "^7.24.7",
56+
"@babel/traverse": "^7.24.7",
5157
"@babel/types": "^7.24.7",
5258
"@tailwindcss-mangle/config": "workspace:^",
5359
"@tailwindcss-mangle/shared": "workspace:^",
5460
"@vue/compiler-sfc": "^3.4.29",
5561
"fast-sort": "^3.4.0",
62+
"htmlparser2": "9.1.0",
5663
"magic-string": "^0.30.10",
5764
"micromatch": "^4.0.7",
58-
"parse5": "^7.1.2",
5965
"postcss": "^8.4.38",
6066
"postcss-selector-parser": "^6.1.0"
6167
},
6268
"devDependencies": {
63-
"@parse5/tools": "^0.5.0",
64-
"@types/babel__core": "^7.20.5",
69+
"@types/babel__traverse": "^7.20.6",
6570
"@types/micromatch": "^4.0.7",
6671
"@vue/compiler-core": "^3.4.29",
6772
"@vue/compiler-sfc": "^3.4.27"
6873
},
69-
"homepage": "https://github.com/sonofmagic/tailwindcss-mangle",
70-
"repository": {
71-
"type": "git",
72-
"url": "git+https://github.com/sonofmagic/tailwindcss-mangle.git"
73-
},
74-
"bugs": {
75-
"url": "https://github.com/sonofmagic/tailwindcss-mangle/issues"
76-
},
7774
"directories": {
7875
"test": "test"
7976
}
80-
}
77+
}

packages/core/src/babel/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import _babelTraverse from '@babel/traverse'
2+
3+
export { parse, parseExpression } from '@babel/parser'
4+
5+
function _interopDefaultCompat(e: any) {
6+
return e && typeof e === 'object' && 'default' in e ? e.default : e
7+
}
8+
9+
export const traverse = _interopDefaultCompat(_babelTraverse) as typeof _babelTraverse

packages/core/src/css/plugins.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ export type PostcssMangleTailwindcssPlugin = PluginCreator<ICssHandlerOptions>
77

88
const postcssPlugin = 'postcss-mangle-tailwindcss-plugin'
99

10-
const clonedKey = '__tw_mangle_cloned__'
11-
1210
export function isVueScoped(s: parser.ClassName): boolean {
1311
if (s.parent) {
1412
const index = s.parent.nodes.indexOf(s)
@@ -23,39 +21,37 @@ export function isVueScoped(s: parser.ClassName): boolean {
2321
}
2422

2523
export const transformSelectorPostcssPlugin: PluginCreator<ICssHandlerOptions> = function (options) {
26-
const { ignoreVueScoped, replaceMap, ctx } = defu(options, {
24+
const { ignoreVueScoped, ctx } = defu(options, {
2725
ignoreVueScoped: true,
2826
})
27+
const replaceMap = ctx.replaceMap
2928

3029
return {
3130
postcssPlugin,
32-
async Rule(rule) {
33-
// @ts-ignore
34-
if (rule[clonedKey]) {
35-
return
36-
}
37-
await parser((selectors) => {
38-
selectors.walkClasses((s) => {
39-
if (s.value && replaceMap && replaceMap.has(s.value)) {
40-
if (ignoreVueScoped && isVueScoped(s)) {
41-
return
42-
}
43-
const v = replaceMap.get(s.value)
44-
if (v) {
45-
if (ctx.isPreserveClass(s.value)) {
46-
const r = rule.cloneBefore()
47-
// @ts-ignore
48-
r[clonedKey] = true
31+
Once(root) {
32+
root.walkRules((rule) => {
33+
parser((selectors) => {
34+
selectors.walkClasses((s) => {
35+
if (s.value && replaceMap && replaceMap.has(s.value)) {
36+
if (ignoreVueScoped && isVueScoped(s)) {
37+
return
38+
}
39+
const v = replaceMap.get(s.value)
40+
if (v) {
41+
if (ctx.isPreserveClass(s.value)) {
42+
rule.cloneBefore()
43+
}
44+
s.value = v
4945
}
50-
s.value = v
5146
}
52-
}
47+
})
48+
}).transformSync(rule, {
49+
lossless: false,
50+
updateSelector: true,
5351
})
54-
}).transform(rule, {
55-
lossless: false,
56-
updateSelector: true,
5752
})
5853
},
54+
5955
}
6056
}
6157
transformSelectorPostcssPlugin.postcss = true

packages/core/src/ctx/index.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from 'node:fs'
22
import { isAbsolute, resolve } from 'node:path'
3+
import process from 'node:process'
34
import { ClassGenerator } from '@tailwindcss-mangle/shared'
45
import { getConfig } from '@tailwindcss-mangle/config'
56
import type { MangleUserConfig } from '@tailwindcss-mangle/config'
@@ -17,7 +18,7 @@ export class Context {
1718
options: MangleUserConfig
1819
private includeMatcher: (file: string) => boolean
1920
private excludeMatcher: (file: string) => boolean
20-
private replaceMap: Map<string, string>
21+
public replaceMap: Map<string, string>
2122
classSet: Set<string>
2223

2324
classGenerator: ClassGenerator
@@ -46,9 +47,6 @@ export class Context {
4647
}
4748

4849
isPreserveFunction(calleeName: string) {
49-
// if (callee === undefined) {
50-
// return false
51-
// }
5250
return this.preserveFunctionSet.has(calleeName)
5351
}
5452

@@ -77,12 +75,6 @@ export class Context {
7775
}
7876

7977
getReplaceMap() {
80-
// const map = new Map<string, string>()
81-
// for (const [key, value] of sort([...this.replaceMap.entries()]).desc((x) => x[0].length)) {
82-
// if (!this.isPreserveClass(key)) {
83-
// map.set(key, value)
84-
// }
85-
// }
8678
return this.replaceMap // map
8779
}
8880

packages/core/src/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
import process from 'node:process'
2+
13
export const isProd = () => process.env.NODE_ENV === 'production'
24
export const isDev = () => process.env.NODE_ENV === 'development'

packages/core/src/html/index.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,38 @@
1-
import { parse, serialize } from 'parse5'
2-
import { traverse } from '@parse5/tools'
1+
import { Parser } from 'htmlparser2'
2+
import MagicString from 'magic-string'
33
import type { IHtmlHandlerOptions } from '../types'
44
import { makeRegex, splitCode } from '../shared'
5-
// const { traverse } = await import('@parse5/tools')
6-
export function htmlHandler(rawSource: string, options: IHtmlHandlerOptions) {
7-
const { replaceMap, ctx } = options
8-
const fragment = parse(rawSource)
9-
traverse(fragment, {
10-
element(node) {
11-
const attribute = node.attrs.find(x => x.name === 'class')
12-
if (attribute) {
13-
const array = splitCode(attribute.value, {
5+
import { jsHandler } from '@/js'
6+
7+
export function htmlHandler(raw: string | MagicString, options: IHtmlHandlerOptions) {
8+
const { ctx, isVue } = options
9+
const { replaceMap } = ctx
10+
const ms: MagicString = typeof raw === 'string' ? new MagicString(raw) : raw
11+
const parser = new Parser({
12+
onattribute(name, value) {
13+
if (name === 'class') {
14+
const arr = splitCode(value, {
1415
splitQuote: false,
1516
})
16-
for (const v of array) {
17+
let rawValue = value
18+
for (const v of arr) {
1719
if (replaceMap.has(v)) {
18-
attribute.value = attribute.value.replace(makeRegex(v), ctx.classGenerator.generateClassName(v).name)
20+
rawValue = rawValue.replace(makeRegex(v), ctx.classGenerator.generateClassName(v).name)
1921
}
2022
}
23+
ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, rawValue)
24+
}
25+
if (isVue) {
26+
if (name === ':class') {
27+
const { code } = jsHandler(value, {
28+
ctx,
29+
})
30+
ms.update(parser.startIndex + name.length + 2, parser.endIndex - 1, code)
31+
}
2132
}
2233
},
2334
})
24-
return serialize(fragment)
35+
parser.write(ms.original)
36+
parser.end()
37+
return ms.toString()
2538
}

0 commit comments

Comments
 (0)