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: add a module option to disable tailwind global style injection in all pages #850

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export default defineAppConfig({
prose: {
code: {
icon: {
'nuxt.config': 'vscode-icons:file-type-nuxt'
}
}
}
}
'nuxt.config': 'vscode-icons:file-type-nuxt',
},
},
},
},
},
header: {
logo: {
Expand Down
6 changes: 5 additions & 1 deletion docs/components/AppFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ const { footer } = useAppConfig()
<UFooter>
<template #left>
<span class="text-sm text-gray-500 dark:text-gray-400">
© 2024 | <NuxtLink to="https://github.com/nuxt-modules/tailwindcss/blob/main/LICENSE" target="_blank" class="text-gray-900 dark:text-white">MIT License</NuxtLink> | v{{ footer.pkgVersion }}
© 2024 | <NuxtLink
to="https://github.com/nuxt-modules/tailwindcss/blob/main/LICENSE"
target="_blank"
class="text-gray-900 dark:text-white"
>MIT License</NuxtLink> | v{{ footer.pkgVersion }}
</span>
</template>

Expand Down
5 changes: 4 additions & 1 deletion docs/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ const { header } = useAppConfig()
<TailwindText class="h-3.5" />
</template>

<template v-if="header?.search" #center>
<template
v-if="header?.search"
#center
>
<UContentSearchButton class="hidden lg:flex" />
</template>

Expand Down
5 changes: 4 additions & 1 deletion docs/components/TailwindText.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 377.44 55.32">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 377.44 55.32"
>
<path
fill="currentColor"
d="M24.12,24.87H14.89V42.73c0,4.77,3.13,4.69,9.23,4.4v7.22C11.76,55.84,6.85,52.41,6.85,42.73V24.87H0V17.12H6.85v-10l8-2.38V17.12h9.23Zm35.19-7.75h8V54.35h-8V49c-2.83,3.94-7.22,6.33-13,6.33-10.12,0-18.53-8.57-18.53-19.58s8.41-19.58,18.54-19.58c5.8,0,10.2,2.38,13,6.25ZM47.55,47.65A11.5,11.5,0,0,0,59.31,35.74,11.5,11.5,0,0,0,47.55,23.83,11.5,11.5,0,0,0,35.79,35.74,11.5,11.5,0,0,0,47.55,47.65ZM80.76,11.54A5.2,5.2,0,0,1,75.62,6.4a5.14,5.14,0,1,1,10.27,0A5.19,5.19,0,0,1,80.76,11.54Zm-4,42.81V17.12h8V54.35Zm17.34,0V0h8V54.35Zm60.23-37.23h8.49L151.11,54.35h-7.89l-7.75-25.09-7.81,25.09h-7.89L108.08,17.12h8.49l7.22,25.69,7.81-25.69h7.67L147,42.81Zm18.47-5.58a5.2,5.2,0,0,1-5.14-5.14,5.14,5.14,0,1,1,10.27,0A5.19,5.19,0,0,1,172.78,11.54Zm-4,42.81V17.12h8V54.35Zm36.92-38.2c8.34,0,14.3,5.66,14.3,15.34V54.35h-8v-22c0-5.66-3.28-8.63-8.34-8.63-5.29,0-9.46,3.12-9.46,10.72v20h-8V17.12h8v4.77c2.46-3.87,6.48-5.74,11.54-5.74ZM258.1,2.23h8V54.35h-8V49c-2.83,3.94-7.23,6.33-13,6.33-10.13,0-18.54-8.57-18.54-19.58s8.41-19.58,18.54-19.58c5.8,0,10.2,2.38,13,6.25ZM246.33,47.65a11.5,11.5,0,0,0,11.76-11.91,11.76,11.76,0,1,0-23.52,0A11.5,11.5,0,0,0,246.33,47.65Zm46.76,7.67a19.26,19.26,0,0,1-19.66-19.58,19.2,19.2,0,0,1,19.66-19.58,18.39,18.39,0,0,1,16.6,9.6l-6.93,4c-1.63-3.5-5.28-5.73-9.75-5.73a11.36,11.36,0,0,0-11.54,11.69A11.35,11.35,0,0,0,293,47.42a10.9,10.9,0,0,0,9.9-5.73l6.93,4a18.73,18.73,0,0,1-16.75,9.68Zm30-27.92c0,6.77,20,2.68,20,16.45,0,7.45-6.48,11.47-14.52,11.47-7.45,0-12.81-3.35-15.19-8.71l6.92-4c1.2,3.35,4.17,5.36,8.27,5.36,3.57,0,6.33-1.19,6.33-4.17,0-6.63-20-2.91-20-16.23,0-7,6-11.39,13.62-11.39,6.11,0,11.17,2.83,13.78,7.74l-6.78,3.8a7.25,7.25,0,0,0-7-4.25c-2.9,0-5.43,1.27-5.43,3.95Zm34.32,0c0,6.77,20,2.68,20,16.45,0,7.45-6.48,11.47-14.52,11.47-7.45,0-12.81-3.35-15.19-8.71l6.92-4c1.2,3.35,4.17,5.36,8.27,5.36,3.57,0,6.33-1.19,6.33-4.17,0-6.63-20-2.91-20-16.23,0-7,6-11.39,13.62-11.39C369,16.16,374,19,376.62,23.9l-6.78,3.8a7.24,7.24,0,0,0-7-4.25c-2.91,0-5.44,1.27-5.44,3.95Z"
Expand Down
6 changes: 5 additions & 1 deletion docs/components/TheLogo.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 512 512">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 512 512"
>
<path
d="M281.4 397.7h156.9c5 0 9.8-1.8 14.1-4.2 4.3-2.5 8.8-5.6 11.3-9.9 2.5-4.3 4.2-9.2 4.2-14.1 0-5-1.7-9.8-4.2-14.1l-106-182.3c-2.5-4.3-5.6-7.4-9.9-9.9-4.3-2.5-10.5-4.2-15.5-4.2s-9.8 1.8-14.1 4.2c-4.3 2.5-7.4 5.6-9.9 9.9l-26.9 46.6-53.7-90.5c-2.5-4.3-5.6-8.8-9.9-11.3-4.3-2.5-9.1-2.8-14.1-2.8s-9.8.3-14.1 2.8c-4.3 2.5-8.8 7-11.3 11.3L46.8 355.3c-2.5 4.3-2.8 9.2-2.8 14.1 0 5 .3 9.8 2.8 14.1 2.5 4.3 7 7.4 11.3 9.9 4.3 2.5 9.1 4.2 14.1 4.2h98.9c39.2 0 67.7-17.6 87.6-50.9l48.1-83.4 25.4-43.8 77.7 132.9h-103l-25.5 45.3zm-111.6-45.3h-69.3l103.2-178.1 52.3 89-34.6 60.4c-13.2 21.7-28.3 28.7-51.6 28.7z"
style="fill: #00dc82"
Expand Down
2 changes: 1 addition & 1 deletion docs/tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default <Partial<Config>>{
900: '#0A5331',
950: '#052e16',
},
tailwind: '#38bdf8'
tailwind: '#38bdf8',
},
},
},
Expand Down
1 change: 1 addition & 0 deletions playground/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default defineNuxtConfig({
// viewer: false,
config: {},
exposeConfig: true,
lazy: true,
cssPath: '~/assets/css/tailwind.css',
editorSupport: true,
} satisfies Partial<ModuleOptions>,
Expand Down
19 changes: 19 additions & 0 deletions playground/pages/lazy.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div>
<p class="bg-black text-white rounded-md">
Lazy load tailwind:
</p>
<button
type="button"
@click="loadTailwindStyles"
>
Load tailwind styles
</button>
</div>
</template>

<script setup>
import { useTailwind } from '#imports'

const { loadTailwindStyles } = useTailwind()
</script>
44 changes: 23 additions & 21 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const unsafeInlineConfig = (inlineConfig: ModuleOptions['config']) => {
}

if (inlineConfig.content) {
const invalidProperty = ['extract', 'transform'].find((i) => i in inlineConfig.content! && typeof inlineConfig.content![i as keyof ModuleOptions['config']['content']] === 'function' )
const invalidProperty = ['extract', 'transform'].find(i => i in inlineConfig.content! && typeof inlineConfig.content![i as keyof ModuleOptions['config']['content']] === 'function')

if (invalidProperty) {
return `content.${invalidProperty}`
Expand All @@ -51,7 +51,7 @@ const unsafeInlineConfig = (inlineConfig: ModuleOptions['config']) => {

if (inlineConfig.safelist) {
// @ts-expect-error `s` is never
const invalidIdx = inlineConfig.safelist.findIndex((s) => typeof s === 'object' && s.pattern instanceof RegExp)
const invalidIdx = inlineConfig.safelist.findIndex(s => typeof s === 'object' && s.pattern instanceof RegExp)

if (invalidIdx > -1) {
return `safelist[${invalidIdx}]`
Expand Down Expand Up @@ -156,32 +156,34 @@ const createInternalContext = async (moduleOptions: ModuleOptions, nuxt = useNux
return tailwindConfig
}

const generateConfig = () => enableHMR ? addTemplate({
filename: CONFIG_TEMPLATE_NAME,
write: true,
getContents: () => {
const serializeConfig = <T extends Partial<TWConfig>>(config: T) =>
JSON.stringify(
Array.isArray(config.plugins) && config.plugins.length > 0 ? configMerger({ plugins: (defaultPlugins: TWConfig['plugins']) => defaultPlugins?.filter(p => p && typeof p !== 'function') }, config) : config,
(_, v) => typeof v === 'function' ? `() => (${JSON.stringify(v())})` : v
).replace(/"(\(\) => \(.*\))"/g, (_, substr) => substr.replace(/\\"/g, '"'))

const layerConfigs = configPaths.map((configPath) => {
const configImport = `require(${JSON.stringify(/[/\\]node_modules[/\\]/.test(configPath) ? configPath : './' + relative(nuxt.options.buildDir, configPath))})`
return configUpdatedHook[configPath] ? configUpdatedHook[configPath].startsWith('return {};') ? '' : `(() => {const cfg=configMerger(undefined, ${configImport});${configUpdatedHook[configPath]};return cfg;})()` : configImport
}).filter(Boolean)

return [
const generateConfig = () => enableHMR
? addTemplate({
filename: CONFIG_TEMPLATE_NAME,
write: true,
getContents: () => {
const serializeConfig = <T extends Partial<TWConfig>>(config: T) =>
JSON.stringify(
Array.isArray(config.plugins) && config.plugins.length > 0 ? configMerger({ plugins: (defaultPlugins: TWConfig['plugins']) => defaultPlugins?.filter(p => p && typeof p !== 'function') }, config) : config,
(_, v) => typeof v === 'function' ? `() => (${JSON.stringify(v())})` : v,
).replace(/"(\(\) => \(.*\))"/g, (_, substr) => substr.replace(/\\"/g, '"'))

const layerConfigs = configPaths.map((configPath) => {
const configImport = `require(${JSON.stringify(/[/\\]node_modules[/\\]/.test(configPath) ? configPath : './' + relative(nuxt.options.buildDir, configPath))})`
return configUpdatedHook[configPath] ? configUpdatedHook[configPath].startsWith('return {};') ? '' : `(() => {const cfg=configMerger(undefined, ${configImport});${configUpdatedHook[configPath]};return cfg;})()` : configImport
}).filter(Boolean)

return [
`// generated by the @nuxtjs/tailwindcss <https://github.com/nuxt-modules/tailwindcss> module at ${(new Date()).toLocaleString()}`,
`const configMerger = require(${JSON.stringify(createResolver(import.meta.url).resolve('./runtime/merger.mjs'))});`,
`\nconst inlineConfig = ${serializeConfig(moduleOptions.config as Partial<TWConfig>)};\n`,
'const config = [',
layerConfigs.join(',\n'),
`].reduce((prev, curr) => configMerger(curr, prev), configMerger(inlineConfig, { content: ${JSON.stringify(contentPaths)} }));\n`,
`module.exports = ${configUpdatedHook['main-config'] ? `(() => {const cfg=config;${configUpdatedHook['main-config']};return cfg;})()` : 'config'}\n`,
].join('\n')
},
}) : { dst: '' }
].join('\n')
},
})
: { dst: '' }

const registerHooks = () => {
if (!enableHMR) return
Expand Down
19 changes: 16 additions & 3 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
createResolver,
addImports,
updateTemplates,
addTemplate,
addTemplate, addImportsDir,
} from '@nuxt/kit'

// @ts-expect-error no declaration file
Expand Down Expand Up @@ -43,6 +43,7 @@ const deprecationWarnings = (moduleOptions: ModuleOptions, nuxt = useNuxt()) =>
const defaults = (nuxt = useNuxt()): ModuleOptions => ({
configPath: 'tailwind.config',
cssPath: join(nuxt.options.dir.assets, 'css/tailwind.css'),
lazy: false,
config: defaultTailwindConfig,
viewer: true,
exposeConfig: false,
Expand All @@ -54,6 +55,9 @@ export default defineNuxtModule<ModuleOptions>({
meta: { name, version, configKey, compatibility }, defaults,
async setup(moduleOptions, nuxt) {
if (moduleOptions.quiet) logger.level = LogLevels.silent

const resolver = createResolver(import.meta.url)

deprecationWarnings(moduleOptions, nuxt)

// install postcss8 module on nuxt < 2.16
Expand All @@ -72,13 +76,15 @@ export default defineNuxtModule<ModuleOptions>({
if ((editorSupportConfig.autocompleteUtil || moduleOptions.addTwUtil) && !isNuxt2()) {
addImports({
name: 'autocompleteUtil',
from: createResolver(import.meta.url).resolve('./runtime/utils'),
from: resolver.resolve('./runtime/utils'),
as: 'tw',
...(typeof editorSupportConfig.autocompleteUtil === 'object' ? editorSupportConfig.autocompleteUtil : {}),
})
}
}

addImportsDir(resolver.resolve('./runtime/composables'))

// css file handling
const [cssPath, cssPathConfig] = Array.isArray(moduleOptions.cssPath) ? moduleOptions.cssPath : [moduleOptions.cssPath]
const [resolvedCss, loggerInfo] = await resolvers.resolveCSSPath(cssPath, nuxt)
Expand All @@ -87,8 +93,15 @@ export default defineNuxtModule<ModuleOptions>({
nuxt.options.css = nuxt.options.css ?? []
const resolvedNuxtCss = (resolvedCss && await Promise.all(nuxt.options.css.map((p: any) => resolvePath(p.src ?? p)))) || []

nuxt.options.alias['#tailwind/styles-path'] = addTemplate({
filename: 'tailwind.stylesPath.js',
getContents: () => {
return `export default '${resolvedCss || ''}' || null`
},
}).dst

// inject only if this file isn't listed already by user
if (resolvedCss && !resolvedNuxtCss.includes(resolvedCss)) {
if (!moduleOptions.lazy && resolvedCss && !resolvedNuxtCss.includes(resolvedCss)) {
let injectPosition: number
try {
injectPosition = resolvers.resolveInjectPosition(nuxt.options.css, cssPathConfig?.injectPosition || moduleOptions.injectPosition)
Expand Down
18 changes: 18 additions & 0 deletions src/runtime/composables/useTailwind.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useHead } from '#imports'
import tailwindStylesSrc from '#tailwind/styles-path'

type TailwindModuleUtilities = {
loadTailwindStyles: () => void
}

export default function useTailwind(): TailwindModuleUtilities {
return {
loadTailwindStyles() {
useHead({
style: [
{ src: tailwindStylesSrc, key: '__tailwind.styles', type: 'text/css' },
],
})
},
}
}
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ export interface ModuleOptions {
* @default 'tailwind.config'
*/
configPath: string | string[]
/**
* Make tailwind styles manual, you will need to use the "useTailwind" composable to inject the styles when you need them.
*
* @default false
*/
lazy: boolean
/**
* The path of the Tailwind CSS file. If the file does not exist, the module's default CSS file will be imported instead.
*
Expand Down
1 change: 0 additions & 1 deletion test/sink.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ describe.skipIf(!existsSync(fixturePath))('nuxt.com', async () => {
beforeAll(() => {
const generateCommand = exec(`cd ${fixturePath} && pnpm generate`)

// eslint-disable-next-line no-constant-condition
while (true) {
if (
existsSync(`${fixturePath}.output/public/index.html`)
Expand Down