Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nuxt-modules/tailwindcss
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v6.7.1
Choose a base ref
...
head repository: nuxt-modules/tailwindcss
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v6.7.2
Choose a head ref
  • 3 commits
  • 16 files changed
  • 1 contributor

Commits on Jun 13, 2023

  1. docs: update deps

    atinux committed Jun 13, 2023
    Copy the full SHA
    5a877b9 View commit details
  2. Revert "perf: parallelise all async calls (#679)"

    This reverts commit 5502765.
    atinux committed Jun 13, 2023
    Copy the full SHA
    69232a3 View commit details
  3. chore(release): v6.7.2

    atinux committed Jun 13, 2023
    Copy the full SHA
    22c86df View commit details
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,23 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## v6.7.2

[compare changes](https://undefined/undefined/compare/v6.7.1...v6.7.2)


### 🔥 Performance

- Parallelise all async calls " (#679)

### 📖 Documentation

- Update deps (5a877b9)

### ❤️ Contributors

- Sébastien Chopin ([@Atinux](http://github.com/Atinux))

## v6.7.1

[compare changes](https://undefined/undefined/compare/v6.7.0...v6.7.1)
4 changes: 1 addition & 3 deletions docs/components/content/Logo.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
<template>
<svg
class="w-auto h-8 text-[#18181B] dark:text-white"
width="224"
height="40"
class="h-8 text-[#18181B] dark:text-white"
viewBox="0 0 224 40"
fill="none"
xmlns="http://www.w3.org/2000/svg"
4 changes: 0 additions & 4 deletions docs/content/2.tailwind/1.config.md
Original file line number Diff line number Diff line change
@@ -125,10 +125,6 @@ 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).
6 changes: 3 additions & 3 deletions docs/package.json
Original file line number Diff line number Diff line change
@@ -12,9 +12,9 @@
"license": "MIT",
"homepage": "https://tailwindcss.nuxtjs.org",
"devDependencies": {
"@nuxt-themes/docus": "^1.11.1",
"@nuxthq/studio": "^0.12.1",
"@nuxt-themes/docus": "^1.12.3",
"@nuxthq/studio": "^0.13.2",
"@nuxtjs/plausible": "^0.2.1",
"nuxt": "^3.4.3"
"nuxt": "^3.5.3"
}
}
2,782 changes: 1,461 additions & 1,321 deletions docs/pnpm-lock.yaml

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
{
"name": "@nuxtjs/tailwindcss",
"version": "6.7.1",
"version": "6.7.2",
"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",
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const colors = require('tailwindcss/colors')
import colors from 'tailwindcss/colors'

module.exports = {
export default {
theme: {
extend: {
colors: {
4 changes: 2 additions & 2 deletions src/vite-hmr.ts → src/hmr.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { isAbsolute, resolve } from 'pathe'
import type { Plugin as VitePlugin } from 'vite'
import type { TWConfig } from './types'
import type { Config } from 'tailwindcss'
import micromatch from 'micromatch'

export default function (tailwindConfig: Partial<TWConfig> = {}, rootDir: string, cssPath: string): VitePlugin {
export default function (tailwindConfig: Partial<Config> = {}, rootDir: string, cssPath: string): VitePlugin {
const resolvedContent = ((Array.isArray(tailwindConfig.content) ? tailwindConfig.content : tailwindConfig.content?.files || []).filter(f => typeof f === 'string') as Array<string>).map(f => !isAbsolute(f) ? resolve(rootDir, f) : f)

return {
316 changes: 215 additions & 101 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,166 @@
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,
useNuxt
isNuxt3, findPath, requireModule
} 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 { configMerger } from './utils'
import {
resolveModulePaths,
resolveCSSPath,
resolveInjectPosition
} from './resolvers'
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'
export type { ModuleOptions } from './types'
import { eventHandler, sendRedirect, H3Event } from 'h3'
import { name, version } from '../package.json'
import vitePlugin from './hmr'
import { configMerger, createTemplates, InjectPosition, resolveInjectPosition } from './utils'
import { addTemplate } from '@nuxt/kit'

const logger = useLogger('nuxt:tailwindcss')

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
})
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 | T[]

declare module '@nuxt/schema' {
interface NuxtHooks {
'tailwindcss:config': (tailwindConfig: Partial<Config>) => void;
'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType<typeof resolveConfig<Config>>) => void;
}
}

interface ExtendTailwindConfig {
content: Config['content'] | ((contentDefaults: string[]) => Config['content']);
}

export interface ModuleOptions {
configPath: Arrayable<string>;
cssPath: string | false;
config: Omit<Config, keyof ExtendTailwindConfig> & ExtendTailwindConfig;
viewer: boolean;
exposeConfig: boolean;
exposeLevel: number;
injectPosition: InjectPosition;
disableHmrHotfix: boolean;
}

export default defineNuxtModule<ModuleOptions>({
meta: { name, version, configKey, compatibility }, defaults,
meta: {
name,
version,
configKey: 'tailwindcss'
},
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
}),
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<TWConfig> | 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)
}
/**
* Config file handling
*/

const configPaths: string[] = []
const contentPaths = []

// Transform purge option from Array to object with { content }
if (_tailwindConfig && !_tailwindConfig.content) {
_tailwindConfig.content = _tailwindConfig.purge
/**
* 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<string>) => {
// 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)
}
}
}

// 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))
}
} else {
await addConfigPath(moduleOptions.configPath)
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)))
} 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())
}
}

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 })
))
// 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<Config> | 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)
}
}

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

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

// Expose resolved tailwind config as an alias
@@ -86,13 +172,35 @@ export default defineNuxtModule<ModuleOptions>({
// 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
const [resolvedCss, loggerInfo] = resolveCSSPath(cssPath, nuxt)
logger.info(loggerInfo)

// 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')
// @ts-ignore
resolvedCss = 'tailwindcss/tailwind.css'
}
} 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)
}
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):
@@ -107,8 +215,9 @@ export default defineNuxtModule<ModuleOptions>({
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
@@ -121,59 +230,64 @@ export default defineNuxtModule<ModuleOptions>({
postcssOptions.plugins['postcss-custom-properties'] = postcssOptions.plugins['postcss-custom-properties'] ?? {}
postcssOptions.plugins.tailwindcss = tailwindConfig

// install postcss8 module on nuxt < 2.16
if (parseFloat(getNuxtVersion()) < 2.16) {
/*
* install postcss8 module on nuxt < 2.16
*/
const nuxtVersion = getNuxtVersion(nuxt).split('.')
if (parseInt(nuxtVersion[0], 10) === 2 && parseInt(nuxtVersion[1], 10) < 16) {
await installModule('@nuxt/postcss8')
}

/**
* Vite HMR support
*/

// enabled only in development
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)) {
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}`)
logger.warn('Please restart the Nuxt server to apply changes or upgrade to latest Nuxt for automatic restart.')
})
nuxt.hook('close', () => watcher.close())
}

if (nuxt.options.dev && !moduleOptions.disableHmrHotfix) {
// Insert Vite plugin to work around HMR issue
if (!moduleOptions.disableHmrHotfix) {
addVitePlugin(vitePlugin(tailwindConfig, nuxt.options.rootDir, resolvedCss))
}
addVitePlugin(vitePlugin(tailwindConfig, nuxt.options.rootDir, resolvedCss))
}

/**
* Viewer
*/

// 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/'
}
})
// 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)))}`)
})
}

if (nuxt.options.dev && moduleOptions.viewer) {
nuxt.hook('devtools:customTabs', (tabs) => {
tabs.push({
title: 'TailwindCSS',
name: 'tailwindcss',
icon: 'logos-tailwindcss-icon',
view: {
type: 'iframe',
src: '/_tailwind/'
}
})
}
})
}
}

})

