11// @ts -check
22import * as fs from 'fs/promises'
3- import { createRequire } from 'module'
43import * as path from 'path'
54import { pathToFileURL } from 'url'
65import clearModule from 'clear-module'
@@ -18,11 +17,9 @@ import loadConfigFallback from 'tailwindcss/loadConfig'
1817import resolveConfigFallback from 'tailwindcss/resolveConfig'
1918import type { RequiredConfig } from 'tailwindcss/types/config.js'
2019import { expiringMap } from './expiring-map.js'
21- import { resolveFrom , resolveIn } from './resolve'
20+ import { resolveCssFrom , resolveJsFrom } from './resolve'
2221import type { ContextContainer } from './types'
2322
24- let localRequire = createRequire ( import . meta. url )
25-
2623let sourceToPathMap = new Map < string , string | null > ( )
2724let sourceToEntryMap = new Map < string , string | null > ( )
2825let pathToContextMap = expiringMap < string | null , ContextContainer > ( 10_000 )
@@ -107,7 +104,7 @@ async function loadTailwindConfig(
107104 let tailwindConfig : RequiredConfig = { content : [ ] }
108105
109106 try {
110- let pkgFile = resolveIn ( 'tailwindcss/package.json' , [ baseDir ] )
107+ let pkgFile = resolveJsFrom ( baseDir , 'tailwindcss/package.json' )
111108 let pkgDir = path . dirname ( pkgFile )
112109
113110 try {
@@ -151,29 +148,40 @@ async function loadTailwindConfig(
151148 * Create a loader function that can load plugins and config files relative to
152149 * the CSS file that uses them. However, we don't want missing files to prevent
153150 * everything from working so we'll let the error handler decide how to proceed.
154- *
155- * @param {object } param0
156- * @returns
157151 */
158152function createLoader < T > ( {
153+ legacy,
159154 filepath,
160155 onError,
161156} : {
157+ legacy : boolean
162158 filepath : string
163- onError : ( id : string , error : unknown ) => T
159+ onError : ( id : string , error : unknown , resourceType : string ) => T
164160} ) {
165- let baseDir = path . dirname ( filepath )
166161 let cacheKey = `${ + Date . now ( ) } `
167162
168- return async function loadFile ( id : string ) {
163+ async function loadFile ( id : string , base : string , resourceType : string ) {
169164 try {
170- let resolved = resolveFrom ( baseDir , id )
165+ let resolved = resolveJsFrom ( base , id )
166+
171167 let url = pathToFileURL ( resolved )
172168 url . searchParams . append ( 't' , cacheKey )
173169
174170 return await import ( url . href ) . then ( ( m ) => m . default ?? m )
175171 } catch ( err ) {
176- return onError ( id , err )
172+ return onError ( id , err , resourceType )
173+ }
174+ }
175+
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 ) ,
177185 }
178186 }
179187}
@@ -184,7 +192,8 @@ async function loadV4(
184192 entryPoint : string | null ,
185193) {
186194 // Import Tailwind — if this is v4 it'll have APIs we can use directly
187- let pkgPath = resolveIn ( 'tailwindcss' , [ baseDir ] )
195+ let pkgPath = resolveJsFrom ( baseDir , 'tailwindcss' )
196+
188197 let tw = await import ( pathToFileURL ( pkgPath ) . toString ( ) )
189198
190199 // This is not Tailwind v4
@@ -195,15 +204,63 @@ async function loadV4(
195204 // If the user doesn't define an entrypoint then we use the default theme
196205 entryPoint = entryPoint ?? `${ pkgDir } /theme.css`
197206
207+ let importBasePath = path . dirname ( entryPoint )
208+
198209 // Resolve imports in the entrypoint to a flat CSS tree
199210 let css = await fs . readFile ( entryPoint , 'utf-8' )
200- let resolveImports = postcss ( [ postcssImport ( ) ] )
201- let result = await resolveImports . process ( css , { from : entryPoint } )
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+ }
202231
203232 // Load the design system and set up a compatible context object that is
204233 // usable by the rest of the plugin
205- let design = await tw . __unstable__loadDesignSystem ( result . css , {
234+ 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
206262 loadPlugin : createLoader ( {
263+ legacy : true ,
207264 filepath : entryPoint ,
208265 onError ( id , err ) {
209266 console . error ( `Unable to load plugin: ${ id } ` , err )
@@ -213,6 +270,7 @@ async function loadV4(
213270 } ) ,
214271
215272 loadConfig : createLoader ( {
273+ legacy : true ,
216274 filepath : entryPoint ,
217275 onError ( id , err ) {
218276 console . error ( `Unable to load config: ${ id } ` , err )
0 commit comments