Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow content as object #674

Merged
merged 13 commits into from
May 15, 2023
20 changes: 11 additions & 9 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { existsSync } from 'fs'
import { join, relative } from 'pathe'
import { defuArrayFn } from 'defu'
import { watch } from 'chokidar'
import { underline, yellow } from 'colorette'
import {
Expand All @@ -22,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 { createTemplates, InjectPosition, resolveInjectPosition } from './utils'
import { configMerger, createTemplates, InjectPosition, resolveInjectPosition } from './utils'

const logger = useLogger('nuxt:tailwindcss')

Expand All @@ -45,7 +44,7 @@ type Arrayable<T> = T | T[]
declare module '@nuxt/schema' {
interface NuxtHooks {
'tailwindcss:config': (tailwindConfig: Partial<Config>) => void;
'tailwindcss:resolvedConfig': (tailwindConfig: Config) => void;
'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType<typeof resolveConfig<Config>>) => void;
}
}

Expand Down Expand Up @@ -137,10 +136,11 @@ export default defineNuxtModule<ModuleOptions>({
}

// Default tailwind config
let tailwindConfig = defuArrayFn(moduleOptions.config, { content: contentPaths }) as Config
let tailwindConfig = configMerger(moduleOptions.config, { content: contentPaths })

// Recursively resolve each config and merge tailwind configs together.
for (const configPath of configPaths) {
let _tailwindConfig: Config | undefined
let _tailwindConfig: Partial<Config> | undefined
try {
_tailwindConfig = requireModule(configPath, { clearCache: true })
} catch (e) {
Expand All @@ -152,14 +152,14 @@ export default defineNuxtModule<ModuleOptions>({
_tailwindConfig.content = _tailwindConfig.purge
Atinux marked this conversation as resolved.
Show resolved Hide resolved
}
if (_tailwindConfig) {
tailwindConfig = defuArrayFn(_tailwindConfig, tailwindConfig)
tailwindConfig = configMerger(_tailwindConfig, tailwindConfig)
}
}

// Allow extending tailwindcss config by other modules
await nuxt.callHook('tailwindcss:config', tailwindConfig)

const resolvedConfig = resolveConfig(tailwindConfig) as Config
const resolvedConfig = resolveConfig(tailwindConfig as Config)
await nuxt.callHook('tailwindcss:resolvedConfig', resolvedConfig)

// Expose resolved tailwind config as an alias
Expand All @@ -179,18 +179,20 @@ export default defineNuxtModule<ModuleOptions>({

// Include CSS file in project css
let resolvedCss: string
const { resolve: relativeResolve } = createResolver(import.meta.url)

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 from runtime/tailwind.css')
Atinux marked this conversation as resolved.
Show resolved Hide resolved
// @ts-ignore
resolvedCss = createResolver(import.meta.url).resolve('runtime/tailwind.css')
resolvedCss = relativeResolve('runtime/tailwind.css')
Atinux marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
logger.info('No Tailwind CSS file found. Skipping...')
resolvedCss = createResolver(import.meta.url).resolve('runtime/empty.css')
resolvedCss = relativeResolve('runtime/empty.css')
Atinux marked this conversation as resolved.
Show resolved Hide resolved
}
nuxt.options.css = nuxt.options.css ?? []

Atinux marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
24 changes: 23 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import { dirname, join } from 'pathe'
import { useNuxt, addTemplate } from '@nuxt/kit'
import type { Config } from 'tailwindcss'
import { createDefu } from 'defu'

const NON_ALPHANUMERIC_RE = /^[0-9a-z]+$/i
const isJSObject = (value: any) => typeof value === 'object' && !Array.isArray(value)

export const configMerger: (
...p: Array<Partial<Config> | Record<string | number | symbol, any>>
) => Partial<Config> = createDefu((obj, key, value) => {
if (key === 'content') {
if (isJSObject(obj[key]) && Array.isArray(value)) {
obj[key]['files'] = [...(obj[key]['files'] || []), ...value]
return true
} else if (Array.isArray(obj[key]) && isJSObject(value)) {
obj[key] = { ...value, files: [...obj[key], ...(value.files || [])]}
return true
}
}

// keeping arrayFn
if (Array.isArray(obj[key]) && typeof value === "function") {
obj[key] = value(obj[key])
return true
}
})


export type InjectPosition = 'first' | 'last' | number | { after: string };

/**
Expand Down Expand Up @@ -47,7 +69,7 @@ export function resolveInjectPosition (css: string[], position: InjectPosition)
* @param maxLevel maximum level of depth
* @param nuxt nuxt app
*/
export const createTemplates = (resolvedConfig: Config, maxLevel: number, nuxt = useNuxt()) => {
export function createTemplates (resolvedConfig: Partial<Config>, maxLevel: number, nuxt = useNuxt()) {
const dtsContent: string[] = []

const populateMap = (obj: any, path: string[] = [], level = 1) => {
Expand Down
14 changes: 12 additions & 2 deletions test/configs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ describe('tailwindcss module configs', async () => {
'alt-tailwind.config.js',
'malformed-tailwind.config',
'ts-tailwind.config',
'override-tailwind.config.js'
'override-tailwind.config.js',
'content-obj.config'
],
cssPath: 'tailwind.css'
})
Expand Down Expand Up @@ -50,9 +51,18 @@ describe('tailwindcss module configs', async () => {
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
expect(contentFiles.length).toBe(4)

expect(contentFiles[0]).toBe('ts-content/**/*.md')
expect(contentFiles[1]).toBe('./custom-theme/**/*.vue')
expect(contentFiles.slice(2).filter(c => c.endsWith('vue')).length).toBe(2)
})

test('content merges with objects', () => {
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()
expect(content.files.pop()).toBe('./my-components/**/*.tsx')
})
})
13 changes: 13 additions & 0 deletions test/fixture/basic/content-obj.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Config } from 'tailwindcss'

const config: Config = {
content: {
relative: true,
files: ['./my-components/**/*.tsx'],
extract: {
jpg: () => ['bg-red']
}
}
}

export default config;