Skip to content

Commit 81595fe

Browse files
authored
feat: first class hmr (#818)
1 parent 4ecc5ad commit 81595fe

24 files changed

+3307
-1398
lines changed

docs/content/1.getting-started/2.configuration.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,13 @@ You can edit the endpoint by `viewer.endpoint` and if you'd like to export the v
167167

168168
- Default: `false`
169169

170-
You can take advantage of some DX utilities this modules provide to you as you develop your Nuxt applicatio with Tailwind. Read more in [Editor Support](/tailwind/editor-support).
170+
You can take advantage of some DX utilities this modules provide to you as you develop your Nuxt application with Tailwind. Read more in [Editor Support](/tailwind/editor-support).
171171

172172
```ts [nuxt.config.ts]
173173
export default defineNuxtConfig({
174174
tailwindcss: {
175175
editorSupport: true
176-
// editorSupport: { autocompleteUtil: { as: 'tailwindClasses' }, generateConfig: true }
176+
// editorSupport: { autocompleteUtil: { as: 'tailwindClasses' } }
177177
}
178178
})
179179
```

docs/content/2.tailwind/3.editor-support.md

+19-14
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Add the following configuration to your `.vscode/settings.json` file, so that Ta
2020

2121
If you use pnpm, ensure that tailwindcss is installed in your top-level node_modules folder.
2222

23-
## Autocomplete
23+
## String Classes Autocomplete
2424

2525
When using strings of Tailwind classes, you can enable IntelliSense suggestions using the [`editorSupport.autocompleteUtil`](/getting-started/configuration#editorsupport) option. You will have to add the following VSCode setting:
2626

@@ -44,9 +44,20 @@ const variantClasses = {
4444
</script>
4545
```
4646

47-
## Load Config File
47+
## Configuration IntelliSense
4848

49-
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 happen to use a lower version and/or require to generate a flat configuration, you can do so using [`editorSupport.generateConfig`](/getting-started/configuration#editorsupport) option, or you can use the `tailwindcss:resolvedConfig` hook and a custom Nuxt module:
49+
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:
50+
51+
```diff [.vscode/settings.json]
52+
// ...
53+
+ "tailwindCSS.experimental.configFile": ".nuxt/tailwind.config.cjs",
54+
"files.associations": {
55+
"*.css": "tailwindcss"
56+
},
57+
// ...
58+
```
59+
60+
If you require more customisation to what configuration the IntelliSense extension reads, you can take advantage of hooks, especially the `tailwindcss:resolvedConfig` hook that runs the configuration through [`tailwindcss/resolveConfig`](https://github.com/tailwindlabs/tailwindcss/blob/master/resolveConfig.js) to provide the complete config object.
5061

5162
```ts [modules/tw-cjs-config.ts]
5263
import { defineNuxtModule, addTemplate } from '@nuxt/kit'
@@ -55,8 +66,11 @@ export default defineNuxtModule({
5566
setup (options, nuxt) {
5667
nuxt.hook('tailwindcss:resolvedConfig', (config) => {
5768
addTemplate({
58-
filename: 'tailwind.config.cjs', // gets prepended by .nuxt/
59-
getContents: () => `module.exports = ${JSON.stringify(config)}`,
69+
filename: 'intellisense-tw.cjs', // gets prepended by .nuxt/
70+
getContents: () => `
71+
/* my-comment */
72+
module.exports = ${JSON.stringify(config)}
73+
`,
6074
write: true
6175
})
6276
})
@@ -65,12 +79,3 @@ export default defineNuxtModule({
6579
```
6680

6781
This hook allows you to customize your generated template in different ways (e.g., different filename, contents, etc.) through a module. Please be aware that using `JSON.stringify` will remove plugins from your configuration.
68-
69-
```diff [.vscode/settings.json]
70-
// ...
71-
+ "tailwindCSS.experimental.configFile": ".nuxt/tailwind.config.cjs",
72-
"files.associations": {
73-
"*.css": "tailwindcss"
74-
},
75-
// ...
76-
```

package.json

+17-20
Original file line numberDiff line numberDiff line change
@@ -43,38 +43,35 @@
4343
"test:types": "pnpm dev:prepare && tsc --noEmit && nuxi typecheck playground"
4444
},
4545
"dependencies": {
46-
"@nuxt/kit": "^3.9.3",
47-
"autoprefixer": "^10.4.17",
48-
"chokidar": "^3.5.3",
49-
"clear-module": "^4.1.2",
46+
"@nuxt/kit": "^3.11.1",
47+
"autoprefixer": "^10.4.19",
5048
"consola": "^3.2.3",
5149
"defu": "^6.1.4",
52-
"h3": "^1.10.0",
53-
"micromatch": "^4.0.5",
50+
"h3": "^1.11.1",
5451
"pathe": "^1.1.2",
5552
"postcss": "^8.4.33",
56-
"postcss-custom-properties": "^13.3.4",
57-
"postcss-nesting": "^12.0.2",
53+
"postcss-custom-properties": "^13.3.6",
54+
"postcss-nesting": "^12.1.0",
5855
"tailwind-config-viewer": "^1.7.3",
5956
"tailwindcss": "~3.4.1",
60-
"ufo": "^1.3.2"
57+
"ufo": "^1.5.3",
58+
"unctx": "^2.3.1"
6159
},
6260
"devDependencies": {
63-
"@fontsource/inter": "^5.0.16",
64-
"@nuxt/content": "^2.10.0",
65-
"@nuxt/devtools": "^1.0.8",
61+
"@fontsource/inter": "^5.0.17",
62+
"@nuxt/content": "^2.12.1",
63+
"@nuxt/devtools": "^1.1.5",
6664
"@nuxt/eslint-config": "latest",
6765
"@nuxt/module-builder": "^0.5.5",
68-
"@nuxt/test-utils": "^3.10.0",
69-
"@tailwindcss/typography": "^0.5.10",
70-
"@types/micromatch": "^4.0.6",
66+
"@nuxt/test-utils": "^3.12.0",
67+
"@tailwindcss/typography": "^0.5.12",
7168
"changelogen": "^0.5.5",
72-
"destr": "^2.0.2",
69+
"destr": "^2.0.3",
7370
"eslint": "latest",
7471
"happy-dom": "^13.1.4",
75-
"nuxt": "^3.9.3",
76-
"typescript": "^5.3.3",
77-
"vitest": "1.1.0"
72+
"nuxt": "^3.11.1",
73+
"typescript": "^5.4.3",
74+
"vitest": "1.4.0"
7875
},
7976
"packageManager": "[email protected]",
8077
"resolutions": {
@@ -83,4 +80,4 @@
8380
"stackblitz": {
8481
"startCommand": "pnpm dev:prepare && pnpm dev"
8582
}
86-
}
83+
}

playground/app.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
</template>
66

77
<script setup>
8-
</script>
8+
</script>

playground/modules/resolved.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { defineNuxtModule, addTemplate, updateTemplates } from '@nuxt/kit'
2+
import { resolve } from 'pathe'
3+
import loadConfig from 'tailwindcss/loadConfig.js'
4+
import resolveConfig from 'tailwindcss/resolveConfig.js'
5+
6+
export default defineNuxtModule({
7+
setup (_options, nuxt) {
8+
// logger.info('Creating test-tailwind.config.cjs...')
9+
let counter = 1
10+
11+
nuxt.hook('tailwindcss:resolvedConfig', (config, oldConfig) =>
12+
oldConfig
13+
? setTimeout(() => updateTemplates({ filter: t => t.filename === 'resolved-config.cjs' }), 100)
14+
: addTemplate({
15+
filename: 'resolved-config.cjs',
16+
getContents: () => `module.exports = /* ${counter++}, ${Boolean(oldConfig)} */ ${JSON.stringify(config, null, 2)}`,
17+
write: true
18+
})
19+
)
20+
21+
// const template = addTemplate({
22+
// filename: 'resolved-config.config.cjs', // gets prepended by .nuxt/
23+
// getContents: ({ nuxt }) => {
24+
// const config = loadConfig(resolve(nuxt.options.buildDir, 'tailwind.config.cjs'))
25+
// return `module.exports = ${JSON.stringify(resolveConfig(config), null, 2)}`
26+
// },
27+
// write: true
28+
// })
29+
30+
// nuxt.hook('app:templatesGenerated', (_app, templates) => {
31+
// templates.map(t => t.dst).includes(resolve(nuxt.options.buildDir, 'tailwind.config.cjs')) && updateTemplates({ filter: t => t.dst === template.dst })
32+
// })
33+
}
34+
})

playground/modules/template.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { defineNuxtModule, addTemplate } from '@nuxt/kit'
2+
3+
export default defineNuxtModule((_, nuxt) => {
4+
const template = addTemplate({
5+
filename: 'my-tw-config.cjs',
6+
write: true,
7+
getContents: () => `
8+
const colors = require('tailwindcss/colors')
9+
10+
module.exports = {
11+
theme: {
12+
extend: {
13+
colors: {
14+
accent: colors.slate['500']
15+
}
16+
}
17+
}
18+
}
19+
`
20+
})
21+
22+
nuxt.options.tailwindcss = nuxt.options.tailwindcss ?? {}
23+
if (!Array.isArray(nuxt.options.tailwindcss.configPath)) {
24+
nuxt.options.tailwindcss.configPath = nuxt.options.tailwindcss.configPath ? [nuxt.options.tailwindcss.configPath] : ['tailwind.config']
25+
}
26+
nuxt.options.tailwindcss.configPath.push(template.dst)
27+
})

playground/nuxt.config.ts

+42-3
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,58 @@
1+
import { defineNuxtConfig } from 'nuxt/config'
12
import { existsSync } from 'node:fs'
23
import { resolve } from 'pathe'
4+
import { consola } from 'consola'
5+
import typography from '@tailwindcss/typography'
6+
7+
import type { ModuleHooks, ModuleOptions } from '../src/types'
8+
9+
const logger = consola.withTag('nuxt:tailwindcss:playground')
310

411
export default defineNuxtConfig({
512
extends: ['./theme'],
13+
// builder: 'webpack',
614
modules: [
7-
'@nuxt/content',
815
existsSync(resolve(__dirname, '../dist/module.mjs')) ? '@nuxtjs/tailwindcss' : '../src/module',
9-
'@nuxt/devtools'
16+
'@nuxt/content',
1017
],
18+
// @ts-ignore
1119
tailwindcss: {
1220
// viewer: false,
21+
config: { plugins: [typography()] },
1322
exposeConfig: true,
1423
cssPath: '~/assets/css/tailwind.css',
1524
editorSupport: true
16-
},
25+
} satisfies Partial<ModuleOptions>,
26+
hooks: {
27+
'tailwindcss:loadConfig': (config, configPath, idx) => {
28+
logger.info('Running `tailwindcss:loadConfig` hook...', Object.keys(config || {}), { configPath, idx })
29+
30+
if (idx === 0 && config) {
31+
config.theme = config.theme ?? {}
32+
config.theme.extend = config.theme.extend ?? {}
33+
config.theme.extend.screens = { md2: '100px' }
34+
config.theme.extend.colors = config.theme.extend.colors ?? {}
35+
// @ts-ignore
36+
config.theme.extend.colors.zeroLayer = '#0fe325'
37+
} else if (idx === 1 && config) {
38+
config.content = config.content ?? []
39+
Array.isArray(config.content) ? config.content.push('my-content') : config.content.files.push('my-file-content')
40+
}
41+
},
42+
'tailwindcss:config': (config) => {
43+
logger.info('Running `tailwindcss:config` hook...')
44+
45+
config.theme = config.theme ?? {}
46+
config.theme.extend = config.theme.extend ?? {}
47+
config.theme.extend.colors = config.theme.extend.colors ?? {}
48+
// @ts-ignore
49+
config.theme.extend.colors.twConfig = '#f0ff0f'
50+
},
51+
'tailwindcss:resolvedConfig': (config, oldConfig) => {
52+
// @ts-ignore
53+
logger.info('Running `tailwindcss:resolvedConfig` hook...', { typography: Boolean(config.theme.typography), hasOld: Boolean(oldConfig) })
54+
}
55+
} satisfies Partial<ModuleHooks>,
1756
content: {
1857
documentDriven: true
1958
},

playground/package.json

+1-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,5 @@
66
"dev": "nuxi dev",
77
"build": "nuxi build",
88
"generate": "nuxi generate"
9-
},
10-
"dependencies": {},
11-
"devDependencies": {}
9+
}
1210
}

playground/pages/index.vue

+13
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,20 @@
99
<span class="text-blue-500">meow!</span>
1010
</div>
1111
<p class="text-brand">
12+
This color comes from the `./tailwind.config`
13+
</p>
14+
<p class="text-secondary">
1215
This color comes from the `./theme` layer
1316
</p>
17+
<p class="text-accent">
18+
This color comes from the `./modules/template` module
19+
</p>
20+
<p class="text-zeroLayer">
21+
This color comes from the `tailwindcss:loadConfig` hook
22+
</p>
23+
<p class="text-twConfig">
24+
This color comes from the `tailwindcss:config` hook
25+
</p>
1426
<div>
1527
<NuxtLink
1628
to="/content"
@@ -35,5 +47,6 @@
3547
import { tw } from '#imports'
3648
import tailwindConfig from '#tailwind-config'
3749
50+
// const tw = <T>(s: T) => s
3851
const mainDivClass = tw`max-w-screen-lg p-4 mx-auto space-y-4`
3952
</script>

playground/theme/tailwind.config.cjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ module.exports = {
44
theme: {
55
extend: {
66
colors: {
7-
brand: colors.fuchsia['500']
7+
brand: colors.fuchsia['500'],
8+
secondary: colors.fuchsia['500']
89
}
910
}
1011
}

0 commit comments

Comments
 (0)