Skip to content

Commit

Permalink
feat: allow content as object (#674)
Browse files Browse the repository at this point in the history
* fix: typeof import default in dts

* chore: using nuxt convention for indexing type

* chore: initial

* chore: tests

* Update src/module.ts

* chore: remove runtime dir

---------

Co-authored-by: Sébastien Chopin <[email protected]>
Co-authored-by: Sébastien Chopin <[email protected]>
Co-authored-by: Sébastien Chopin <[email protected]>
  • Loading branch information
4 people authored May 15, 2023
1 parent e96937d commit 8c4e528
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 16 deletions.
27 changes: 17 additions & 10 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,8 @@ 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'
import { addTemplate } from '@nuxt/kit'

const logger = useLogger('nuxt:tailwindcss')

Expand All @@ -45,7 +45,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 +137,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 +153,14 @@ export default defineNuxtModule<ModuleOptions>({
_tailwindConfig.content = _tailwindConfig.purge
}
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 +180,24 @@ export default defineNuxtModule<ModuleOptions>({

// 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 from runtime/tailwind.css')
logger.info('Using default Tailwind CSS file')
// @ts-ignore
resolvedCss = createResolver(import.meta.url).resolve('runtime/tailwind.css')
resolvedCss = 'tailwindcss/tailwind.css'
}
} else {
logger.info('No Tailwind CSS file found. Skipping...')
resolvedCss = createResolver(import.meta.url).resolve('runtime/empty.css')
const emptyCSSPath = addTemplate({
filename: 'tailwind-empty.css',
write: true,
getContents: () => ''
}).dst
resolvedCss = createResolver(import.meta.url).resolve(emptyCSSPath)
}
nuxt.options.css = nuxt.options.css ?? []

Expand Down
Empty file removed src/runtime/empty.css
Empty file.
3 changes: 0 additions & 3 deletions src/runtime/tailwind.css

This file was deleted.

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;

0 comments on commit 8c4e528

Please sign in to comment.