WindiCSS實(shí)現(xiàn)加載windi.config.ts配置文件詳解
背景
我們知道WindiCSS
的配置文件既支持js
后綴也支持ts
后綴,即:windi.config.js
和windi.config.ts
我們?cè)?vscode 安裝的WindiCSS IntelliSense
也支持讀取多種后綴格式的配置文件。vscode 基于 electron 實(shí)現(xiàn),electron 底層是一個(gè)node.js + v8
的集成終端,支持運(yùn)行 js 格式的代碼,WindiCSS IntelliSense
最終打包出來的運(yùn)行的代碼也是 js 格式的代碼
那WindiCSS IntelliSense
是怎么實(shí)現(xiàn) js 文件加載 ts 文件的呢?
這個(gè)問題困惑了我大半天,正好最近在寫腳手架,需要支持加載 ts 后綴的配置文件
于是下定決心,把這個(gè)問題搞清楚,最后終于在源碼里找到了答案
解惑
WindiCSS IntelliSense源碼
- 我們將
WindiCSS IntelliSense
源碼直接clone
下來
$ git clone https://github.com/windicss/windicss-intellisense.git
- 找到讀取配置文件的核心代碼
<!--src\lib\index.ts--> // ... async init() { try { const config = await this.loadConfig(); this.processor = new Processor( config ) as Processor; this.attrPrefix = this.processor.config('attributify.prefix') as | string | undefined; this.variants = this.processor.resolveVariants(); this.colors = flatColors( this.processor.theme('colors', {}) as colorObject ); this.register(); } catch (error) { Log.error(error); } } // ...
- 關(guān)鍵實(shí)現(xiàn)
<!--src\lib\index.ts--> // ... import { loadConfig } from 'unconfig'; // ... async loadConfig(file?: string) { if(!workspace.workspaceFolders) return; const { config, sources } = await loadConfig<Config>({ sources: [ { files: 'windi.config', extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs'], }, { files: 'tailwind.config', extensions: ['ts', 'mts', 'cts', 'js', 'mjs', 'cjs'], }, ], merge: false, cwd: workspace.workspaceFolders[0].uri.fsPath, }); Log.info(`Loading Config File: ${sources}`); return config; } // ...
從關(guān)鍵實(shí)現(xiàn)的代碼上看,我們就找到了答案:使用unconfig來實(shí)現(xiàn)加載不同后綴的文件
看到這里,我們還是沒有搞懂:為什么js
能加載ts
,我們繼續(xù)深入了解一下unconfig
的內(nèi)部實(shí)現(xiàn)
unconfig源碼
- 我們將
unconfig
源碼直接clone
下來
git clone https://github.com/antfu/unconfig.git
- 核心代碼
<!--src\index.ts--> // ... import jiti from 'jiti' // ... async function loadConfigFile<T>(filepath: string, source: LoadConfigSource<T>): Promise<LoadConfigResult<T> | undefined> { let config: T | undefined let parser = source.parser || 'auto' let bundleFilepath = filepath let code: string | undefined async function read() { if (code == null) code = await fs.readFile(filepath, 'utf-8') return code } if (source.transform) { const transformed = await source.transform(await read(), filepath) if (transformed) { bundleFilepath = join(dirname(filepath), `__unconfig_${basename(filepath)}`) await fs.writeFile(bundleFilepath, transformed, 'utf-8') code = transformed } } if (parser === 'auto') { try { config = JSON.parse(await read()) parser = 'json' } catch { parser = 'require' } } try { if (!config) { if (typeof parser === 'function') { config = await parser(filepath) } else if (parser === 'require') { config = await jiti(filepath, { interopDefault: true, cache: false, requireCache: false, v8cache: false, esmResolve: true, })(bundleFilepath) } else if (parser === 'json') { config = JSON.parse(await read()) } } if (!config) return const rewritten = source.rewrite ? await source.rewrite(config, filepath) : config if (!rewritten) return undefined return { config: rewritten, sources: [filepath], } } catch (e) { if (source.skipOnError) return throw e } finally { if (bundleFilepath !== filepath) await fs.unlink(bundleFilepath).catch() } } // ...
- 把核心代碼進(jìn)行精簡(jiǎn),找到關(guān)鍵實(shí)現(xiàn)
<!--src\index.ts--> // ... import jiti from 'jiti' // ... async function loadConfigFile<T>(filepath: string, source: LoadConfigSource<T>): Promise<LoadConfigResult<T> | undefined> { // ... try { if (!config) { if (typeof parser === 'function') { config = await parser(filepath) } else if (parser === 'require') { config = await jiti(filepath, { interopDefault: true, cache: false, requireCache: false, v8cache: false, esmResolve: true, })(bundleFilepath) } else if (parser === 'json') { config = JSON.parse(await read()) } } // ... } // ...
從關(guān)鍵實(shí)現(xiàn)的代碼上看,我們就找到了答案:使用jiti來實(shí)現(xiàn) js 文件加載 ts 文件時(shí),動(dòng)態(tài)編譯 ts 文件并返回結(jié)果。
jiti
文檔中這么描述:Runtime typescript and ESM support for Node.js (CommonJS),我們可以更加粗暴地理解為require-ts
。
為了讓大家更好地理解unconfig
的工作流程,樓主根據(jù)上述的unconfig
核心代碼,整理出一個(gè)unconfig核心工作原理流程圖
關(guān)于js
文件如何加載ts
文件的疑惑得以解開
代碼實(shí)踐
看過沒練過,等于沒看過 - B 站夢(mèng)覺教游泳
我們?cè)趯懩_手架的時(shí)候可以直接使用unconfig
讀取配置文件即可,例如:讀取vite.config.ts
可以這么實(shí)現(xiàn)
import { loadConfig } from 'unconfig' const { config } = await loadConfig({ sources: [ { files: 'vite.config', async rewrite(config) { return await (typeof config === 'function' ? config() : config) }, }, ] })
以上就是WindiCSS實(shí)現(xiàn)加載windi.config.ts配置文件詳解的詳細(xì)內(nèi)容,更多關(guān)于WindiCSS加載windi.config.ts的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
動(dòng)態(tài)引入DynamicImport實(shí)現(xiàn)原理
這篇文章主要為大家介紹了動(dòng)態(tài)引入DynamicImport實(shí)現(xiàn)原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Js原型鏈constructor prototype __proto__屬性實(shí)例詳解
這篇文章主要介紹了Js原型鏈constructor prototype __proto__屬性實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10electron創(chuàng)建新窗口模態(tài)框并實(shí)現(xiàn)主進(jìn)程傳值給子進(jìn)程
這篇文章主要為大家介紹了electron創(chuàng)建新窗口模態(tài)框并實(shí)現(xiàn)主進(jìn)程傳值給子進(jìn)程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02