From 4334ea31e94695412eafe0ba868ba3db0b4cc98f Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Sat, 25 Mar 2023 19:48:31 +0000 Subject: [PATCH 01/12] fix: typeof import default in dts --- src/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index bfa570f0..ac43d5aa 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -84,7 +84,7 @@ export const createTemplates = (resolvedConfig: Config, maxLevel: number, nuxt = filename: `tailwind.config/${subpath}.mjs`, getContents: () => `${values.map(v => `import _${v} from "./${key}/${v}.mjs"`).join('\n')}\nconst config = { ${values.map(k => `"${k}": _${k}`).join(', ')} }\nexport { config as default${values.length > 0 ? ', _' : ''}${values.join(', _')} }` }) - dtsContent.push(`declare module "#tailwind-config/${subpath}" {${Object.keys(value).map(v => ` export const _${v}: typeof import("#tailwind-config/${join(`${key}/${subpath}`, `../${v}`)}");`).join('')} const defaultExport: { ${values.map(k => `"${k}": typeof _${k}`).join(', ')} }; export default defaultExport; }`) + dtsContent.push(`declare module "#tailwind-config/${subpath}" {${Object.keys(value).map(v => ` export const _${v}: typeof import("#tailwind-config/${join(`${key}/${subpath}`, `../${v}`)}").default;`).join('')} const defaultExport: { ${values.map(k => `"${k}": typeof _${k}`).join(', ')} }; export default defaultExport; }`) } }) } @@ -98,7 +98,7 @@ export const createTemplates = (resolvedConfig: Config, maxLevel: number, nuxt = write: true }) - dtsContent.push(`declare module "#tailwind-config" {${configOptions.map(v => ` export const ${v}: typeof import("${join('#tailwind-config', v)}");`).join('')} const defaultExport: { ${configOptions.map(v => `"${v}": typeof ${v}`)} }; export default defaultExport; }`) + dtsContent.push(`declare module "#tailwind-config" {${configOptions.map(v => ` export const ${v}: typeof import("${join('#tailwind-config', v)}").default;`).join('')} const defaultExport: { ${configOptions.map(v => `"${v}": typeof ${v}`)} }; export default defaultExport; }`) const typesTemplate = addTemplate({ filename: 'tailwind.config.d.ts', getContents: () => dtsContent.join('\n'), From da4f9d327c6a917fee2f401fbd240a047aebe9fa Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Wed, 29 Mar 2023 00:06:39 +0100 Subject: [PATCH 02/12] chore: using nuxt convention for indexing type --- src/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index ac43d5aa..f2dc1b32 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -84,7 +84,7 @@ export const createTemplates = (resolvedConfig: Config, maxLevel: number, nuxt = filename: `tailwind.config/${subpath}.mjs`, getContents: () => `${values.map(v => `import _${v} from "./${key}/${v}.mjs"`).join('\n')}\nconst config = { ${values.map(k => `"${k}": _${k}`).join(', ')} }\nexport { config as default${values.length > 0 ? ', _' : ''}${values.join(', _')} }` }) - dtsContent.push(`declare module "#tailwind-config/${subpath}" {${Object.keys(value).map(v => ` export const _${v}: typeof import("#tailwind-config/${join(`${key}/${subpath}`, `../${v}`)}").default;`).join('')} const defaultExport: { ${values.map(k => `"${k}": typeof _${k}`).join(', ')} }; export default defaultExport; }`) + dtsContent.push(`declare module "#tailwind-config/${subpath}" {${Object.keys(value).map(v => ` export const _${v}: typeof import("#tailwind-config/${join(`${key}/${subpath}`, `../${v}`)}")["default"];`).join('')} const defaultExport: { ${values.map(k => `"${k}": typeof _${k}`).join(', ')} }; export default defaultExport; }`) } }) } @@ -98,7 +98,7 @@ export const createTemplates = (resolvedConfig: Config, maxLevel: number, nuxt = write: true }) - dtsContent.push(`declare module "#tailwind-config" {${configOptions.map(v => ` export const ${v}: typeof import("${join('#tailwind-config', v)}").default;`).join('')} const defaultExport: { ${configOptions.map(v => `"${v}": typeof ${v}`)} }; export default defaultExport; }`) + dtsContent.push(`declare module "#tailwind-config" {${configOptions.map(v => ` export const ${v}: typeof import("${join('#tailwind-config', v)}")["default"];`).join('')} const defaultExport: { ${configOptions.map(v => `"${v}": typeof ${v}`)} }; export default defaultExport; }`) const typesTemplate = addTemplate({ filename: 'tailwind.config.d.ts', getContents: () => dtsContent.join('\n'), From 59d17208163d4c551cda2c4e20c62f1180998280 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Mon, 15 May 2023 15:53:15 +0100 Subject: [PATCH 03/12] chore: initial --- ...tailwind.config.ts => tailwind.config.cjs} | 4 +- src/module.ts | 86 +++++++++---------- 2 files changed, 43 insertions(+), 47 deletions(-) rename playground/theme/{tailwind.config.ts => tailwind.config.cjs} (60%) diff --git a/playground/theme/tailwind.config.ts b/playground/theme/tailwind.config.cjs similarity index 60% rename from playground/theme/tailwind.config.ts rename to playground/theme/tailwind.config.cjs index e698f67f..2fdfc700 100644 --- a/playground/theme/tailwind.config.ts +++ b/playground/theme/tailwind.config.cjs @@ -1,6 +1,6 @@ -import colors from 'tailwindcss/colors' +const colors = require('tailwindcss/colors') -export default { +module.exports = { theme: { extend: { colors: { diff --git a/src/module.ts b/src/module.ts index 3425f126..72a7f776 100644 --- a/src/module.ts +++ b/src/module.ts @@ -12,7 +12,7 @@ import { createResolver, resolvePath, addVitePlugin, - isNuxt3, findPath, requireModule + isNuxt3, findPath } from '@nuxt/kit' import type { Config } from 'tailwindcss' import resolveConfig from 'tailwindcss/resolveConfig.js' @@ -45,6 +45,7 @@ type Arrayable = T | T[] declare module '@nuxt/schema' { interface NuxtHooks { 'tailwindcss:config': (tailwindConfig: Partial) => void; + 'tailwindcss:loadConfig': (tailwindConfig: Partial, configPath: string, index: number, configPaths: string[]) => void; 'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType>) => void; } } @@ -86,44 +87,37 @@ export default defineNuxtModule({ */ const configPaths: string[] = [] - const contentPaths = [] + const contentPaths: string[] = [] - /** - * Push config paths into `configPaths` without extension. - * Allows next steps of processing to try both .js / .ts when resolving the config. - */ - const addConfigPath = async (path: Arrayable) => { - // filter in case an empty path is provided - const paths = (Array.isArray(path) ? path : [path]).filter(Boolean) - for (const path of paths) { - const resolvedPath = (await findPath(path, { extensions: ['.js', '.cjs', '.mjs', '.ts'] }, 'file')) - // only if the path is found - if (resolvedPath) { - configPaths.push(resolvedPath) - } - } - } + const resolveConfigPath = async (path: Arrayable) => ( + await Promise.all( + (Array.isArray(path) ? path : [path]) + .filter(Boolean) + .map((path) => findPath(path, { extensions: ['.js', '.cjs', '.mjs', '.ts'] })) + ) + ).filter((i): i is string => Boolean(i)) // Support `extends` directories if (nuxt.options._layers && nuxt.options._layers.length > 1) { // nuxt.options._layers is from rootDir to nested level // We need to reverse the order to give the deepest tailwind.config the lowest priority - const layers = nuxt.options._layers.slice().reverse() - for (const layer of layers) { - await addConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')) - contentPaths.push(...layerPaths(layer?.config?.srcDir || layer.cwd)) - } + const layers = nuxt.options._layers.slice().reverse(); + + (await Promise.all( + layers.map(async (layer) => ([ + await resolveConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')), + layerPaths(layer?.config?.srcDir || layer.cwd) + ]))) + ).forEach(l => configPaths.push(...l[0]) + contentPaths.push(...l[1])) } else { - await addConfigPath(moduleOptions.configPath) + await resolveConfigPath(moduleOptions.configPath).then(p => configPaths.push(...p)) contentPaths.push(...layerPaths(nuxt.options.srcDir)) } // Watch the Tailwind config file to restart the server if (nuxt.options.dev) { if (isNuxt2()) { - // @ts-ignore nuxt.options.watch = nuxt.options.watch || [] - // @ts-ignore configPaths.forEach(path => nuxt.options.watch.push(path)) } else if (Array.isArray(nuxt.options.watch)) { nuxt.options.watch.push(...configPaths.map(path => relative(nuxt.options.srcDir, path))) @@ -137,25 +131,28 @@ export default defineNuxtModule({ } // Default tailwind config - let tailwindConfig = configMerger(moduleOptions.config, { content: contentPaths }) - - // Recursively resolve each config and merge tailwind configs together. - for (const configPath of configPaths) { - let _tailwindConfig: Partial | undefined - try { - _tailwindConfig = requireModule(configPath, { clearCache: true }) - } catch (e) { - logger.warn(`Failed to load Tailwind config at: \`./${relative(nuxt.options.rootDir, configPath)}\``, e) - } - - // Transform purge option from Array to object with { content } - if (_tailwindConfig && Array.isArray(_tailwindConfig.purge) && !_tailwindConfig.content) { - _tailwindConfig.content = _tailwindConfig.purge - } - if (_tailwindConfig) { - tailwindConfig = configMerger(_tailwindConfig, tailwindConfig) - } - } + const tailwindConfig = configMerger( + moduleOptions.config, + { content: contentPaths }, + ...(await Promise.all( + configPaths.map(async (configPath, idx, paths) => { + let _tailwindConfig: Partial | undefined + try { + _tailwindConfig = await import(configPath).then(c => c.default || c) + } catch (e) { + logger.warn(`Failed to load Tailwind config at: \`./${relative(nuxt.options.rootDir, configPath)}\``, e) + } + + // Transform purge option from Array to object with { content } + if (_tailwindConfig && !_tailwindConfig.content) { + _tailwindConfig.content = _tailwindConfig.purge + } + + await nuxt.callHook('tailwindcss:loadConfig', _tailwindConfig || {}, configPath, idx, paths) + return _tailwindConfig || {} + })) + ) + ) // Allow extending tailwindcss config by other modules await nuxt.callHook('tailwindcss:config', tailwindConfig) @@ -187,7 +184,6 @@ export default defineNuxtModule({ resolvedCss = cssPath } else { logger.info('Using default Tailwind CSS file') - // @ts-ignore resolvedCss = 'tailwindcss/tailwind.css' } } else { From 8e8a8d7eaac58d85232cc49fefa8170cd2f39c08 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Mon, 15 May 2023 16:54:57 +0100 Subject: [PATCH 04/12] chore: progress --- src/module.ts | 89 ++++++++++++++++++-------------------------- src/utils.ts | 16 +++++++- test/basic.test.ts | 16 ++++---- test/configs.test.ts | 16 ++++---- 4 files changed, 68 insertions(+), 69 deletions(-) diff --git a/src/module.ts b/src/module.ts index 72a7f776..c5d9603e 100644 --- a/src/module.ts +++ b/src/module.ts @@ -12,7 +12,7 @@ import { createResolver, resolvePath, addVitePlugin, - isNuxt3, findPath + isNuxt3 } from '@nuxt/kit' import type { Config } from 'tailwindcss' import resolveConfig from 'tailwindcss/resolveConfig.js' @@ -21,7 +21,7 @@ import defaultTailwindConfig from 'tailwindcss/stubs/config.simple.js' import { eventHandler, sendRedirect, H3Event } from 'h3' import { name, version } from '../package.json' import vitePlugin from './hmr' -import { configMerger, createTemplates, InjectPosition, resolveInjectPosition } from './utils' +import { configMerger, createTemplates, InjectPosition, resolveConfigPath, resolveInjectPosition } from './utils' import { addTemplate } from '@nuxt/kit' const logger = useLogger('nuxt:tailwindcss') @@ -45,7 +45,7 @@ type Arrayable = T | T[] declare module '@nuxt/schema' { interface NuxtHooks { 'tailwindcss:config': (tailwindConfig: Partial) => void; - 'tailwindcss:loadConfig': (tailwindConfig: Partial, configPath: string, index: number, configPaths: string[]) => void; + 'tailwindcss:loadConfig': (tailwindConfig: Partial | undefined, configPath: string, index: number, configPaths: string[]) => void; 'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType>) => void; } } @@ -86,33 +86,18 @@ export default defineNuxtModule({ * Config file handling */ - const configPaths: string[] = [] - const contentPaths: string[] = [] - - const resolveConfigPath = async (path: Arrayable) => ( - await Promise.all( - (Array.isArray(path) ? path : [path]) - .filter(Boolean) - .map((path) => findPath(path, { extensions: ['.js', '.cjs', '.mjs', '.ts'] })) - ) - ).filter((i): i is string => Boolean(i)) - - // Support `extends` directories - if (nuxt.options._layers && nuxt.options._layers.length > 1) { - // nuxt.options._layers is from rootDir to nested level - // We need to reverse the order to give the deepest tailwind.config the lowest priority - const layers = nuxt.options._layers.slice().reverse(); - - (await Promise.all( - layers.map(async (layer) => ([ - await resolveConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')), - layerPaths(layer?.config?.srcDir || layer.cwd) - ]))) - ).forEach(l => configPaths.push(...l[0]) + contentPaths.push(...l[1])) - } else { - await resolveConfigPath(moduleOptions.configPath).then(p => configPaths.push(...p)) - contentPaths.push(...layerPaths(nuxt.options.srcDir)) - } + const [configPaths, contentPaths]: [Array, Array] = + (nuxt.options._layers && nuxt.options._layers.length > 1) + // Support `extends` directories + ? (await Promise.all( + // nuxt.options._layers is from rootDir to nested level + // We need to reverse the order to give the deepest tailwind.config the lowest priority + nuxt.options._layers.slice().reverse().map(async (layer) => ([ + await resolveConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')), + layerPaths(layer?.config?.srcDir || layer.cwd) + ]))) + ).reduce((prev, curr) => prev.map((p, i) => p.concat(curr[i]))) as any + : [await resolveConfigPath(moduleOptions.configPath), layerPaths(nuxt.options.srcDir)] // Watch the Tailwind config file to restart the server if (nuxt.options.dev) { @@ -130,29 +115,29 @@ export default defineNuxtModule({ } } - // Default tailwind config - const tailwindConfig = configMerger( - moduleOptions.config, - { content: contentPaths }, - ...(await Promise.all( - configPaths.map(async (configPath, idx, paths) => { - let _tailwindConfig: Partial | undefined - try { - _tailwindConfig = await import(configPath).then(c => c.default || c) - } catch (e) { - logger.warn(`Failed to load Tailwind config at: \`./${relative(nuxt.options.rootDir, configPath)}\``, e) - } - - // Transform purge option from Array to object with { content } - if (_tailwindConfig && !_tailwindConfig.content) { - _tailwindConfig.content = _tailwindConfig.purge - } - - await nuxt.callHook('tailwindcss:loadConfig', _tailwindConfig || {}, configPath, idx, paths) - return _tailwindConfig || {} - })) + const tailwindConfig = ( + await Promise.all( + configPaths.map(async (configPath, idx, paths) => { + let _tailwindConfig: Partial | undefined + try { + _tailwindConfig = await import(configPath).then(c => c.default || c) + } catch (e) { + logger.warn(`Failed to load Tailwind config at: \`./${relative(nuxt.options.rootDir, configPath)}\``, e) + } + + // Transform purge option from Array to object with { content } + if (_tailwindConfig && !_tailwindConfig.content) { + _tailwindConfig.content = _tailwindConfig.purge + } + + await nuxt.callHook('tailwindcss:loadConfig', _tailwindConfig, configPath, idx, paths) + return _tailwindConfig || {} + })) + ).reduce( + (prev, curr) => configMerger(curr, prev), + // internal default tailwind config + configMerger(moduleOptions.config, { content: contentPaths }) ) - ) // Allow extending tailwindcss config by other modules await nuxt.callHook('tailwindcss:config', tailwindConfig) diff --git a/src/utils.ts b/src/utils.ts index 55dba0da..7f38581b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ import { dirname, join } from 'pathe' -import { useNuxt, addTemplate } from '@nuxt/kit' +import { useNuxt, addTemplate, findPath } from '@nuxt/kit' import type { Config } from 'tailwindcss' import { createDefu } from 'defu' @@ -26,6 +26,20 @@ export const configMerger: ( } }) +/** + * Resolves all configPath values for an application + * + * @param path configPath for a layer + * @returns array of resolved paths + */ +export const resolveConfigPath = async (path: string | string[]) => ( + await Promise.all( + (Array.isArray(path) ? path : [path]) + .filter(Boolean) + .map((path) => findPath(path, { extensions: ['.js', '.cjs', '.mjs', '.ts'] })) + ) +).filter((i): i is string => Boolean(i)) + export type InjectPosition = 'first' | 'last' | number | { after: string }; diff --git a/test/basic.test.ts b/test/basic.test.ts index 3e7a9920..7ad25752 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -34,10 +34,10 @@ describe('tailwindcss module', async () => { // }) test('include custom tailwind.css file in project css', () => { - const nuxt = useTestContext().nuxt + const nuxt = useTestContext().nuxt! expect(nuxt.options.css).toHaveLength(1) - expect(nuxt.options.css[0]).toEqual(nuxt.options.tailwindcss.cssPath) + expect(nuxt.options.css[0]).toEqual(nuxt.options.tailwindcss.cssPath.replace(/\\/g /* windows protocol */, '/')) expect(spyStderr).toHaveBeenCalledTimes(0) expect(spyStdout).toHaveBeenCalledTimes(1) @@ -45,8 +45,8 @@ describe('tailwindcss module', async () => { }) test('default js config is merged in', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.'))! // set from default config tailwind.config.js expect(nuxt.vfs[vfsKey]).contains('"primary": "#f1e05a"') }) @@ -61,16 +61,16 @@ describe('tailwindcss module', async () => { // test('expose config', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config/theme/flexBasis.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config/theme/flexBasis.'))! // check default tailwind default animation exists expect(nuxt.vfs[vfsKey]).contains('"full": _full, "0.5": "0.125rem"') expect(nuxt.vfs[vfsKey]).contains('export { config as default') }) test('expose config variable', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config/theme/animation.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config/theme/animation.'))! expect(nuxt.vfs[vfsKey]).contains('const _pulse = "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"') }) }) diff --git a/test/configs.test.ts b/test/configs.test.ts index e7a81171..9ca906a5 100644 --- a/test/configs.test.ts +++ b/test/configs.test.ts @@ -33,22 +33,22 @@ describe('tailwindcss module configs', async () => { }) test('ts config file is loaded and merged', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.'))! // set from ts-tailwind.config.ts expect(nuxt.vfs[vfsKey]).contains('"typescriptBlue": "#007acc"') }) test('js config file is loaded and merged', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.'))! // set from ts-tailwind.config.ts expect(nuxt.vfs[vfsKey]).contains('"javascriptYellow": "#f1e05a"') }) test('content is overridden', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.'))! // set from override-tailwind.config.ts const contentFiles = destr(nuxt.vfs[vfsKey].replace(/^(module\.exports = )/, '')).content.files @@ -58,8 +58,8 @@ describe('tailwindcss module configs', async () => { }) test('content merges with objects', () => { - const nuxt = useTestContext().nuxt - const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.')) + const nuxt = useTestContext().nuxt! + const vfsKey = Object.keys(nuxt.vfs).find(k => k.includes('tailwind.config.'))! const { content } = destr(nuxt.vfs[vfsKey].replace(/^(module\.exports = )/, '')) expect(content.relative).toBeTruthy() From b08c45a80eba9e0b27224ab4cfeb176591ed8583 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Mon, 15 May 2023 17:30:29 +0100 Subject: [PATCH 05/12] chore: some cleanup --- package.json | 7 ++- src/module.ts | 94 ++++++++++++++----------------------- src/types.ts | 18 +++++++ src/utils.ts | 30 +++++++++--- src/{hmr.ts => vite-hmr.ts} | 4 +- 5 files changed, 83 insertions(+), 70 deletions(-) create mode 100644 src/types.ts rename src/{hmr.ts => vite-hmr.ts} (91%) diff --git a/package.json b/package.json index 0e6fe2ca..a7ec173e 100755 --- a/package.json +++ b/package.json @@ -4,6 +4,11 @@ "description": "TailwindCSS module for Nuxt", "repository": "nuxt-modules/tailwindcss", "license": "MIT", + "configKey": "tailwindcss", + "compatibility": { + "nuxt": "^2.9.0 || ^3.0.0-rc.1", + "bridge": true + }, "exports": { ".": { "require": "./dist/module.cjs", @@ -63,4 +68,4 @@ "nuxt": "^3.4.3", "vitest": "^0.31.0" } -} \ No newline at end of file +} diff --git a/src/module.ts b/src/module.ts index c5d9603e..5f2a2de8 100644 --- a/src/module.ts +++ b/src/module.ts @@ -2,6 +2,7 @@ import { existsSync } from 'fs' import { join, relative } from 'pathe' import { watch } from 'chokidar' import { underline, yellow } from 'colorette' + import { defineNuxtModule, installModule, @@ -12,65 +13,38 @@ import { createResolver, resolvePath, addVitePlugin, - isNuxt3 + isNuxt3, + addTemplate } from '@nuxt/kit' -import type { Config } from 'tailwindcss' -import resolveConfig from 'tailwindcss/resolveConfig.js' + // @ts-expect-error import defaultTailwindConfig from 'tailwindcss/stubs/config.simple.js' +import resolveConfig from 'tailwindcss/resolveConfig.js' import { eventHandler, sendRedirect, H3Event } from 'h3' -import { name, version } from '../package.json' -import vitePlugin from './hmr' -import { configMerger, createTemplates, InjectPosition, resolveConfigPath, resolveInjectPosition } from './utils' -import { addTemplate } from '@nuxt/kit' -const logger = useLogger('nuxt:tailwindcss') - -const layerPaths = (srcDir: string) => ([ - `${srcDir}/components/**/*.{vue,js,ts}`, - `${srcDir}/layouts/**/*.vue`, - `${srcDir}/pages/**/*.vue`, - `${srcDir}/composables/**/*.{js,ts}`, - `${srcDir}/plugins/**/*.{js,ts}`, - `${srcDir}/utils/**/*.{js,ts}`, - `${srcDir}/App.{js,ts,vue}`, - `${srcDir}/app.{js,ts,vue}`, - `${srcDir}/Error.{js,ts,vue}`, - `${srcDir}/error.{js,ts,vue}`, - `${srcDir}/app.config.{js,ts}` -]) - -type Arrayable = T | T[] +import { + configMerger, + createTemplates, + resolveConfigPath, + resolveContentPaths, + resolveInjectPosition +} from './utils' +import vitePlugin from './vite-hmr' +import { name, version, configKey, compatibility } from '../package.json' + +import type { ModuleOptions, TWConfig } from './types' +export { ModuleOptions } from './types' declare module '@nuxt/schema' { interface NuxtHooks { - 'tailwindcss:config': (tailwindConfig: Partial) => void; - 'tailwindcss:loadConfig': (tailwindConfig: Partial | undefined, configPath: string, index: number, configPaths: string[]) => void; - 'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType>) => void; + 'tailwindcss:config': (tailwindConfig: Partial) => void; + 'tailwindcss:loadConfig': (tailwindConfig: Partial | undefined, configPath: string, index: number, configPaths: string[]) => void; + 'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType>) => void; } } -interface ExtendTailwindConfig { - content: Config['content'] | ((contentDefaults: string[]) => Config['content']); -} - -export interface ModuleOptions { - configPath: Arrayable; - cssPath: string | false; - config: Omit & ExtendTailwindConfig; - viewer: boolean; - exposeConfig: boolean; - exposeLevel: number; - injectPosition: InjectPosition; - disableHmrHotfix: boolean; -} - export default defineNuxtModule({ - meta: { - name, - version, - configKey: 'tailwindcss' - }, + meta: { name, version, configKey, compatibility }, defaults: nuxt => ({ configPath: 'tailwind.config', cssPath: join(nuxt.options.dir.assets, 'css/tailwind.css'), @@ -82,9 +56,8 @@ export default defineNuxtModule({ disableHmrHotfix: false }), async setup (moduleOptions, nuxt) { - /** - * Config file handling - */ + const logger = useLogger('nuxt:tailwindcss') + const resolver = createResolver(import.meta.url) const [configPaths, contentPaths]: [Array, Array] = (nuxt.options._layers && nuxt.options._layers.length > 1) @@ -94,10 +67,10 @@ export default defineNuxtModule({ // We need to reverse the order to give the deepest tailwind.config the lowest priority nuxt.options._layers.slice().reverse().map(async (layer) => ([ await resolveConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')), - layerPaths(layer?.config?.srcDir || layer.cwd) + resolveContentPaths(layer?.config?.srcDir || layer.cwd) ]))) ).reduce((prev, curr) => prev.map((p, i) => p.concat(curr[i]))) as any - : [await resolveConfigPath(moduleOptions.configPath), layerPaths(nuxt.options.srcDir)] + : [await resolveConfigPath(moduleOptions.configPath), resolveContentPaths(nuxt.options.srcDir)] // Watch the Tailwind config file to restart the server if (nuxt.options.dev) { @@ -118,7 +91,7 @@ export default defineNuxtModule({ const tailwindConfig = ( await Promise.all( configPaths.map(async (configPath, idx, paths) => { - let _tailwindConfig: Partial | undefined + let _tailwindConfig: Partial | undefined try { _tailwindConfig = await import(configPath).then(c => c.default || c) } catch (e) { @@ -142,7 +115,7 @@ export default defineNuxtModule({ // Allow extending tailwindcss config by other modules await nuxt.callHook('tailwindcss:config', tailwindConfig) - const resolvedConfig = resolveConfig(tailwindConfig as Config) + const resolvedConfig = resolveConfig(tailwindConfig as TWConfig) await nuxt.callHook('tailwindcss:resolvedConfig', resolvedConfig) // Expose resolved tailwind config as an alias @@ -173,12 +146,13 @@ export default defineNuxtModule({ } } else { logger.info('No Tailwind CSS file found. Skipping...') - const emptyCSSPath = addTemplate({ - filename: 'tailwind-empty.css', - write: true, - getContents: () => '' - }).dst - resolvedCss = createResolver(import.meta.url).resolve(emptyCSSPath) + resolvedCss = resolver.resolve( + addTemplate({ + filename: 'tailwind-empty.css', + write: true, + getContents: () => '' + }).dst + ) } nuxt.options.css = nuxt.options.css ?? [] diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..5236f62b --- /dev/null +++ b/src/types.ts @@ -0,0 +1,18 @@ +export type TWConfig = import('tailwindcss').Config +export type Arrayable = T | Array +export type InjectPosition = 'first' | 'last' | number | { after: string }; + +interface ExtendTailwindConfig { + content: TWConfig['content'] | ((contentDefaults: Array) => TWConfig['content']); +} + +export interface ModuleOptions { + configPath: Arrayable; + cssPath: string | false; + config: Omit & ExtendTailwindConfig; + viewer: boolean; + exposeConfig: boolean; + exposeLevel: number; + injectPosition: InjectPosition; + disableHmrHotfix: boolean; +} diff --git a/src/utils.ts b/src/utils.ts index 7f38581b..c11a6380 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,14 +1,14 @@ import { dirname, join } from 'pathe' import { useNuxt, addTemplate, findPath } from '@nuxt/kit' -import type { Config } from 'tailwindcss' import { createDefu } from 'defu' +import type { Arrayable, InjectPosition, TWConfig } from './types' const NON_ALPHANUMERIC_RE = /^[0-9a-z]+$/i const isJSObject = (value: any) => typeof value === 'object' && !Array.isArray(value) export const configMerger: ( - ...p: Array | Record> -) => Partial = createDefu((obj, key, value) => { + ...p: Array | Record> +) => Partial = createDefu((obj, key, value) => { if (key === 'content') { if (isJSObject(obj[key]) && Array.isArray(value)) { obj[key]['files'] = [...(obj[key]['files'] || []), ...value] @@ -32,7 +32,7 @@ export const configMerger: ( * @param path configPath for a layer * @returns array of resolved paths */ -export const resolveConfigPath = async (path: string | string[]) => ( +export const resolveConfigPath = async (path: Arrayable) => ( await Promise.all( (Array.isArray(path) ? path : [path]) .filter(Boolean) @@ -40,8 +40,24 @@ export const resolveConfigPath = async (path: string | string[]) => ( ) ).filter((i): i is string => Boolean(i)) - -export type InjectPosition = 'first' | 'last' | number | { after: string }; +/** + * + * @param srcDir + * @returns array of resolved content globs + */ +export const resolveContentPaths = (srcDir: string) => ([ + `${srcDir}/components/**/*.{vue,js,ts}`, + `${srcDir}/layouts/**/*.vue`, + `${srcDir}/pages/**/*.vue`, + `${srcDir}/composables/**/*.{js,ts}`, + `${srcDir}/plugins/**/*.{js,ts}`, + `${srcDir}/utils/**/*.{js,ts}`, + `${srcDir}/App.{js,ts,vue}`, + `${srcDir}/app.{js,ts,vue}`, + `${srcDir}/Error.{js,ts,vue}`, + `${srcDir}/error.{js,ts,vue}`, + `${srcDir}/app.config.{js,ts}` +]) /** * Resolve human-readable inject position specification into absolute index in the array @@ -83,7 +99,7 @@ export function resolveInjectPosition (css: string[], position: InjectPosition) * @param maxLevel maximum level of depth * @param nuxt nuxt app */ -export function createTemplates (resolvedConfig: Partial, maxLevel: number, nuxt = useNuxt()) { +export function createTemplates (resolvedConfig: Partial, maxLevel: number, nuxt = useNuxt()) { const dtsContent: string[] = [] const populateMap = (obj: any, path: string[] = [], level = 1) => { diff --git a/src/hmr.ts b/src/vite-hmr.ts similarity index 91% rename from src/hmr.ts rename to src/vite-hmr.ts index e83ea3ae..936d3d87 100644 --- a/src/hmr.ts +++ b/src/vite-hmr.ts @@ -1,9 +1,9 @@ import { isAbsolute, resolve } from 'pathe' import type { Plugin as VitePlugin } from 'vite' -import type { Config } from 'tailwindcss' +import type { TWConfig } from './types' import micromatch from 'micromatch' -export default function (tailwindConfig: Partial = {}, rootDir: string, cssPath: string): VitePlugin { +export default function (tailwindConfig: Partial = {}, rootDir: string, cssPath: string): VitePlugin { const resolvedContent = ((Array.isArray(tailwindConfig.content) ? tailwindConfig.content : tailwindConfig.content?.files || []).filter(f => typeof f === 'string') as Array).map(f => !isAbsolute(f) ? resolve(rootDir, f) : f) return { From 2fb6e7679f4c4aead9f63cb5e870cc2ac6c6401b Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Mon, 15 May 2023 17:44:34 +0100 Subject: [PATCH 06/12] chore: splitting utils --- src/module.ts | 47 ++++++++------- src/resolving.ts | 68 ++++++++++++++++++++++ src/templates.ts | 75 ++++++++++++++++++++++++ src/utils.ts | 145 +---------------------------------------------- 4 files changed, 171 insertions(+), 164 deletions(-) create mode 100644 src/resolving.ts create mode 100644 src/templates.ts diff --git a/src/module.ts b/src/module.ts index 5f2a2de8..b90630cc 100644 --- a/src/module.ts +++ b/src/module.ts @@ -14,7 +14,8 @@ import { resolvePath, addVitePlugin, isNuxt3, - addTemplate + addTemplate, + useNuxt } from '@nuxt/kit' // @ts-expect-error @@ -22,39 +23,32 @@ import defaultTailwindConfig from 'tailwindcss/stubs/config.simple.js' import resolveConfig from 'tailwindcss/resolveConfig.js' import { eventHandler, sendRedirect, H3Event } from 'h3' +import { configMerger } from './utils' import { - configMerger, - createTemplates, resolveConfigPath, resolveContentPaths, resolveInjectPosition -} from './utils' +} from './resolving' +import createTemplates from './templates' import vitePlugin from './vite-hmr' import { name, version, configKey, compatibility } from '../package.json' import type { ModuleOptions, TWConfig } from './types' export { ModuleOptions } from './types' -declare module '@nuxt/schema' { - interface NuxtHooks { - 'tailwindcss:config': (tailwindConfig: Partial) => void; - 'tailwindcss:loadConfig': (tailwindConfig: Partial | undefined, configPath: string, index: number, configPaths: string[]) => void; - 'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType>) => void; - } -} +const defaults = (nuxt = useNuxt()): ModuleOptions => ({ + configPath: 'tailwind.config', + cssPath: join(nuxt.options.dir.assets, 'css/tailwind.css'), + config: defaultTailwindConfig, + viewer: true, + exposeConfig: false, + exposeLevel: 2, + injectPosition: 'first', + disableHmrHotfix: false +}) export default defineNuxtModule({ - meta: { name, version, configKey, compatibility }, - defaults: nuxt => ({ - configPath: 'tailwind.config', - cssPath: join(nuxt.options.dir.assets, 'css/tailwind.css'), - config: defaultTailwindConfig, - viewer: true, - exposeConfig: false, - exposeLevel: 2, - injectPosition: 'first', - disableHmrHotfix: false - }), + meta: { name, version, configKey, compatibility }, defaults, async setup (moduleOptions, nuxt) { const logger = useLogger('nuxt:tailwindcss') const resolver = createResolver(import.meta.url) @@ -72,6 +66,7 @@ export default defineNuxtModule({ ).reduce((prev, curr) => prev.map((p, i) => p.concat(curr[i]))) as any : [await resolveConfigPath(moduleOptions.configPath), resolveContentPaths(nuxt.options.srcDir)] + // Watch the Tailwind config file to restart the server if (nuxt.options.dev) { if (isNuxt2()) { @@ -246,3 +241,11 @@ export default defineNuxtModule({ } }) + +declare module '@nuxt/schema' { + interface NuxtHooks { + 'tailwindcss:config': (tailwindConfig: Partial) => void; + 'tailwindcss:loadConfig': (tailwindConfig: Partial | undefined, configPath: string, index: number, configPaths: string[]) => void; + 'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType>) => void; + } +} diff --git a/src/resolving.ts b/src/resolving.ts new file mode 100644 index 00000000..ad39e3c1 --- /dev/null +++ b/src/resolving.ts @@ -0,0 +1,68 @@ +import { findPath } from "@nuxt/kit" +import type { Arrayable, InjectPosition } from "./types" + +/** + * Resolves all configPath values for an application + * + * @param path configPath for a layer + * @returns array of resolved paths + */ +export const resolveConfigPath = async (path: Arrayable) => ( + await Promise.all( + (Array.isArray(path) ? path : [path]) + .filter(Boolean) + .map((path) => findPath(path, { extensions: ['.js', '.cjs', '.mjs', '.ts'] })) + ) +).filter((i): i is string => Boolean(i)) + +/** + * + * @param srcDir + * @returns array of resolved content globs + */ +export const resolveContentPaths = (srcDir: string) => ([ + `${srcDir}/components/**/*.{vue,js,ts}`, + `${srcDir}/layouts/**/*.vue`, + `${srcDir}/pages/**/*.vue`, + `${srcDir}/composables/**/*.{js,ts}`, + `${srcDir}/plugins/**/*.{js,ts}`, + `${srcDir}/utils/**/*.{js,ts}`, + `${srcDir}/App.{js,ts,vue}`, + `${srcDir}/app.{js,ts,vue}`, + `${srcDir}/Error.{js,ts,vue}`, + `${srcDir}/error.{js,ts,vue}`, + `${srcDir}/app.config.{js,ts}` +]) + +/** + * Resolve human-readable inject position specification into absolute index in the array + * + * @param css nuxt css config + * @param position position to inject + * + * @returns index in the css array + */ +export function resolveInjectPosition (css: string[], position: InjectPosition) { + if (typeof (position) === 'number') { + return ~~Math.min(position, css.length + 1) + } + + if (typeof (position) === 'string') { + switch (position) { + case 'first': return 0 + case 'last': return css.length + default: throw new Error('invalid literal: ' + position) + } + } + + if (position.after !== undefined) { + const index = css.indexOf(position.after) + if (index === -1) { + throw new Error('`after` position specifies a file which does not exists on CSS stack: ' + position.after) + } + + return index + 1 + } + + throw new Error('invalid position: ' + JSON.stringify(position)) +} diff --git a/src/templates.ts b/src/templates.ts new file mode 100644 index 00000000..bc6524e6 --- /dev/null +++ b/src/templates.ts @@ -0,0 +1,75 @@ +import { dirname, join } from 'pathe' +import { useNuxt, addTemplate } from '@nuxt/kit' +import { isJSObject, NON_ALPHANUMERIC_RE } from './utils' +import type { TWConfig } from './types' + +/** + * Creates MJS exports for properties of the config + * + * @param resolvedConfig tailwind config + * @param maxLevel maximum level of depth + * @param nuxt nuxt app + */ +export default function createTemplates (resolvedConfig: Partial, maxLevel: number, nuxt = useNuxt()) { + const dtsContent: Array = [] + + const populateMap = (obj: any, path: string[] = [], level = 1) => { + Object.entries(obj).forEach(([key, value = {} as any]) => { + const subpath = path.concat(key).join('/') + + if ( + level >= maxLevel || // if recursive call is more than desired + !isJSObject(value) || // if its not an object, no more recursion required + Object.keys(value).find(k => !k.match(NON_ALPHANUMERIC_RE)) // object has non-alphanumeric property (unsafe var name) + ) { + if (isJSObject(value)) { + const [validKeys, invalidKeys]: [string[], string[]] = [[], []] + Object.keys(value).forEach(i => (NON_ALPHANUMERIC_RE.test(i) ? validKeys : invalidKeys).push(i)) + + addTemplate({ + filename: `tailwind.config/${subpath}.mjs`, + getContents: () => `${validKeys.map(i => `const _${i} = ${JSON.stringify(value[i])}`).join('\n')}\nconst config = { ${validKeys.map(i => `"${i}": _${i}, `).join('')}${invalidKeys.map(i => `"${i}": ${JSON.stringify(value[i])}, `).join('')} }\nexport { config as default${validKeys.length > 0 ? ', _' : ''}${validKeys.join(', _')} }` + }) + dtsContent.push(`declare module "#tailwind-config/${subpath}" { ${validKeys.map(i => `export const _${i}: ${JSON.stringify(value[i])};`).join('')} const defaultExport: { ${validKeys.map(i => `"${i}": typeof _${i}, `).join('')}${invalidKeys.map(i => `"${i}": ${JSON.stringify(value[i])}, `).join('')} }; export default defaultExport; }`) + } else { + addTemplate({ + filename: `tailwind.config/${subpath}.mjs`, + getContents: () => `export default ${JSON.stringify(value, null, 2)}` + }) + dtsContent.push(`declare module "#tailwind-config/${subpath}" { const defaultExport: ${JSON.stringify(value)}; export default defaultExport; }`) + } + } else { + // recurse through nested objects + populateMap(value, path.concat(key), level + 1) + + const values = Object.keys(value) + addTemplate({ + filename: `tailwind.config/${subpath}.mjs`, + getContents: () => `${values.map(v => `import _${v} from "./${key}/${v}.mjs"`).join('\n')}\nconst config = { ${values.map(k => `"${k}": _${k}`).join(', ')} }\nexport { config as default${values.length > 0 ? ', _' : ''}${values.join(', _')} }` + }) + dtsContent.push(`declare module "#tailwind-config/${subpath}" {${Object.keys(value).map(v => ` export const _${v}: typeof import("#tailwind-config/${join(`${key}/${subpath}`, `../${v}`)}")["default"];`).join('')} const defaultExport: { ${values.map(k => `"${k}": typeof _${k}`).join(', ')} }; export default defaultExport; }`) + } + }) + } + + populateMap(resolvedConfig) + const configOptions = Object.keys(resolvedConfig) + + const template = addTemplate({ + filename: 'tailwind.config/index.mjs', + getContents: () => `${configOptions.map(v => `import ${v} from "#build/tailwind.config/${v}.mjs"`).join('\n')}\nconst config = { ${configOptions.join(', ')} }\nexport { config as default, ${configOptions.join(', ')} }`, + write: true + }) + + dtsContent.push(`declare module "#tailwind-config" {${configOptions.map(v => ` export const ${v}: typeof import("${join('#tailwind-config', v)}")["default"];`).join('')} const defaultExport: { ${configOptions.map(v => `"${v}": typeof ${v}`)} }; export default defaultExport; }`) + const typesTemplate = addTemplate({ + filename: 'tailwind.config.d.ts', + getContents: () => dtsContent.join('\n'), + write: true + }) + + nuxt.options.alias['#tailwind-config'] = dirname(template.dst) + nuxt.hook('prepare:types', (opts) => { + opts.references.push({ path: typesTemplate.dst }) + }) +} diff --git a/src/utils.ts b/src/utils.ts index c11a6380..789467bc 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,10 +1,8 @@ -import { dirname, join } from 'pathe' -import { useNuxt, addTemplate, findPath } from '@nuxt/kit' import { createDefu } from 'defu' -import type { Arrayable, InjectPosition, TWConfig } from './types' +import type { TWConfig } from './types' -const NON_ALPHANUMERIC_RE = /^[0-9a-z]+$/i -const isJSObject = (value: any) => typeof value === 'object' && !Array.isArray(value) +export const NON_ALPHANUMERIC_RE = /^[0-9a-z]+$/i +export const isJSObject = (value: any) => typeof value === 'object' && !Array.isArray(value) export const configMerger: ( ...p: Array | Record> @@ -25,140 +23,3 @@ export const configMerger: ( return true } }) - -/** - * Resolves all configPath values for an application - * - * @param path configPath for a layer - * @returns array of resolved paths - */ -export const resolveConfigPath = async (path: Arrayable) => ( - await Promise.all( - (Array.isArray(path) ? path : [path]) - .filter(Boolean) - .map((path) => findPath(path, { extensions: ['.js', '.cjs', '.mjs', '.ts'] })) - ) -).filter((i): i is string => Boolean(i)) - -/** - * - * @param srcDir - * @returns array of resolved content globs - */ -export const resolveContentPaths = (srcDir: string) => ([ - `${srcDir}/components/**/*.{vue,js,ts}`, - `${srcDir}/layouts/**/*.vue`, - `${srcDir}/pages/**/*.vue`, - `${srcDir}/composables/**/*.{js,ts}`, - `${srcDir}/plugins/**/*.{js,ts}`, - `${srcDir}/utils/**/*.{js,ts}`, - `${srcDir}/App.{js,ts,vue}`, - `${srcDir}/app.{js,ts,vue}`, - `${srcDir}/Error.{js,ts,vue}`, - `${srcDir}/error.{js,ts,vue}`, - `${srcDir}/app.config.{js,ts}` -]) - -/** - * Resolve human-readable inject position specification into absolute index in the array - * - * @param css nuxt css config - * @param position position to inject - * - * @returns index in the css array - */ -export function resolveInjectPosition (css: string[], position: InjectPosition) { - if (typeof (position) === 'number') { - return ~~Math.min(position, css.length + 1) - } - - if (typeof (position) === 'string') { - switch (position) { - case 'first': return 0 - case 'last': return css.length - default: throw new Error('invalid literal: ' + position) - } - } - - if (position.after !== undefined) { - const index = css.indexOf(position.after) - if (index === -1) { - throw new Error('`after` position specifies a file which does not exists on CSS stack: ' + position.after) - } - - return index + 1 - } - - throw new Error('invalid position: ' + JSON.stringify(position)) -} - -/** - * Creates MJS exports for properties of the config - * - * @param resolvedConfig tailwind config - * @param maxLevel maximum level of depth - * @param nuxt nuxt app - */ -export function createTemplates (resolvedConfig: Partial, maxLevel: number, nuxt = useNuxt()) { - const dtsContent: string[] = [] - - const populateMap = (obj: any, path: string[] = [], level = 1) => { - Object.entries(obj).forEach(([key, value = {} as any]) => { - const subpath = path.concat(key).join('/') - - if ( - level >= maxLevel || // if recursive call is more than desired - !isJSObject(value) || // if its not an object, no more recursion required - Object.keys(value).find(k => !k.match(NON_ALPHANUMERIC_RE)) // object has non-alphanumeric property (unsafe var name) - ) { - if (isJSObject(value)) { - const [validKeys, invalidKeys]: [string[], string[]] = [[], []] - Object.keys(value).forEach(i => (NON_ALPHANUMERIC_RE.test(i) ? validKeys : invalidKeys).push(i)) - - addTemplate({ - filename: `tailwind.config/${subpath}.mjs`, - getContents: () => `${validKeys.map(i => `const _${i} = ${JSON.stringify(value[i])}`).join('\n')}\nconst config = { ${validKeys.map(i => `"${i}": _${i}, `).join('')}${invalidKeys.map(i => `"${i}": ${JSON.stringify(value[i])}, `).join('')} }\nexport { config as default${validKeys.length > 0 ? ', _' : ''}${validKeys.join(', _')} }` - }) - dtsContent.push(`declare module "#tailwind-config/${subpath}" { ${validKeys.map(i => `export const _${i}: ${JSON.stringify(value[i])};`).join('')} const defaultExport: { ${validKeys.map(i => `"${i}": typeof _${i}, `).join('')}${invalidKeys.map(i => `"${i}": ${JSON.stringify(value[i])}, `).join('')} }; export default defaultExport; }`) - } else { - addTemplate({ - filename: `tailwind.config/${subpath}.mjs`, - getContents: () => `export default ${JSON.stringify(value, null, 2)}` - }) - dtsContent.push(`declare module "#tailwind-config/${subpath}" { const defaultExport: ${JSON.stringify(value)}; export default defaultExport; }`) - } - } else { - // recurse through nested objects - populateMap(value, path.concat(key), level + 1) - - const values = Object.keys(value) - addTemplate({ - filename: `tailwind.config/${subpath}.mjs`, - getContents: () => `${values.map(v => `import _${v} from "./${key}/${v}.mjs"`).join('\n')}\nconst config = { ${values.map(k => `"${k}": _${k}`).join(', ')} }\nexport { config as default${values.length > 0 ? ', _' : ''}${values.join(', _')} }` - }) - dtsContent.push(`declare module "#tailwind-config/${subpath}" {${Object.keys(value).map(v => ` export const _${v}: typeof import("#tailwind-config/${join(`${key}/${subpath}`, `../${v}`)}")["default"];`).join('')} const defaultExport: { ${values.map(k => `"${k}": typeof _${k}`).join(', ')} }; export default defaultExport; }`) - } - }) - } - - populateMap(resolvedConfig) - const configOptions = Object.keys(resolvedConfig) - - const template = addTemplate({ - filename: 'tailwind.config/index.mjs', - getContents: () => `${configOptions.map(v => `import ${v} from "#build/tailwind.config/${v}.mjs"`).join('\n')}\nconst config = { ${configOptions.join(', ')} }\nexport { config as default, ${configOptions.join(', ')} }`, - write: true - }) - - dtsContent.push(`declare module "#tailwind-config" {${configOptions.map(v => ` export const ${v}: typeof import("${join('#tailwind-config', v)}")["default"];`).join('')} const defaultExport: { ${configOptions.map(v => `"${v}": typeof ${v}`)} }; export default defaultExport; }`) - const typesTemplate = addTemplate({ - filename: 'tailwind.config.d.ts', - getContents: () => dtsContent.join('\n'), - write: true - }) - - nuxt.options.alias['#tailwind-config'] = dirname(template.dst) - nuxt.hook('prepare:types', (opts) => { - opts.references.push({ path: typesTemplate.dst }) - }) -} From aa3d808ec0a303a5d100bb3f55d597b4fe719d52 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Mon, 15 May 2023 17:58:55 +0100 Subject: [PATCH 07/12] chore: move out viewer --- src/module.ts | 30 +++--------------------------- src/viewer.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 27 deletions(-) create mode 100644 src/viewer.ts diff --git a/src/module.ts b/src/module.ts index b90630cc..d37299b7 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,19 +1,16 @@ import { existsSync } from 'fs' import { join, relative } from 'pathe' import { watch } from 'chokidar' -import { underline, yellow } from 'colorette' import { defineNuxtModule, installModule, - addDevServerHandler, isNuxt2, useLogger, getNuxtVersion, createResolver, resolvePath, addVitePlugin, - isNuxt3, addTemplate, useNuxt } from '@nuxt/kit' @@ -21,7 +18,6 @@ import { // @ts-expect-error import defaultTailwindConfig from 'tailwindcss/stubs/config.simple.js' import resolveConfig from 'tailwindcss/resolveConfig.js' -import { eventHandler, sendRedirect, H3Event } from 'h3' import { configMerger } from './utils' import { @@ -31,6 +27,7 @@ import { } from './resolving' import createTemplates from './templates' import vitePlugin from './vite-hmr' +import setupViewer from './viewer' import { name, version, configKey, compatibility } from '../package.json' import type { ModuleOptions, TWConfig } from './types' @@ -183,8 +180,7 @@ export default defineNuxtModule({ /* * install postcss8 module on nuxt < 2.16 */ - const nuxtVersion = getNuxtVersion(nuxt).split('.') - if (parseInt(nuxtVersion[0], 10) === 2 && parseInt(nuxtVersion[1], 10) < 16) { + if (parseFloat(getNuxtVersion()) < 2.16) { await installModule('@nuxt/postcss8') } @@ -204,28 +200,8 @@ export default defineNuxtModule({ // Add _tailwind config viewer endpoint // TODO: Fix `addServerHandler` on Nuxt 2 w/o Bridge if (nuxt.options.dev && moduleOptions.viewer) { - const { withTrailingSlash, withoutTrailingSlash, joinURL } = await import('ufo') - const route = joinURL(nuxt.options.app?.baseURL, '/_tailwind') - // @ts-ignore - const createServer = await import('tailwind-config-viewer/server/index.js').then(r => r.default || r) as any - const routerPrefix = isNuxt3() ? route : undefined - const _viewerDevMiddleware = createServer({ tailwindConfigProvider: () => tailwindConfig, routerPrefix }).asMiddleware() - const viewerDevMiddleware = eventHandler((event) => { - if (event.req.url === withoutTrailingSlash(route)) { - return sendRedirect(event, withTrailingSlash(event.req.url), 301) - } - _viewerDevMiddleware(event.req, event.res) - }) - if (isNuxt3()) { addDevServerHandler({ route, handler: viewerDevMiddleware }) } - // @ts-ignore - if (isNuxt2()) { nuxt.options.serverMiddleware.push({ route, handler: (req, res) => viewerDevMiddleware(new H3Event(req, res)) }) } - nuxt.hook('listen', (_, listener) => { - const viewerUrl = `${withoutTrailingSlash(listener.url)}${route}` - logger.info(`Tailwind Viewer: ${underline(yellow(withTrailingSlash(viewerUrl)))}`) - }) - } + setupViewer(tailwindConfig, nuxt) - if (nuxt.options.dev && moduleOptions.viewer) { nuxt.hook('devtools:customTabs', (tabs) => { tabs.push({ title: 'TailwindCSS', diff --git a/src/viewer.ts b/src/viewer.ts new file mode 100644 index 00000000..cf360ef2 --- /dev/null +++ b/src/viewer.ts @@ -0,0 +1,27 @@ +import { underline, yellow } from 'colorette' +import { eventHandler, sendRedirect } from 'h3' +import { addDevServerHandler, isNuxt2, isNuxt3, useLogger, useNuxt } from '@nuxt/kit' +import { withTrailingSlash, withoutTrailingSlash, joinURL } from 'ufo' +import type { TWConfig } from './types' + +export default async function (twConfig: Partial, nuxt = useNuxt()) { + // const { withTrailingSlash, withoutTrailingSlash, joinURL } = await import('ufo') + const route = joinURL(nuxt.options.app?.baseURL, '/_tailwind') + // @ts-ignore + const createServer = await import('tailwind-config-viewer/server/index.js').then(r => r.default || r) as any + const routerPrefix = isNuxt3() ? route : undefined + const _viewerDevMiddleware = createServer({ tailwindConfigProvider: () => twConfig, routerPrefix }).asMiddleware() + const viewerDevMiddleware = eventHandler((event) => { + if (event.req.url === withoutTrailingSlash(route)) { + return sendRedirect(event, withTrailingSlash(event.req.url), 301) + } + _viewerDevMiddleware(event.req, event.res) + }) + if (isNuxt3()) { addDevServerHandler({ route, handler: viewerDevMiddleware }) } + // @ts-ignore + if (isNuxt2()) { nuxt.options.serverMiddleware.push({ route, handler: (req, res) => viewerDevMiddleware(new H3Event(req, res)) }) } + nuxt.hook('listen', (_, listener) => { + const viewerUrl = `${withoutTrailingSlash(listener.url)}${route}` + useLogger('nuxt:tailwindcss').info(`Tailwind Viewer: ${underline(yellow(withTrailingSlash(viewerUrl)))}`) + }) +} From d8af758269af9e4573f6145f8023126911d27141 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Mon, 15 May 2023 18:09:26 +0100 Subject: [PATCH 08/12] chore: dev block --- src/module.ts | 118 ++++++++++++++++++++++---------------------------- 1 file changed, 52 insertions(+), 66 deletions(-) diff --git a/src/module.ts b/src/module.ts index d37299b7..536f435f 100644 --- a/src/module.ts +++ b/src/module.ts @@ -63,23 +63,6 @@ export default defineNuxtModule({ ).reduce((prev, curr) => prev.map((p, i) => p.concat(curr[i]))) as any : [await resolveConfigPath(moduleOptions.configPath), resolveContentPaths(nuxt.options.srcDir)] - - // Watch the Tailwind config file to restart the server - if (nuxt.options.dev) { - if (isNuxt2()) { - nuxt.options.watch = nuxt.options.watch || [] - configPaths.forEach(path => nuxt.options.watch.push(path)) - } else if (Array.isArray(nuxt.options.watch)) { - nuxt.options.watch.push(...configPaths.map(path => relative(nuxt.options.srcDir, path))) - } else { - const watcher = watch(configPaths, { depth: 0 }).on('change', (path) => { - logger.info(`Tailwind config changed: ${path}`) - logger.warn('Please restart the Nuxt server to apply changes or upgrade to latest Nuxt for automatic restart.') - }) - nuxt.hook('close', () => watcher.close()) - } - } - const tailwindConfig = ( await Promise.all( configPaths.map(async (configPath, idx, paths) => { @@ -126,28 +109,24 @@ export default defineNuxtModule({ const cssPath = typeof moduleOptions.cssPath === 'string' ? await resolvePath(moduleOptions.cssPath, { extensions: ['.css', '.sass', '.scss', '.less', '.styl'] }) : false // Include CSS file in project css - let resolvedCss: string - - if (typeof cssPath === 'string') { - if (existsSync(cssPath)) { - logger.info(`Using Tailwind CSS from ~/${relative(nuxt.options.srcDir, cssPath)}`) - resolvedCss = cssPath - } else { - logger.info('Using default Tailwind CSS file') - resolvedCss = 'tailwindcss/tailwind.css' - } - } else { - logger.info('No Tailwind CSS file found. Skipping...') - resolvedCss = resolver.resolve( - addTemplate({ - filename: 'tailwind-empty.css', - write: true, - getContents: () => '' - }).dst - ) - } + const [resolvedCss, loggerInfo] = + typeof cssPath === 'string' + ? existsSync(cssPath) + ? ['tailwindcss/tailwind.css', 'Using default Tailwind CSS file'] + : [cssPath, `Using Tailwind CSS from ~/${relative(nuxt.options.srcDir, cssPath)}`] + : [ + resolver.resolve( + addTemplate({ + filename: 'tailwind-empty.css', + write: true, + getContents: () => '' + }).dst + ), + 'No Tailwind CSS file found. Skipping...' + ] + + logger.info(loggerInfo) nuxt.options.css = nuxt.options.css ?? [] - const resolvedNuxtCss = await Promise.all(nuxt.options.css.map((p: any) => resolvePath(p.src ?? p))) // Inject only if this file isn't listed already by user (e.g. user may put custom path both here and in css): @@ -177,42 +156,49 @@ export default defineNuxtModule({ postcssOptions.plugins['postcss-custom-properties'] = postcssOptions.plugins['postcss-custom-properties'] ?? {} postcssOptions.plugins.tailwindcss = tailwindConfig - /* - * install postcss8 module on nuxt < 2.16 - */ + // install postcss8 module on nuxt < 2.16 if (parseFloat(getNuxtVersion()) < 2.16) { await installModule('@nuxt/postcss8') } - /** - * Vite HMR support - */ - if (nuxt.options.dev && !moduleOptions.disableHmrHotfix) { - // Insert Vite plugin to work around HMR issue - addVitePlugin(vitePlugin(tailwindConfig, nuxt.options.rootDir, resolvedCss)) - } + if (nuxt.options.dev) { + // Watch the Tailwind config file to restart the server + if (isNuxt2()) { + nuxt.options.watch = nuxt.options.watch || [] + configPaths.forEach(path => nuxt.options.watch.push(path)) + } else if (Array.isArray(nuxt.options.watch)) { + nuxt.options.watch.push(...configPaths.map(path => relative(nuxt.options.srcDir, path))) + } else { + const watcher = watch(configPaths, { depth: 0 }).on('change', (path) => { + logger.info(`Tailwind config changed: ${path}`) + logger.warn('Please restart the Nuxt server to apply changes or upgrade to latest Nuxt for automatic restart.') + }) + nuxt.hook('close', () => watcher.close()) + } - /** - * Viewer - */ + // Insert Vite plugin to work around HMR issue + if (!moduleOptions.disableHmrHotfix) { + addVitePlugin(vitePlugin(tailwindConfig, nuxt.options.rootDir, resolvedCss)) + } - // Add _tailwind config viewer endpoint - // TODO: Fix `addServerHandler` on Nuxt 2 w/o Bridge - if (nuxt.options.dev && moduleOptions.viewer) { - setupViewer(tailwindConfig, nuxt) - - nuxt.hook('devtools:customTabs', (tabs) => { - tabs.push({ - title: 'TailwindCSS', - name: 'tailwindcss', - icon: 'logos-tailwindcss-icon', - view: { - type: 'iframe', - src: '/_tailwind/' - } + // Add _tailwind config viewer endpoint + // TODO: Fix `addServerHandler` on Nuxt 2 w/o Bridge + if (moduleOptions.viewer) { + setupViewer(tailwindConfig, nuxt) + + nuxt.hook('devtools:customTabs', (tabs) => { + tabs.push({ + title: 'TailwindCSS', + name: 'tailwindcss', + icon: 'logos-tailwindcss-icon', + view: { + type: 'iframe', + src: '/_tailwind/' + } + }) }) - }) + } } } From ad8ef69deff28c4bf3a129ff7ba4fdafd2e5de05 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Tue, 16 May 2023 11:50:31 +0100 Subject: [PATCH 09/12] chore: progress --- docs/content/2.tailwind/1.config.md | 4 ++ src/module.ts | 57 ++++++----------------------- src/resolving.ts | 51 +++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/docs/content/2.tailwind/1.config.md b/docs/content/2.tailwind/1.config.md index bfe8735c..5eadee40 100644 --- a/docs/content/2.tailwind/1.config.md +++ b/docs/content/2.tailwind/1.config.md @@ -125,6 +125,10 @@ This config has less priority over the [tailwind.config.js](#tailwindconfigjs) f This is an advanced usage section and intended primarily for Nuxt modules authors. :: +#### `tailwindcss:loadConfig` + +Passes any Tailwind configuration read by the module for each (extended) [layer](https://nuxt.com/docs/getting-started/layers)/[path](/getting-started/options#configpath) before merging all of them. + #### `tailwindcss:config` Passes the resolved vanilla configuration read from all layers and paths with merging using [defu](https://github.com/unjs/defu). diff --git a/src/module.ts b/src/module.ts index 536f435f..99e52cb7 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,4 +1,3 @@ -import { existsSync } from 'fs' import { join, relative } from 'pathe' import { watch } from 'chokidar' @@ -8,10 +7,8 @@ import { isNuxt2, useLogger, getNuxtVersion, - createResolver, resolvePath, addVitePlugin, - addTemplate, useNuxt } from '@nuxt/kit' @@ -21,8 +18,8 @@ import resolveConfig from 'tailwindcss/resolveConfig.js' import { configMerger } from './utils' import { - resolveConfigPath, - resolveContentPaths, + resolveModulePaths, + resolveCSSPath, resolveInjectPosition } from './resolving' import createTemplates from './templates' @@ -31,7 +28,9 @@ import setupViewer from './viewer' import { name, version, configKey, compatibility } from '../package.json' import type { ModuleOptions, TWConfig } from './types' -export { ModuleOptions } from './types' +export type { ModuleOptions } from './types' + +const logger = useLogger('nuxt:tailwindcss') const defaults = (nuxt = useNuxt()): ModuleOptions => ({ configPath: 'tailwind.config', @@ -47,21 +46,7 @@ const defaults = (nuxt = useNuxt()): ModuleOptions => ({ export default defineNuxtModule({ meta: { name, version, configKey, compatibility }, defaults, async setup (moduleOptions, nuxt) { - const logger = useLogger('nuxt:tailwindcss') - const resolver = createResolver(import.meta.url) - - const [configPaths, contentPaths]: [Array, Array] = - (nuxt.options._layers && nuxt.options._layers.length > 1) - // Support `extends` directories - ? (await Promise.all( - // nuxt.options._layers is from rootDir to nested level - // We need to reverse the order to give the deepest tailwind.config the lowest priority - nuxt.options._layers.slice().reverse().map(async (layer) => ([ - await resolveConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')), - resolveContentPaths(layer?.config?.srcDir || layer.cwd) - ]))) - ).reduce((prev, curr) => prev.map((p, i) => p.concat(curr[i]))) as any - : [await resolveConfigPath(moduleOptions.configPath), resolveContentPaths(nuxt.options.srcDir)] + const [configPaths, contentPaths] = await resolveModulePaths(moduleOptions.configPath, nuxt) const tailwindConfig = ( await Promise.all( @@ -102,30 +87,12 @@ export default defineNuxtModule({ // Compute tailwindConfig hash tailwindConfig._hash = String(Date.now()) - /** - * CSS file handling - */ + /** CSS file handling */ const cssPath = typeof moduleOptions.cssPath === 'string' ? await resolvePath(moduleOptions.cssPath, { extensions: ['.css', '.sass', '.scss', '.less', '.styl'] }) : false - - // Include CSS file in project css - const [resolvedCss, loggerInfo] = - typeof cssPath === 'string' - ? existsSync(cssPath) - ? ['tailwindcss/tailwind.css', 'Using default Tailwind CSS file'] - : [cssPath, `Using Tailwind CSS from ~/${relative(nuxt.options.srcDir, cssPath)}`] - : [ - resolver.resolve( - addTemplate({ - filename: 'tailwind-empty.css', - write: true, - getContents: () => '' - }).dst - ), - 'No Tailwind CSS file found. Skipping...' - ] - + const [resolvedCss, loggerInfo] = resolveCSSPath(cssPath, nuxt) logger.info(loggerInfo) + nuxt.options.css = nuxt.options.css ?? [] const resolvedNuxtCss = await Promise.all(nuxt.options.css.map((p: any) => resolvePath(p.src ?? p))) @@ -141,9 +108,8 @@ export default defineNuxtModule({ nuxt.options.css.splice(injectPosition, 0, resolvedCss) } - /** - * PostCSS 8 support for Nuxt 2 - */ + + /** PostCSS 8 support for Nuxt 2 */ // Setup postcss plugins // https://tailwindcss.com/docs/using-with-preprocessors#future-css-features @@ -162,6 +128,7 @@ export default defineNuxtModule({ } + // enabled only in development if (nuxt.options.dev) { // Watch the Tailwind config file to restart the server if (isNuxt2()) { diff --git a/src/resolving.ts b/src/resolving.ts index ad39e3c1..9bea2a35 100644 --- a/src/resolving.ts +++ b/src/resolving.ts @@ -1,5 +1,7 @@ -import { findPath } from "@nuxt/kit" -import type { Arrayable, InjectPosition } from "./types" +import { existsSync } from 'fs' +import { join, relative } from 'pathe' +import { addTemplate, createResolver, findPath, useNuxt } from '@nuxt/kit' +import type { Arrayable, InjectPosition, ModuleOptions } from './types' /** * Resolves all configPath values for an application @@ -34,6 +36,51 @@ export const resolveContentPaths = (srcDir: string) => ([ `${srcDir}/app.config.{js,ts}` ]) +/** + * + * @param configPath + * @param nuxt + * @returns [configuration paths, default resolved content paths] + */ +export const resolveModulePaths = async (configPath: ModuleOptions['configPath'], nuxt = useNuxt()): Promise<[string[], string[]]> => ( + (nuxt.options._layers && nuxt.options._layers.length > 1) + // Support `extends` directories + ? (await Promise.all( + // nuxt.options._layers is from rootDir to nested level + // We need to reverse the order to give the deepest tailwind.config the lowest priority + nuxt.options._layers.slice().reverse().map(async (layer) => ([ + await resolveConfigPath(layer?.config?.tailwindcss?.configPath || join(layer.cwd, 'tailwind.config')), + resolveContentPaths(layer?.config?.srcDir || layer.cwd) + ]))) + ).reduce((prev, curr) => prev.map((p, i) => p.concat(curr[i]))) as any + : [await resolveConfigPath(configPath), resolveContentPaths(nuxt.options.srcDir)] +) + +/** + * + * @param cssPath + * @param nuxt + * @returns [resolvedCss, loggerMessage] + */ +export function resolveCSSPath (cssPath: ModuleOptions['cssPath'], nuxt = useNuxt()): [string, string] { + if (typeof cssPath === 'string') { + return existsSync(cssPath) + ? [cssPath, `Using Tailwind CSS from ~/${relative(nuxt.options.srcDir, cssPath)}`] + : ['tailwindcss/tailwind.css', 'Using default Tailwind CSS file'] + } else { + return [ + createResolver(import.meta.url).resolve( + addTemplate({ + filename: 'tailwind-empty.css', + write: true, + getContents: () => '' + }).dst + ), + 'No Tailwind CSS file found. Skipping...' + ] + } +} + /** * Resolve human-readable inject position specification into absolute index in the array * From 8a47df8e9bfcd049ebebcf5d097b618003c44a91 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Tue, 16 May 2023 12:13:45 +0100 Subject: [PATCH 10/12] chore: unnesting await --- src/module.ts | 47 +++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/module.ts b/src/module.ts index 99e52cb7..9e77ad63 100644 --- a/src/module.ts +++ b/src/module.ts @@ -48,29 +48,28 @@ export default defineNuxtModule({ async setup (moduleOptions, nuxt) { const [configPaths, contentPaths] = await resolveModulePaths(moduleOptions.configPath, nuxt) - const tailwindConfig = ( - await Promise.all( - configPaths.map(async (configPath, idx, paths) => { - let _tailwindConfig: Partial | undefined - try { - _tailwindConfig = await import(configPath).then(c => c.default || c) - } catch (e) { - logger.warn(`Failed to load Tailwind config at: \`./${relative(nuxt.options.rootDir, configPath)}\``, e) - } - - // Transform purge option from Array to object with { content } - if (_tailwindConfig && !_tailwindConfig.content) { - _tailwindConfig.content = _tailwindConfig.purge - } - - await nuxt.callHook('tailwindcss:loadConfig', _tailwindConfig, configPath, idx, paths) - return _tailwindConfig || {} - })) - ).reduce( - (prev, curr) => configMerger(curr, prev), - // internal default tailwind config - configMerger(moduleOptions.config, { content: contentPaths }) - ) + const tailwindConfig = await Promise.all(( + configPaths.map(async (configPath, idx, paths) => { + let _tailwindConfig: Partial | undefined + try { + _tailwindConfig = await import(configPath).then(c => c.default || c) + } catch (e) { + logger.warn(`Failed to load Tailwind config at: \`./${relative(nuxt.options.rootDir, configPath)}\``, e) + } + + // Transform purge option from Array to object with { content } + if (_tailwindConfig && !_tailwindConfig.content) { + _tailwindConfig.content = _tailwindConfig.purge + } + + await nuxt.callHook('tailwindcss:loadConfig', _tailwindConfig, configPath, idx, paths) + return _tailwindConfig || {} + })) + ).then((configs) => configs.reduce( + (prev, curr) => configMerger(curr, prev), + // internal default tailwind config + configMerger(moduleOptions.config, { content: contentPaths }) + )) // Allow extending tailwindcss config by other modules await nuxt.callHook('tailwindcss:config', tailwindConfig) @@ -135,7 +134,7 @@ export default defineNuxtModule({ nuxt.options.watch = nuxt.options.watch || [] configPaths.forEach(path => nuxt.options.watch.push(path)) } else if (Array.isArray(nuxt.options.watch)) { - nuxt.options.watch.push(...configPaths.map(path => relative(nuxt.options.srcDir, path))) + configPaths.forEach(path => nuxt.options.watch.push(relative(nuxt.options.srcDir, path))) } else { const watcher = watch(configPaths, { depth: 0 }).on('change', (path) => { logger.info(`Tailwind config changed: ${path}`) From f70497020f31e147fca09892ac7ce96c7a6bbb92 Mon Sep 17 00:00:00 2001 From: Inesh Bose <2504266b@student.gla.ac.uk> Date: Wed, 17 May 2023 10:33:35 +0100 Subject: [PATCH 11/12] chore: rename file --- src/module.ts | 2 +- src/{resolving.ts => resolvers.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{resolving.ts => resolvers.ts} (100%) diff --git a/src/module.ts b/src/module.ts index 9e77ad63..524e3d28 100644 --- a/src/module.ts +++ b/src/module.ts @@ -21,7 +21,7 @@ import { resolveModulePaths, resolveCSSPath, resolveInjectPosition -} from './resolving' +} from './resolvers' import createTemplates from './templates' import vitePlugin from './vite-hmr' import setupViewer from './viewer' diff --git a/src/resolving.ts b/src/resolvers.ts similarity index 100% rename from src/resolving.ts rename to src/resolvers.ts From a49bdb3bf7989185e14f68cd6b6265367f84c677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Chopin?= Date: Fri, 19 May 2023 10:52:23 +0200 Subject: [PATCH 12/12] Update src/viewer.ts --- src/viewer.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/viewer.ts b/src/viewer.ts index cf360ef2..e1653275 100644 --- a/src/viewer.ts +++ b/src/viewer.ts @@ -5,7 +5,6 @@ import { withTrailingSlash, withoutTrailingSlash, joinURL } from 'ufo' import type { TWConfig } from './types' export default async function (twConfig: Partial, nuxt = useNuxt()) { - // const { withTrailingSlash, withoutTrailingSlash, joinURL } = await import('ufo') const route = joinURL(nuxt.options.app?.baseURL, '/_tailwind') // @ts-ignore const createServer = await import('tailwind-config-viewer/server/index.js').then(r => r.default || r) as any