Skip to content

Commit a8693bd

Browse files
committed
Add support for new loadModule and loadStylesheet APIs
1 parent 98c4812 commit a8693bd

File tree

2 files changed

+80
-9
lines changed

2 files changed

+80
-9
lines changed

src/config.ts

+68-9
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import loadConfigFallback from 'tailwindcss/loadConfig'
1717
import resolveConfigFallback from 'tailwindcss/resolveConfig'
1818
import type { RequiredConfig } from 'tailwindcss/types/config.js'
1919
import { expiringMap } from './expiring-map.js'
20-
import { resolveJsFrom } from './resolve'
20+
import { resolveCssFrom, resolveJsFrom } from './resolve'
2121
import type { ContextContainer } from './types'
2222

2323
let sourceToPathMap = new Map<string, string | null>()
@@ -150,15 +150,17 @@ async function loadTailwindConfig(
150150
* everything from working so we'll let the error handler decide how to proceed.
151151
*/
152152
function createLoader<T>({
153+
legacy,
153154
filepath,
154155
onError,
155156
}: {
157+
legacy: boolean
156158
filepath: string
157-
onError: (id: string, error: unknown) => T
159+
onError: (id: string, error: unknown, resourceType: string) => T
158160
}) {
159161
let cacheKey = `${+Date.now()}`
160162

161-
async function loadFile(id: string, base: string) {
163+
async function loadFile(id: string, base: string, resourceType: string) {
162164
try {
163165
let resolved = resolveJsFrom(base, id)
164166

@@ -167,12 +169,21 @@ function createLoader<T>({
167169

168170
return await import(url.href).then((m) => m.default ?? m)
169171
} catch (err) {
170-
return onError(id, err)
172+
return onError(id, err, resourceType)
171173
}
172174
}
173175

174-
let baseDir = path.dirname(filepath)
175-
return (id: string) => loadFile(id, baseDir)
176+
if (legacy) {
177+
let baseDir = path.dirname(filepath)
178+
return (id: string) => loadFile(id, baseDir, 'module')
179+
}
180+
181+
return async (id: string, base: string, resourceType: string) => {
182+
return {
183+
base,
184+
module: await loadFile(id, base, resourceType),
185+
}
186+
}
176187
}
177188

178189
async function loadV4(
@@ -193,16 +204,63 @@ async function loadV4(
193204
// If the user doesn't define an entrypoint then we use the default theme
194205
entryPoint = entryPoint ?? `${pkgDir}/theme.css`
195206

207+
let importBasePath = path.dirname(entryPoint)
208+
196209
// Resolve imports in the entrypoint to a flat CSS tree
197210
let css = await fs.readFile(entryPoint, 'utf-8')
198-
let resolveImports = postcss([postcssImport()])
199-
let result = await resolveImports.process(css, { from: entryPoint })
200-
css = result.css
211+
212+
// Determine if the v4 API supports resolving `@import`
213+
let supportsImports = false
214+
try {
215+
await tw.__unstable__loadDesignSystem('@import "./empty";', {
216+
loadStylesheet: () => {
217+
supportsImports = true
218+
return {
219+
base: importBasePath,
220+
content: '',
221+
}
222+
},
223+
})
224+
} catch {}
225+
226+
if (!supportsImports) {
227+
let resolveImports = postcss([postcssImport()])
228+
let result = await resolveImports.process(css, { from: entryPoint })
229+
css = result.css
230+
}
201231

202232
// Load the design system and set up a compatible context object that is
203233
// usable by the rest of the plugin
204234
let design = await tw.__unstable__loadDesignSystem(css, {
235+
base: importBasePath,
236+
237+
// v4.0.0-alpha.25+
238+
loadModule: createLoader({
239+
legacy: false,
240+
filepath: entryPoint,
241+
onError: (id, err, resourceType) => {
242+
console.error(`Unable to load ${resourceType}: ${id}`, err)
243+
244+
if (resourceType === 'config') {
245+
return {}
246+
} else if (resourceType === 'plugin') {
247+
return () => {}
248+
}
249+
},
250+
}),
251+
252+
loadStylesheet: async (id: string, base: string) => {
253+
let resolved = resolveCssFrom(base, id)
254+
255+
return {
256+
base: path.dirname(resolved),
257+
content: await fs.readFile(resolved, 'utf-8'),
258+
}
259+
},
260+
261+
// v4.0.0-alpha.24 and below
205262
loadPlugin: createLoader({
263+
legacy: true,
206264
filepath: entryPoint,
207265
onError(id, err) {
208266
console.error(`Unable to load plugin: ${id}`, err)
@@ -212,6 +270,7 @@ async function loadV4(
212270
}),
213271

214272
loadConfig: createLoader({
273+
legacy: true,
215274
filepath: entryPoint,
216275
onError(id, err) {
217276
console.error(`Unable to load config: ${id}`, err)

src/resolve.ts

+12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ const cjsResolver = ResolverFactory.createResolver({
2121
conditionNames: ['node', 'require'],
2222
})
2323

24+
const cssResolver = ResolverFactory.createResolver({
25+
fileSystem,
26+
useSyncFileSystemCalls: true,
27+
extensions: ['.css'],
28+
mainFields: ['style'],
29+
conditionNames: ['style'],
30+
})
31+
2432
// This is a long-lived cache for resolved modules whether they exist or not
2533
// Because we're compatible with a large number of plugins, we need to check
2634
// for the existence of a module before attempting to import it. This cache
@@ -57,3 +65,7 @@ export function resolveJsFrom(base: string, id: string): string {
5765
return cjsResolver.resolveSync({}, base, id) || id
5866
}
5967
}
68+
69+
export function resolveCssFrom(base: string, id: string) {
70+
return cssResolver.resolveSync({}, base, id) || id
71+
}

0 commit comments

Comments
 (0)