turbopack-unocss-transform 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -8
- package/dist/index.cjs +50 -0
- package/dist/index.mjs +20 -6
- package/dist/loader.cjs +15 -0
- package/dist/loader.mjs +298 -54
- package/package.json +16 -9
package/README.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
# turbopack-unocss-transform
|
|
2
|
-
A Turbopack loader for Next.js that applies UnoCSS transformers (like variant-group and attributify-jsx) directly to your TS/JS/TSX/JSX source before CSS generation. Actual CSS is produced by @unocss/postcss; this loader only transforms source code.
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
A Turbopack loader for Next.js that applies UnoCSS transformers (like variant-group and attributify-jsx) directly to your TS/JS/TSX/JSX source before CSS generation.
|
|
4
|
+
|
|
5
|
+
Actual CSS is produced by `@unocss/postcss`; this loader only transforms source code.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add -D turbopack-unocss-transform
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### next.config.ts
|
|
5
16
|
|
|
6
|
-
`next.config.ts`
|
|
7
17
|
```typescript
|
|
8
18
|
import type {NextConfig} from "next"
|
|
9
19
|
import withUnoTransform from "turbopack-unocss-transform"
|
|
@@ -15,16 +25,33 @@ const nextConfig: NextConfig = withUnoTransform({
|
|
|
15
25
|
export default nextConfig
|
|
16
26
|
```
|
|
17
27
|
|
|
18
|
-
|
|
28
|
+
### postcss.config.mjs
|
|
29
|
+
|
|
30
|
+
**Option 1: Import config object**
|
|
31
|
+
|
|
19
32
|
```js
|
|
20
|
-
import unoConfig from "./
|
|
33
|
+
import unoConfig from "./uno.config"
|
|
21
34
|
|
|
22
35
|
export default {
|
|
23
36
|
plugins: [
|
|
24
|
-
["@unocss/postcss", {
|
|
25
|
-
configOrPath: unoConfig
|
|
26
|
-
}],
|
|
37
|
+
["@unocss/postcss", {configOrPath: unoConfig}],
|
|
27
38
|
"autoprefixer"
|
|
28
39
|
]
|
|
29
40
|
}
|
|
30
41
|
```
|
|
42
|
+
|
|
43
|
+
**Option 2: Pass config path as string**
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
export default {
|
|
47
|
+
plugins: [
|
|
48
|
+
["@unocss/postcss", {configOrPath: "./uno.config.ts"}],
|
|
49
|
+
"autoprefixer"
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- Next.js 15+ with Turbopack
|
|
57
|
+
- UnoCSS 0.58+
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const path = require("node:path")
|
|
2
|
+
|
|
3
|
+
function getLoaderPath() {
|
|
4
|
+
return path.resolve(__dirname, "loader.mjs")
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function withUnoTransform(userConfig = {}) {
|
|
8
|
+
const loaderPath = getLoaderPath()
|
|
9
|
+
|
|
10
|
+
const base = {
|
|
11
|
+
turbopack: {
|
|
12
|
+
rules: {
|
|
13
|
+
"**/*.{ts,tsx,js,jsx}": {
|
|
14
|
+
loaders: [loaderPath]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return merge(base, userConfig)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function merge(a, b) {
|
|
24
|
+
if (!b) return a
|
|
25
|
+
|
|
26
|
+
const out = JSON.parse(JSON.stringify(a))
|
|
27
|
+
|
|
28
|
+
mergeInto(out, b)
|
|
29
|
+
|
|
30
|
+
return out
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function mergeInto(t, s) {
|
|
34
|
+
for (const k of Object.keys(s)) {
|
|
35
|
+
const sv = s[k]
|
|
36
|
+
const tv = t[k]
|
|
37
|
+
|
|
38
|
+
if (Array.isArray(sv)) {
|
|
39
|
+
t[k] = Array.isArray(tv) ? [...tv, ...sv] : [...sv]
|
|
40
|
+
} else if (sv && typeof sv === "object") {
|
|
41
|
+
if (!tv || typeof tv !== "object") t[k] = {}
|
|
42
|
+
mergeInto(t[k], sv)
|
|
43
|
+
} else {
|
|
44
|
+
t[k] = sv
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = withUnoTransform
|
|
50
|
+
module.exports.default = withUnoTransform
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
import path from "node:path"
|
|
2
|
+
import {fileURLToPath} from "node:url"
|
|
3
|
+
|
|
4
|
+
function getLoaderPath() {
|
|
5
|
+
try {
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
7
|
+
const __dirname = path.dirname(__filename)
|
|
8
|
+
|
|
9
|
+
return path.resolve(__dirname, "loader.mjs")
|
|
10
|
+
} catch {
|
|
11
|
+
return path.resolve(
|
|
12
|
+
process.cwd(),
|
|
13
|
+
"node_modules/turbopack-unocss-transform/dist/loader.mjs"
|
|
14
|
+
)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
2
17
|
|
|
3
18
|
export default function withUnoTransform(userConfig = {}) {
|
|
4
|
-
const loaderPath =
|
|
19
|
+
const loaderPath = getLoaderPath()
|
|
20
|
+
|
|
5
21
|
const base = {
|
|
6
22
|
turbopack: {
|
|
7
23
|
rules: {
|
|
@@ -27,15 +43,13 @@ function merge(a, b) {
|
|
|
27
43
|
|
|
28
44
|
function mergeInto(t, s) {
|
|
29
45
|
for (const k of Object.keys(s)) {
|
|
30
|
-
const sv = s[k]
|
|
46
|
+
const sv = s[k]
|
|
47
|
+
const tv = t[k]
|
|
31
48
|
|
|
32
49
|
if (Array.isArray(sv)) {
|
|
33
50
|
t[k] = Array.isArray(tv) ? [...tv, ...sv] : [...sv]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
else if (sv && typeof sv === "object") {
|
|
51
|
+
} else if (sv && typeof sv === "object") {
|
|
37
52
|
if (!tv || typeof tv !== "object") t[k] = {}
|
|
38
|
-
|
|
39
53
|
mergeInto(t[k], sv)
|
|
40
54
|
} else {
|
|
41
55
|
t[k] = sv
|
package/dist/loader.cjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
let loaderPromise = null
|
|
2
|
+
|
|
3
|
+
async function getLoader() {
|
|
4
|
+
if (!loaderPromise) {
|
|
5
|
+
loaderPromise = import("./loader.mjs").then((m) => m.default)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return loaderPromise
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = async function unoLoader(source) {
|
|
12
|
+
const loader = await getLoader()
|
|
13
|
+
|
|
14
|
+
return loader.call(this, source)
|
|
15
|
+
}
|
package/dist/loader.mjs
CHANGED
|
@@ -1,98 +1,328 @@
|
|
|
1
|
+
import fs from "node:fs"
|
|
2
|
+
import {createRequire} from "node:module"
|
|
1
3
|
import path from "node:path"
|
|
4
|
+
import {createGenerator} from "@unocss/core"
|
|
2
5
|
import MagicString from "magic-string"
|
|
3
|
-
import {createGenerator} from "unocss"
|
|
4
|
-
import {createRequire} from "node:module"
|
|
5
6
|
|
|
7
|
+
const PREFIX = "[UnoCSS-Turbopack]"
|
|
6
8
|
const nodeRequire = createRequire(import.meta.url)
|
|
7
9
|
|
|
10
|
+
const DEFAULT_CONFIG_PATHS = [
|
|
11
|
+
"uno.config.ts",
|
|
12
|
+
"uno.config.js",
|
|
13
|
+
"uno.config.mjs",
|
|
14
|
+
"unocss.config.ts",
|
|
15
|
+
"unocss.config.js",
|
|
16
|
+
"unocss.config.mjs"
|
|
17
|
+
]
|
|
18
|
+
|
|
8
19
|
let uno = null
|
|
9
20
|
let unoInitPromise = null
|
|
10
21
|
let cfg = null
|
|
11
22
|
let cfgLoaded = false
|
|
23
|
+
let cfgPath = null
|
|
24
|
+
let cfgMtime = 0
|
|
25
|
+
|
|
26
|
+
function createJiti() {
|
|
27
|
+
try {
|
|
28
|
+
return nodeRequire("jiti")(import.meta.url, {
|
|
29
|
+
interopDefault: true,
|
|
30
|
+
esmResolve: true
|
|
31
|
+
})
|
|
32
|
+
} catch (error) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`${PREFIX} Failed to initialize jiti: ${error?.message || error}`
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveConfigPath(configPath) {
|
|
40
|
+
if (path.isAbsolute(configPath)) {
|
|
41
|
+
return configPath
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return path.resolve(process.cwd(), configPath)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function loadConfigFromPath(configPath) {
|
|
48
|
+
const jiti = createJiti()
|
|
49
|
+
const resolved = resolveConfigPath(configPath)
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const mod = jiti(resolved)
|
|
53
|
+
|
|
54
|
+
return mod?.default ?? mod
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error(
|
|
57
|
+
`${PREFIX} Failed to load config from "${resolved}": ${error?.message || error}`
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function findDefaultConfigPath() {
|
|
63
|
+
for (const p of DEFAULT_CONFIG_PATHS) {
|
|
64
|
+
const fullPath = path.join(process.cwd(), p)
|
|
65
|
+
|
|
66
|
+
if (fs.existsSync(fullPath)) {
|
|
67
|
+
return fullPath
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return null
|
|
72
|
+
}
|
|
12
73
|
|
|
13
74
|
function loadPostcssConfig() {
|
|
14
|
-
const jiti =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
75
|
+
const jiti = createJiti()
|
|
76
|
+
const possiblePaths = [
|
|
77
|
+
"postcss.config.mjs",
|
|
78
|
+
"postcss.config.js",
|
|
79
|
+
"postcss.config.cjs"
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
let mod = null
|
|
83
|
+
|
|
84
|
+
for (const p of possiblePaths) {
|
|
85
|
+
const fullPath = path.join(process.cwd(), p)
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
mod = jiti(fullPath)
|
|
89
|
+
break
|
|
90
|
+
} catch {
|
|
91
|
+
// File not found, try next
|
|
92
|
+
}
|
|
93
|
+
}
|
|
19
94
|
|
|
20
|
-
|
|
95
|
+
if (!mod) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`${PREFIX} Could not find postcss.config.{mjs,js,cjs} in ${process.cwd()}`
|
|
98
|
+
)
|
|
99
|
+
}
|
|
21
100
|
|
|
22
101
|
return mod?.default ?? mod
|
|
23
102
|
}
|
|
24
103
|
|
|
104
|
+
function checkIsUnoPlugin(entry) {
|
|
105
|
+
if (typeof entry === "string") {
|
|
106
|
+
return entry === "@unocss/postcss"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (typeof entry === "function") {
|
|
110
|
+
const name = entry.name || ""
|
|
111
|
+
|
|
112
|
+
return name.toLowerCase().includes("unocss") || name.includes("Uno")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (typeof entry === "object" && entry !== null) {
|
|
116
|
+
const postcssPlugin = entry.postcssPlugin || ""
|
|
117
|
+
|
|
118
|
+
return postcssPlugin.toLowerCase().includes("unocss")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function extractConfigFromPlugin(entry) {
|
|
125
|
+
if (Array.isArray(entry)) {
|
|
126
|
+
const [nameOrFn, opts] = entry
|
|
127
|
+
|
|
128
|
+
if (checkIsUnoPlugin(nameOrFn) && opts?.configOrPath) {
|
|
129
|
+
return opts.configOrPath
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (checkIsUnoPlugin(nameOrFn)) {
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (checkIsUnoPlugin(entry)) {
|
|
138
|
+
if (typeof entry === "object" && entry.configOrPath) {
|
|
139
|
+
return entry.configOrPath
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return null
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return undefined
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function invalidateIfConfigChanged() {
|
|
149
|
+
if (!cfgPath) return false
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const stat = fs.statSync(cfgPath)
|
|
153
|
+
|
|
154
|
+
if (stat.mtimeMs !== cfgMtime) {
|
|
155
|
+
cfgMtime = stat.mtimeMs
|
|
156
|
+
cfgLoaded = false
|
|
157
|
+
cfg = null
|
|
158
|
+
uno = null
|
|
159
|
+
unoInitPromise = null
|
|
160
|
+
|
|
161
|
+
return true
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
// File not accessible, keep cache
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
|
|
25
170
|
function loadUnoConfigFromPostcss() {
|
|
26
171
|
if (cfgLoaded) return cfg
|
|
27
172
|
|
|
28
173
|
try {
|
|
29
174
|
nodeRequire("tsconfig-paths/register")
|
|
30
|
-
} catch {
|
|
175
|
+
} catch {
|
|
176
|
+
// Optional dependency
|
|
177
|
+
}
|
|
31
178
|
|
|
32
|
-
|
|
179
|
+
let pc
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
pc = loadPostcssConfig()
|
|
183
|
+
} catch (error) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`${PREFIX} Failed to load postcss config: ${error?.message || error}`
|
|
186
|
+
)
|
|
187
|
+
}
|
|
33
188
|
|
|
34
|
-
if (!pc
|
|
35
|
-
throw new Error(
|
|
189
|
+
if (!(pc && Array.isArray(pc.plugins))) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`${PREFIX} postcss.config is invalid: "plugins" must be an array`
|
|
192
|
+
)
|
|
36
193
|
}
|
|
37
194
|
|
|
38
|
-
let found
|
|
195
|
+
let found
|
|
39
196
|
|
|
40
197
|
for (const entry of pc.plugins) {
|
|
41
|
-
|
|
198
|
+
const result = extractConfigFromPlugin(entry)
|
|
42
199
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
200
|
+
if (result !== undefined) {
|
|
201
|
+
found = result
|
|
202
|
+
break
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (found === undefined) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`${PREFIX} UnoCSS plugin not found in postcss.config plugins`
|
|
48
209
|
)
|
|
210
|
+
}
|
|
49
211
|
|
|
50
|
-
|
|
212
|
+
if (found === null) {
|
|
213
|
+
const defaultPath = findDefaultConfigPath()
|
|
51
214
|
|
|
52
|
-
|
|
215
|
+
if (defaultPath) {
|
|
216
|
+
cfgPath = defaultPath
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const stat = fs.statSync(cfgPath)
|
|
220
|
+
cfgMtime = stat.mtimeMs
|
|
221
|
+
} catch {
|
|
222
|
+
// Will be handled below
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
cfg = loadConfigFromPath(defaultPath)
|
|
227
|
+
} catch (error) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`${PREFIX} Failed to load default UnoCSS config from "${defaultPath}": ${error?.message || error}`
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`${PREFIX} No configOrPath provided and no default config found. Expected one of: ${DEFAULT_CONFIG_PATHS.join(", ")}`
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
} else if (typeof found === "string") {
|
|
238
|
+
cfgPath = resolveConfigPath(found)
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const stat = fs.statSync(cfgPath)
|
|
242
|
+
cfgMtime = stat.mtimeMs
|
|
243
|
+
} catch {
|
|
244
|
+
// Will be handled below
|
|
245
|
+
}
|
|
53
246
|
|
|
54
|
-
|
|
247
|
+
try {
|
|
248
|
+
cfg = loadConfigFromPath(found)
|
|
249
|
+
} catch (error) {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`${PREFIX} Failed to load UnoCSS config from path "${found}": ${error?.message || error}`
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
} else if (typeof found === "object" && found !== null) {
|
|
255
|
+
cfg = found
|
|
256
|
+
} else {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`${PREFIX} configOrPath must be an object (UnoCSS config) or a string (path to config file). Got: ${typeof found}`
|
|
259
|
+
)
|
|
55
260
|
}
|
|
56
261
|
|
|
57
|
-
if (!
|
|
58
|
-
throw new Error(
|
|
262
|
+
if (!cfg || typeof cfg !== "object") {
|
|
263
|
+
throw new Error(`${PREFIX} Loaded config is not a valid object`)
|
|
59
264
|
}
|
|
60
265
|
|
|
61
|
-
cfg = found
|
|
62
266
|
cfgLoaded = true
|
|
63
267
|
|
|
64
268
|
return cfg
|
|
65
269
|
}
|
|
66
270
|
|
|
67
271
|
async function getUno() {
|
|
272
|
+
invalidateIfConfigChanged()
|
|
273
|
+
|
|
68
274
|
if (uno) return uno
|
|
69
275
|
if (unoInitPromise) return unoInitPromise
|
|
70
276
|
|
|
71
|
-
|
|
277
|
+
let config
|
|
72
278
|
|
|
73
|
-
|
|
279
|
+
try {
|
|
280
|
+
config = loadUnoConfigFromPostcss()
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.error(error.message)
|
|
283
|
+
throw error
|
|
284
|
+
}
|
|
74
285
|
|
|
75
|
-
|
|
286
|
+
try {
|
|
287
|
+
unoInitPromise = createGenerator(config).then((u) => {
|
|
288
|
+
uno = u
|
|
289
|
+
return u
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
return unoInitPromise
|
|
293
|
+
} catch (error) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
`${PREFIX} Failed to create UnoCSS generator: ${error?.message || error}`
|
|
296
|
+
)
|
|
297
|
+
}
|
|
76
298
|
}
|
|
77
299
|
|
|
78
300
|
function isProcessable(id) {
|
|
79
|
-
return
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
301
|
+
if (!id) return false
|
|
302
|
+
if (id.includes("node_modules")) return false
|
|
303
|
+
if (/\.d\.ts$/.test(id)) return false
|
|
304
|
+
if (/\.(test|spec)\.(t|j)sx?$/.test(id)) return false
|
|
305
|
+
|
|
306
|
+
return /\.(t|j)sx?$/.test(id)
|
|
84
307
|
}
|
|
85
308
|
|
|
86
309
|
function pickTransformers(enforce = "default") {
|
|
87
|
-
const list =
|
|
310
|
+
const list = cfg?.transformers || []
|
|
88
311
|
|
|
89
|
-
return list.filter(t => (t?.enforce || "default") === enforce)
|
|
312
|
+
return list.filter((t) => (t?.enforce || "default") === enforce)
|
|
90
313
|
}
|
|
91
314
|
|
|
92
315
|
async function applyTransformersPipeline(code, id) {
|
|
93
|
-
|
|
316
|
+
let u
|
|
317
|
+
|
|
318
|
+
try {
|
|
319
|
+
u = await getUno()
|
|
320
|
+
} catch {
|
|
321
|
+
return null
|
|
322
|
+
}
|
|
323
|
+
|
|
94
324
|
const original = code
|
|
95
|
-
const phases = ["pre","default","post"]
|
|
325
|
+
const phases = ["pre", "default", "post"]
|
|
96
326
|
let current = code
|
|
97
327
|
|
|
98
328
|
for (const phase of phases) {
|
|
@@ -101,7 +331,6 @@ async function applyTransformersPipeline(code, id) {
|
|
|
101
331
|
if (!transformers.length) continue
|
|
102
332
|
|
|
103
333
|
let s = new MagicString(current)
|
|
104
|
-
let changed = false
|
|
105
334
|
|
|
106
335
|
for (const t of transformers) {
|
|
107
336
|
if (!t) continue
|
|
@@ -109,7 +338,12 @@ async function applyTransformersPipeline(code, id) {
|
|
|
109
338
|
if (t.idFilter) {
|
|
110
339
|
try {
|
|
111
340
|
if (!t.idFilter(id)) continue
|
|
112
|
-
} catch {
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.warn(
|
|
343
|
+
`${PREFIX} idFilter failed for transformer "${t.name || "unknown"}": ${error?.message || error}`
|
|
344
|
+
)
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
113
347
|
}
|
|
114
348
|
|
|
115
349
|
const fn = t.transform || t
|
|
@@ -126,23 +360,21 @@ async function applyTransformersPipeline(code, id) {
|
|
|
126
360
|
try {
|
|
127
361
|
await fn(s, id, ctx)
|
|
128
362
|
} catch (error) {
|
|
129
|
-
|
|
363
|
+
const relativePath = path.relative(process.cwd(), id)
|
|
364
|
+
console.error(
|
|
365
|
+
`${PREFIX} Transform failed in "${t.name || "unknown"}" for ${relativePath}: ${error?.stack || error?.message || error}`
|
|
366
|
+
)
|
|
130
367
|
}
|
|
131
368
|
|
|
132
369
|
if (s.hasChanged()) {
|
|
133
370
|
current = s.toString()
|
|
134
371
|
s = new MagicString(current)
|
|
135
|
-
changed = true
|
|
136
372
|
}
|
|
137
373
|
}
|
|
138
|
-
|
|
139
|
-
if (!changed) continue
|
|
140
374
|
}
|
|
141
375
|
|
|
142
376
|
if (current !== original) {
|
|
143
|
-
return {
|
|
144
|
-
code: current
|
|
145
|
-
}
|
|
377
|
+
return {code: current}
|
|
146
378
|
}
|
|
147
379
|
|
|
148
380
|
return null
|
|
@@ -152,10 +384,14 @@ const memo = new Map()
|
|
|
152
384
|
const MEMO_LIMIT = 500
|
|
153
385
|
|
|
154
386
|
function sha1Sync(s) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
387
|
+
try {
|
|
388
|
+
const {createHash} = nodeRequire("node:crypto")
|
|
389
|
+
return createHash("sha1").update(s).digest("hex")
|
|
390
|
+
} catch {
|
|
391
|
+
return `${s.length}_${s.slice(0, 100)}`
|
|
392
|
+
}
|
|
158
393
|
}
|
|
394
|
+
|
|
159
395
|
function memoGet(key) {
|
|
160
396
|
if (!memo.has(key)) return null
|
|
161
397
|
|
|
@@ -182,15 +418,23 @@ export default async function unoLoader(source) {
|
|
|
182
418
|
if (!isProcessable(file)) return code
|
|
183
419
|
if (code.length < 10) return code
|
|
184
420
|
|
|
185
|
-
const key = file
|
|
421
|
+
const key = `${file}:${sha1Sync(code)}`
|
|
186
422
|
const cached = memoGet(key)
|
|
187
423
|
|
|
188
424
|
if (cached) return cached
|
|
189
425
|
|
|
190
|
-
|
|
191
|
-
|
|
426
|
+
try {
|
|
427
|
+
const res = await applyTransformersPipeline(code, file)
|
|
428
|
+
const out = res?.code && res.code !== code ? res.code : code
|
|
429
|
+
|
|
430
|
+
memoSet(key, out)
|
|
192
431
|
|
|
193
|
-
|
|
432
|
+
return out
|
|
433
|
+
} catch (error) {
|
|
434
|
+
console.error(
|
|
435
|
+
`${PREFIX} Loader error for ${path.relative(process.cwd(), file)}: ${error?.message || error}`
|
|
436
|
+
)
|
|
194
437
|
|
|
195
|
-
|
|
438
|
+
return code
|
|
439
|
+
}
|
|
196
440
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbopack-unocss-transform",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "vizet <v@kogita.net>",
|
|
6
6
|
"description": "A Turbopack loader for Next.js that applies UnoCSS transformers (like variant-group and attributify-jsx) directly to your TS/JS/TSX/JSX source before CSS generation.",
|
|
@@ -22,24 +22,31 @@
|
|
|
22
22
|
"attributify-jsx"
|
|
23
23
|
],
|
|
24
24
|
"type": "module",
|
|
25
|
-
"main": "dist/
|
|
25
|
+
"main": "dist/index.mjs",
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
28
28
|
"types": "./dist/index.d.ts",
|
|
29
|
-
"
|
|
29
|
+
"import": "./dist/index.mjs",
|
|
30
|
+
"require": "./dist/index.cjs"
|
|
30
31
|
},
|
|
31
|
-
"./loader":
|
|
32
|
+
"./loader": {
|
|
33
|
+
"import": "./dist/loader.mjs",
|
|
34
|
+
"require": "./dist/loader.cjs"
|
|
35
|
+
}
|
|
32
36
|
},
|
|
33
37
|
"files": [
|
|
34
38
|
"dist"
|
|
35
39
|
],
|
|
36
40
|
"peerDependencies": {
|
|
37
|
-
"
|
|
41
|
+
"next": ">=15.0.0"
|
|
38
42
|
},
|
|
39
43
|
"dependencies": {
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
44
|
+
"@unocss/core": "66.5.6",
|
|
45
|
+
"jiti": "^2.4.0",
|
|
46
|
+
"magic-string": "^0.30.17",
|
|
43
47
|
"tsconfig-paths": "^4.2.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@biomejs/biome": "^2.3.11"
|
|
44
51
|
}
|
|
45
|
-
}
|
|
52
|
+
}
|