Skip to content

Commit 3db8b13

Browse files
committed
refactor: TailwindcssPatcher
1 parent 075f145 commit 3db8b13

16 files changed

+214
-167
lines changed

packages/tailwindcss-patch/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"cac": "^6.7.14",
5757
"jiti": "^1.21.0",
5858
"lilconfig": "^3.1.1",
59+
"local-pkg": "^0.5.0",
5960
"postcss": "^8.4.38",
6061
"resolve": "^1.22.8",
6162
"semver": "^7.6.2"

packages/tailwindcss-patch/src/core/exposeContext.ts

-49
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export * from './tw-patcher'
2-
export * from './exposeContext'
32
export * from './inspector'
43
export * from './runtime-patcher'
54
export * from './cache'

packages/tailwindcss-patch/src/core/inspector-postcss7-compat.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ export function inspectPostcssPlugin(content: string) {
9696
if (t.isFunctionExpression(targetFn)) {
9797
// 函数体
9898
const targetBlockStatement = targetFn.body
99-
99+
if (t.isExpressionStatement(targetBlockStatement.body[0]) && t.isAssignmentExpression(targetBlockStatement.body[0].expression) && t.isNumericLiteral(targetBlockStatement.body[0].expression.right)) {
100+
hasPatched = true
101+
return
102+
}
100103
const lastStatement = targetBlockStatement.body[targetBlockStatement.body.length - 1]
101104
if (t.isExpressionStatement(lastStatement)) {
102105
// contextRef.value.push((0, _processTailwindFeatures.default)(context)(root, result));

packages/tailwindcss-patch/src/core/runtime-patcher.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { gte } from 'semver'
55
import type { PackageJson } from 'pkg-types'
66
import { defu } from 'defu'
77
import { inspectPostcssPlugin, inspectProcessTailwindFeaturesReturnContext } from './inspector'
8+
import { inspectPostcssPlugin as inspectPostcssPluginCompat, inspectProcessTailwindFeaturesReturnContext as inspectProcessTailwindFeaturesReturnContextCompat } from './inspector-postcss7-compat'
89
import type { InternalPatchOptions, PatchOptions } from '@/types'
910
import { getDefaultPatchOptions } from '@/defaults'
1011
import { ensureFileContent, requireResolve } from '@/utils'
@@ -14,6 +15,7 @@ export function getInstalledPkgJsonPath(options: PatchOptions = {}) {
1415
// const cwd = process.cwd()
1516
const tmpJsonPath = requireResolve(`tailwindcss/package.json`, {
1617
paths: options.paths,
18+
basedir: options.basedir,
1719
})
1820

1921
return tmpJsonPath
@@ -89,7 +91,7 @@ export function monkeyPatchForExposingContextV2(twDir: string, opt: InternalPatc
8991
const processTailwindFeaturesContent = ensureFileContent(processTailwindFeaturesFilePath)
9092
const result: { processTailwindFeatures?: string, plugin?: string } & Record<string, any> = {}
9193
if (processTailwindFeaturesContent) {
92-
const { code, hasPatched } = inspectProcessTailwindFeaturesReturnContext(processTailwindFeaturesContent)
94+
const { code, hasPatched } = inspectProcessTailwindFeaturesReturnContextCompat(processTailwindFeaturesContent)
9395
if (!hasPatched && opt.overwrite) {
9496
fs.writeFileSync(processTailwindFeaturesFilePath, code, {
9597
encoding: 'utf8',
@@ -102,7 +104,7 @@ export function monkeyPatchForExposingContextV2(twDir: string, opt: InternalPatc
102104
const indexFilePath = path.resolve(twDir, 'lib/jit/index.js')
103105
const pluginContent = ensureFileContent([indexFilePath])
104106
if (pluginContent) {
105-
const { code, hasPatched } = inspectPostcssPlugin(pluginContent)
107+
const { code, hasPatched } = inspectPostcssPluginCompat(pluginContent)
106108
if (!hasPatched && opt.overwrite) {
107109
fs.writeFileSync(indexFilePath, code, {
108110
encoding: 'utf8',

packages/tailwindcss-patch/src/core/tw-patcher.ts

+62-20
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
1-
import fs from 'node:fs/promises'
2-
import { dirname } from 'node:path'
3-
import { getClassCacheSet, getContexts, getTailwindcssEntry } from './exposeContext'
1+
import path from 'node:path'
2+
import fs from 'node:fs'
43
import { CacheManager, getCacheOptions } from './cache'
54
import { createPatch, getPatchOptions } from './runtime-patcher'
65
import { processTailwindcss } from './postcss'
76
import type { UserConfig } from '@/config'
8-
import { ensureDir } from '@/utils'
9-
import type { CacheStrategy, InternalCacheOptions, InternalPatchOptions, TailwindcssPatcherOptions } from '@/types'
7+
import { ensureDir, getPackageInfoSync, isObject } from '@/utils'
8+
import type { CacheStrategy, InternalCacheOptions, InternalPatchOptions, PackageInfo, TailwindcssClassCache, TailwindcssPatcherOptions, TailwindcssRuntimeContext } from '@/types'
109

1110
export class TailwindcssPatcher {
1211
public rawOptions: TailwindcssPatcherOptions
1312
public cacheOptions: InternalCacheOptions
1413
public patchOptions: InternalPatchOptions
1514
public patch: () => void
1615
public cacheManager: CacheManager
16+
public packageInfo?: PackageInfo
17+
public majorVersion?: number
18+
1719
constructor(options: TailwindcssPatcherOptions = {}) {
1820
this.rawOptions = options
1921
this.cacheOptions = getCacheOptions(options.cache)
2022
this.patchOptions = getPatchOptions(options.patch)
2123
this.patch = createPatch(this.patchOptions)
2224
this.cacheManager = new CacheManager(this.cacheOptions)
23-
}
24-
25-
getPkgEntry(basedir?: string) {
26-
return getTailwindcssEntry(basedir)
25+
this.packageInfo = getPackageInfoSync('tailwindcss', { basedir: this.patchOptions.basedir })
26+
if (this.packageInfo && this.packageInfo.version) {
27+
this.majorVersion = Number.parseInt(this.packageInfo.version[0])
28+
}
2729
}
2830

2931
setCache(set: Set<string>) {
@@ -33,17 +35,61 @@ export class TailwindcssPatcher {
3335
}
3436

3537
getCache() {
36-
// if(this.cache.enable){
3738
return this.cacheManager.read()
38-
// }
39+
}
40+
41+
getContexts(): TailwindcssRuntimeContext[] {
42+
if (this.packageInfo) {
43+
const distPath = path.join(this.packageInfo.rootPath, 'lib')
44+
let injectFilePath: string | undefined
45+
if (this.majorVersion === 2) {
46+
injectFilePath = path.join(distPath, 'jit/index.js')
47+
}
48+
else {
49+
injectFilePath = path.join(distPath, 'plugin.js')
50+
if (!fs.existsSync(injectFilePath)) {
51+
injectFilePath = path.join(distPath, 'index.js')
52+
}
53+
}
54+
if (injectFilePath) {
55+
// eslint-disable-next-line ts/no-require-imports, ts/no-var-requires
56+
const mo = require(injectFilePath)
57+
if (mo.contextRef) {
58+
return mo.contextRef.value
59+
}
60+
}
61+
}
62+
63+
return []
64+
}
65+
66+
getClassCaches(): TailwindcssClassCache[] {
67+
const contexts = this.getContexts()
68+
return contexts.filter(x => isObject(x)).map(x => x.classCache)
69+
}
70+
71+
getClassCacheSet(options?: { removeUniversalSelector?: boolean }): Set<string> {
72+
const classCaches = this.getClassCaches()
73+
const classSet = new Set<string>()
74+
for (const classCacheMap of classCaches) {
75+
const keys = classCacheMap.keys()
76+
for (const key of keys) {
77+
const v = key.toString()
78+
if (options?.removeUniversalSelector && v === '*') {
79+
continue
80+
}
81+
classSet.add(v)
82+
}
83+
}
84+
return classSet
3985
}
4086

4187
/**
4288
* @description 在多个 tailwindcss 上下文时,这个方法将被执行多次,所以策略上应该使用 append
4389
*/
44-
getClassSet(options?: { basedir?: string, cacheStrategy?: CacheStrategy, removeUniversalSelector?: boolean }) {
45-
const { basedir, cacheStrategy = this.cacheOptions.strategy ?? 'merge', removeUniversalSelector = true } = options ?? {}
46-
const set = getClassCacheSet(basedir, {
90+
getClassSet(options?: { cacheStrategy?: CacheStrategy, removeUniversalSelector?: boolean }) {
91+
const { cacheStrategy = this.cacheOptions.strategy ?? 'merge', removeUniversalSelector = true } = options ?? {}
92+
const set = this.getClassCacheSet({
4793
removeUniversalSelector,
4894
})
4995
if (cacheStrategy === 'overwrite') {
@@ -62,10 +108,6 @@ export class TailwindcssPatcher {
62108
return set
63109
}
64110

65-
getContexts(basedir?: string) {
66-
return getContexts(basedir)
67-
}
68-
69111
async extract(options?: UserConfig['patch']) {
70112
const { output, tailwindcss } = options ?? {}
71113
if (output && tailwindcss) {
@@ -77,9 +119,9 @@ export class TailwindcssPatcher {
77119
removeUniversalSelector,
78120
})
79121
if (filename) {
80-
await ensureDir(dirname(filename))
122+
await ensureDir(path.dirname(filename))
81123
const classList = [...set]
82-
await fs.writeFile(filename, JSON.stringify(classList, null, loose ? 2 : undefined), 'utf8')
124+
fs.writeFileSync(filename, JSON.stringify(classList, null, loose ? 2 : undefined), 'utf8')
83125
return filename
84126
}
85127
}

packages/tailwindcss-patch/src/types.ts

+7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import type { Config } from 'tailwindcss'
33

44
export type CacheStrategy = 'merge' | 'overwrite'
55

6+
export interface PackageInfo {
7+
name: string
8+
version: string | undefined
9+
rootPath: string
10+
packageJsonPath: string
11+
}
12+
613
export interface CacheOptions {
714
// enable?: boolean
815
dir?: string

packages/tailwindcss-patch/src/utils.ts

+56
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import fss from 'node:fs'
22
import fs from 'node:fs/promises'
3+
import path from 'node:path'
34
import type { SyncOpts } from 'resolve'
45
import pkg from 'resolve'
6+
import type { PackageJson } from 'pkg-types'
57

68
const { sync } = pkg
79

@@ -35,3 +37,57 @@ export async function ensureDir(p: string) {
3537
})
3638
}
3739
}
40+
41+
function searchPackageJSON(dir: string) {
42+
let packageJsonPath
43+
while (true) {
44+
if (!dir) {
45+
return
46+
}
47+
const newDir = path.dirname(dir)
48+
if (newDir === dir) {
49+
return
50+
}
51+
dir = newDir
52+
packageJsonPath = path.join(dir, 'package.json')
53+
if (fss.existsSync(packageJsonPath)) {
54+
break
55+
}
56+
}
57+
58+
return packageJsonPath
59+
}
60+
61+
function getTailwindcssEntry(name: string = 'tailwindcss', opts?: SyncOpts) {
62+
return requireResolve(name, opts)
63+
}
64+
65+
function getPackageJsonPath(name: string, options: SyncOpts = {}) {
66+
const entry = getTailwindcssEntry(name, options)
67+
if (!entry) {
68+
return
69+
}
70+
71+
return searchPackageJSON(entry)
72+
}
73+
74+
export function getPackageInfoSync(name: string, options: SyncOpts = {}) {
75+
const packageJsonPath = getPackageJsonPath(name, options)
76+
if (!packageJsonPath) {
77+
return
78+
}
79+
80+
const packageJson: PackageJson = JSON.parse(fss.readFileSync(packageJsonPath, 'utf8'))
81+
82+
return {
83+
name,
84+
version: packageJson.version,
85+
rootPath: path.dirname(packageJsonPath),
86+
packageJsonPath,
87+
packageJson,
88+
}
89+
}
90+
91+
export function isObject(val: any) {
92+
return val != null && typeof val === 'object' && Array.isArray(val) === false
93+
};

packages/tailwindcss-patch/test/__snapshots__/postcss7-compat.test.ts.snap

+37
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,43 @@ function _default(configOrPath = {}) {
3737
}"
3838
`;
3939

40+
exports[`postcss7-compat > jit plugins patch case 0 1`] = `
41+
""use strict";
42+
43+
Object.defineProperty(exports, "__esModule", {
44+
value: true
45+
});
46+
exports.default = _default;
47+
var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext"));
48+
var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext"));
49+
var _sharedState = require("./lib/sharedState");
50+
var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures"));
51+
function _interopRequireDefault(obj) {
52+
return obj && obj.__esModule ? obj : {
53+
default: obj
54+
};
55+
}
56+
var contextRef = {
57+
value: []
58+
};
59+
exports.contextRef = contextRef;
60+
function _default(configOrPath = {}) {
61+
return [_sharedState.env.DEBUG && function (root) {
62+
console.log('\\n');
63+
console.time('JIT TOTAL');
64+
return root;
65+
}, function (root, result) {
66+
contextRef.value.length = 0;
67+
let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext.default)(configOrPath) : (0, _setupTrackingContext.default)(configOrPath);
68+
contextRef.value.push((0, _processTailwindFeatures.default)(setupContext)(root, result));
69+
}, _sharedState.env.DEBUG && function (root) {
70+
console.timeEnd('JIT TOTAL');
71+
console.log('\\n');
72+
return root;
73+
}].filter(Boolean);
74+
}"
75+
`;
76+
4077
exports[`postcss7-compat > processTailwindFeatures patch 1`] = `
4178
""use strict";
4279

0 commit comments

Comments
 (0)