declare module '@nuxt/schema' {
interface NuxtHooks {
'tailwindcss:config': (tailwindConfig: Partial<TWConfig>) => void;
'tailwindcss:loadConfig': (tailwindConfig: Partial<TWConfig> | undefined, configPath: string, index: number, configPaths: string[]) => void;
'tailwindcss:resolvedConfig': (tailwindConfig: ReturnType<typeof resolveConfig<TWConfig>>) => void;
}
}
115 changes: 0 additions & 115 deletions src/resolvers.ts

This file was deleted.

75 changes: 0 additions & 75 deletions src/templates.ts

This file was deleted.

18 changes: 0 additions & 18 deletions src/types.ts

This file was deleted.

119 changes: 114 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { dirname, join } from 'pathe'
import { useNuxt, addTemplate } from '@nuxt/kit'
import type { Config } from 'tailwindcss'
import { createDefu } from 'defu'
import type { TWConfig } from './types'

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

export const configMerger: (
...p: Array<Partial<TWConfig> | Record<string | number | symbol, any>>
) => Partial<TWConfig> = createDefu((obj, key, value) => {
...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]
@@ -23,3 +25,110 @@ export const configMerger: (
return true
}
})


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

/**
* 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<Config>, 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 })
})
}
26 changes: 0 additions & 26 deletions src/viewer.ts

This file was deleted.

16 changes: 8 additions & 8 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
@@ -34,19 +34,19 @@ 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.replace(/\\/g /* windows protocol */, '/'))
expect(nuxt.options.css[0]).toEqual(nuxt.options.tailwindcss.cssPath)

expect(spyStderr).toHaveBeenCalledTimes(0)
expect(spyStdout).toHaveBeenCalledTimes(1)
expect(spyStdout.mock.calls[0][0]).contains('Using Tailwind CSS from ~/tailwind.css')
})

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"')
})
})
16 changes: 8 additions & 8 deletions test/configs.test.ts
Original file line number Diff line number Diff line change
@@ -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()