Skip to content

Commit

Permalink
fix(config): use mjs template (#930)
Browse files Browse the repository at this point in the history
  • Loading branch information
ineshbose authored Dec 25, 2024
1 parent 0696aba commit bbe05d0
Show file tree
Hide file tree
Showing 6 changed files with 21 additions and 32 deletions.
4 changes: 2 additions & 2 deletions docs/content/2.tailwind/3.editor-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ const variantClasses = {

## Configuration IntelliSense

Since Tailwind CSS v3.3, [ESM/TS configuration has been supported](https://tailwindcss.com/blog/tailwindcss-v3-3#esm-and-type-script-support) so your editor should automatically configure autocomplete based on your `tailwind.config`. If you have a complex Nuxt project with multiple Tailwind configurations that are within layers, passed from hooks or inline `nuxt.config` and want to use a merged configuration, the module generates it in `.nuxt/tailwind.config.cjs` that you can use by adding the following VSCode setting:
Since Tailwind CSS v3.3, [ESM/TS configuration has been supported](https://tailwindcss.com/blog/tailwindcss-v3-3#esm-and-type-script-support) so your editor should automatically configure autocomplete based on your `tailwind.config`. If you have a complex Nuxt project with multiple Tailwind configurations that are within layers, passed from hooks or inline `nuxt.config` and want to use a merged configuration, the module generates it in `.nuxt/tailwind/postcss.mjs` that you can use by adding the following VSCode setting:

::callout{color="blue" icon="i-ph-info-duotone"}
Tailwind provides the [Tailwind CSS IntelliSense](https://tailwindcss.com/docs/editor-setup#jet-brains-ides) extension for better integration with different IDEs.
::

```diff [.vscode/settings.json]
// ...
+ "tailwindCSS.experimental.configFile": ".nuxt/tailwind.config.cjs",
+ "tailwindCSS.experimental.configFile": ".nuxt/tailwind/postcss.mjs",
"files.associations": {
"*.css": "tailwindcss"
},
Expand Down
8 changes: 4 additions & 4 deletions src/expose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const createExposeTemplates = (config: ExposeConfig, nuxt = useNuxt()) =>
|| Object.keys(value).find(k => !k.match(NON_ALPHANUMERIC_RE)) // object has non-alphanumeric property (unsafe var name)
) {
templates.push(addTemplate({
filename: `tailwind.config/${subpath}.mjs`,
filename: `tailwind/expose/${subpath}.mjs`,
getContents: () => {
const _value = getTWConfig(subpathComponents)

Expand All @@ -50,7 +50,7 @@ export const createExposeTemplates = (config: ExposeConfig, nuxt = useNuxt()) =>
populateMap(value, path.concat(key), level + 1)

templates.push(addTemplate({
filename: `tailwind.config/${subpath}.mjs`,
filename: `tailwind/expose/${subpath}.mjs`,
getContents: () => {
const _value = getTWConfig(subpathComponents)
const values = Object.keys(_value)
Expand All @@ -70,13 +70,13 @@ export const createExposeTemplates = (config: ExposeConfig, nuxt = useNuxt()) =>
populateMap()

const entryTemplate = addTemplate({
filename: 'tailwind.config/index.mjs',
filename: 'tailwind/expose/index.mjs',
getContents: () => {
const _tailwindConfig = getTWConfig()
const configOptions = Object.keys(_tailwindConfig)

return [
`${configOptions.map(v => `import ${v} from "#build/tailwind.config/${v}.mjs"`).join('\n')}`,
`${configOptions.map(v => `import ${v} from "#build/tailwind/expose/${v}.mjs"`).join('\n')}`,
`const config = { ${configOptions.join(', ')} }`,
`export { config as default, ${configOptions.join(', ')} }`,
].join('\n')
Expand Down
22 changes: 8 additions & 14 deletions src/internal-context/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,8 @@ const createInternalContext = async (moduleOptions: ModuleOptions, nuxt = useNux

...(nuxt.options._layers || []).slice(1).flatMap(nuxtLayer => [
resolveContentConfig(nuxtLayer.config?.srcDir || nuxtLayer.cwd, nuxtLayer.config),
// @ts-expect-error layer config
...resolveConfigs(nuxtLayer.config.tailwindcss?.config, nuxt),
loadConfig({ name: 'tailwind', cwd: nuxtLayer.cwd, merger: configMerger, packageJson: true, extend: false }).then(thenCallHook),
// @ts-expect-error layer config
...resolveConfigs(nuxtLayer.config.tailwindcss?.configPath, nuxt),
]),
])
Expand All @@ -155,10 +153,11 @@ const createInternalContext = async (moduleOptions: ModuleOptions, nuxt = useNux

const generateConfig = () => {
const ctx = twCtx.tryUse()
const targetDir = join(nuxt.options.buildDir, 'tailwind')

const template = !meta.disableHMR || !ctx?.meta?.disableHMR
? addTemplate({
filename: 'tailwind.config.cjs',
filename: 'tailwind/postcss.mjs',
write: true,
getContents: () => {
const serializeConfig = <T extends Partial<TWConfig>>(config: T) =>
Expand All @@ -167,22 +166,17 @@ const createInternalContext = async (moduleOptions: ModuleOptions, nuxt = useNux
(_, v) => typeof v === 'function' ? `() => (${JSON.stringify(v())})` : v,
).replace(/"(\(\) => \(.*\))"/g, (_, substr) => substr.replace(/\\"/g, '"'))

const layerConfigs = resolvedConfigsCtx.use().map((c) => {
if (c?.configFile) {
const configImport = `require(${JSON.stringify(/[/\\]node_modules[/\\]/.test(c.configFile) ? c.configFile : './' + relative(nuxt.options.buildDir, c.configFile))})`
return configUpdatedHook[c.configFile] ? `(() => {const cfg=configMerger(undefined, ${configImport});${configUpdatedHook[c.configFile]};return cfg;})()` : configImport
}

return c && serializeConfig(c.config)
}).filter(Boolean)
const layerConfigs = resolvedConfigsCtx.use().map((c, idx): [string | null, string | null] => c?.configFile ? [`import cfg${idx} from ${JSON.stringify(/[/\\]node_modules[/\\]/.test(c.configFile) ? c.configFile : './' + relative(targetDir, c.configFile))}`, configUpdatedHook[c.configFile] ? `(() => {const cfg=configMerger(undefined, cfg${idx});${configUpdatedHook[c.configFile]};return cfg;})()` : `cfg${idx}`] : [null, c && serializeConfig(c.config)])

return [
`// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at ${(new Date()).toLocaleString()}`,
`const configMerger = require("@nuxtjs/tailwindcss/merger");\n`,
`import configMerger from "@nuxtjs/tailwindcss/merger";\n`,
layerConfigs.map(([i, _]) => i).filter(Boolean).join(';\n') + ';',
'const config = [',
layerConfigs.join(',\n'),
layerConfigs.map(([_, i]) => i).filter(Boolean).join(',\n'),
`].reduce((acc, curr) => configMerger(acc, curr), {});\n`,
`module.exports = ${configUpdatedHook['main-config'] ? `(() => {const cfg=config;${configUpdatedHook['main-config']};return cfg;})()` : 'config'}\n`,
`const resolvedConfig = ${configUpdatedHook['main-config'] ? `(() => {const cfg=config;${configUpdatedHook['main-config']};return cfg;})()` : 'config'};\n`,
'export default resolvedConfig;',
].join('\n')
},
})
Expand Down
2 changes: 1 addition & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default defineNuxtModule<ModuleOptions>({
}

// workaround for nuxt2 middleware race condition
let nuxt2ViewerConfig: Parameters<typeof setupViewer>[0] = join(nuxt.options.buildDir, 'tailwind.config.cjs')
let nuxt2ViewerConfig: Parameters<typeof setupViewer>[0] = join(nuxt.options.buildDir, 'tailwind/postcss.mjs')

nuxt.hook('modules:done', async () => {
const _config = await ctx.loadConfigs()
Expand Down
9 changes: 2 additions & 7 deletions test/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,17 @@ describe('tailwindcss module', async () => {
})

test('expose config', () => {
const vfsFile = getVfsFile('tailwind.config/theme/flexBasis.mjs')
const vfsFile = getVfsFile('tailwind/expose/theme/flexBasis.mjs')
// check default tailwind default animation exists
expect(vfsFile).contains('"full": _full, "0.5": "0.125rem"')
expect(vfsFile).contains('export { config as default')
})

test('expose config variable', () => {
const vfsFile = getVfsFile('tailwind.config/theme/animation.mjs')
const vfsFile = getVfsFile('tailwind/expose/theme/animation.mjs')
expect(vfsFile).contains('const _pulse = "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"')
})

test('expose config alias', () => {
const vfsFile = getVfsFile('tailwind.config.d.ts')
expect(vfsFile).contains('declare module "#twcss"')
})

// test('viewer works', async () => {
// const html = await $fetch('/_tw')
// expect(html).contains("tailwind-config-viewer doesn't work properly without JavaScript enabled")
Expand Down
8 changes: 4 additions & 4 deletions test/configs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('tailwindcss module configs', async () => {
})

test('malformed config is not read', () => {
expect(getVfsFile('tailwind.config.cjs')).not.contains('malformed-tailwind.config')
expect(getVfsFile('tailwind/postcss.mjs')).not.contains('malformed-tailwind.config')
})

test('ts config file is loaded and merged', () => {
Expand Down Expand Up @@ -93,8 +93,8 @@ describe('tailwindcss module configs', async () => {
})

test('config template compiled properly', () => {
const configFile = getVfsFile('tailwind.config.cjs')
const loadedConfig = loadConfig(join(useTestContext().nuxt!.options.buildDir, 'tailwind.config.cjs'))
expect(configFile).contains(`module.exports = (() => {const cfg=config;cfg["content"]${'files' in loadedConfig.content ? `["files"]["${loadedConfig.content.files.length - 1}"]` : `["${loadedConfig.content.length - 1}"]`} = "my-custom-content";;return cfg;})()`)
const configFile = getVfsFile('tailwind/postcss.mjs')
const loadedConfig = loadConfig(join(useTestContext().nuxt!.options.buildDir, 'tailwind/postcss.mjs'))
expect(configFile).contains(`const resolvedConfig = (() => {const cfg=config;cfg["content"]${'files' in loadedConfig.content ? `["files"]["${loadedConfig.content.files.length - 1}"]` : `["${loadedConfig.content.length - 1}"]`} = "my-custom-content";;return cfg;})()`)
})
})

0 comments on commit bbe05d0

Please sign in to comment.