From 9d425497cb9d2b3de209808c6c02c0a7f8052d81 Mon Sep 17 00:00:00 2001 From: Inesh Bose Date: Mon, 14 Oct 2024 17:39:01 +0100 Subject: [PATCH] fix(viewer): provide workaround for nuxt2 `modules:done` serverMiddleware race condition --- src/context.ts | 17 ++++++++++------- src/module.ts | 18 +++++++++++++++--- src/viewer.ts | 7 +++---- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/context.ts b/src/context.ts index 356fe05f..1a8bd9a9 100644 --- a/src/context.ts +++ b/src/context.ts @@ -26,6 +26,7 @@ twCtx.tryUse = () => { } twCtx.set = (instance, replace = true) => { const resolvedConfig = instance && resolveConfig(instance) + // eslint-disable-next-line @typescript-eslint/no-unused-expressions resolvedConfig && useNuxt().callHook('tailwindcss:resolvedConfig', resolvedConfig, twCtx.tryUse() ?? undefined) set(resolvedConfig as unknown as TWConfig, replace) @@ -179,13 +180,13 @@ const createInternalContext = async (moduleOptions: ModuleOptions, nuxt = useNux }).filter(Boolean) return [ - `// generated by the @nuxtjs/tailwindcss module at ${(new Date()).toLocaleString()}`, - `const configMerger = require(${JSON.stringify(createResolver(import.meta.url).resolve('./runtime/merger.js'))});`, - `\nconst inlineConfig = ${serializeConfig(moduleOptions.config as Partial)};\n`, - 'const config = [', - layerConfigs.join(',\n'), - `].reduce((prev, curr) => configMerger(curr, prev), configMerger(inlineConfig, { content: { files: ${JSON.stringify(contentPaths)} } }));\n`, - `module.exports = ${configUpdatedHook['main-config'] ? `(() => {const cfg=config;${configUpdatedHook['main-config']};return cfg;})()` : 'config'}\n`, + `// generated by the @nuxtjs/tailwindcss module at ${(new Date()).toLocaleString()}`, + `const configMerger = require(${JSON.stringify(createResolver(import.meta.url).resolve('./runtime/merger.js'))});`, + `\nconst inlineConfig = ${serializeConfig(moduleOptions.config as Partial)};\n`, + 'const config = [', + layerConfigs.join(',\n'), + `].reduce((prev, curr) => configMerger(curr, prev), configMerger(inlineConfig, { content: { files: ${JSON.stringify(contentPaths)} } }));\n`, + `module.exports = ${configUpdatedHook['main-config'] ? `(() => {const cfg=config;${configUpdatedHook['main-config']};return cfg;})()` : 'config'}\n`, ].join('\n') }, }) @@ -208,10 +209,12 @@ const createInternalContext = async (moduleOptions: ModuleOptions, nuxt = useNux nuxt.hook('tailwindcss:internal:regenerateTemplates', (data) => { if (!data || !data.configTemplateUpdated) return const configFile = server.moduleGraph.getModuleById(configResolvedPath) + // eslint-disable-next-line @typescript-eslint/no-unused-expressions configFile && server.moduleGraph.invalidateModule(configFile) }) }) + // eslint-disable-next-line @typescript-eslint/no-unused-expressions moduleOptions.exposeConfig && nuxt.hook('builder:watch', async (_, path) => { if (configPaths.includes(join(nuxt.options.rootDir, path))) { twCtx.set(_loadConfig(configResolvedPath)) diff --git a/src/module.ts b/src/module.ts index a6d9bcfb..d95c7703 100644 --- a/src/module.ts +++ b/src/module.ts @@ -3,7 +3,6 @@ import { joinURL } from 'ufo' import { defineNuxtModule, installModule, - isNuxt2, getNuxtVersion, resolvePath, useNuxt, @@ -11,6 +10,7 @@ import { addImports, updateTemplates, addTemplate, + isNuxtMajorVersion, } from '@nuxt/kit' // @ts-expect-error no declaration file @@ -69,7 +69,7 @@ export default defineNuxtModule({ if (moduleOptions.editorSupport || moduleOptions.addTwUtil) { const editorSupportConfig = resolvers.resolveEditorSupportConfig(moduleOptions.editorSupport) - if ((editorSupportConfig.autocompleteUtil || moduleOptions.addTwUtil) && !isNuxt2()) { + if ((editorSupportConfig.autocompleteUtil || moduleOptions.addTwUtil) && !isNuxtMajorVersion(2, nuxt)) { addImports({ name: 'autocompleteUtil', from: createResolver(import.meta.url).resolve('./runtime/utils'), @@ -100,12 +100,17 @@ export default defineNuxtModule({ nuxt.options.css.splice(injectPosition, 0, resolvedCss) } + // workaround for nuxt2 middleware race condition + let nuxt2ViewerConfig: Parameters[0] = join(nuxt.options.buildDir, 'tailwind.config.cjs') + nuxt.hook('modules:done', async () => { const _config = await ctx.loadConfig() const twConfig = ctx.generateConfig() ctx.registerHooks() + nuxt2ViewerConfig = twConfig.dst || _config + // expose resolved tailwind config as an alias if (moduleOptions.exposeConfig) { const exposeConfig = resolvers.resolveExposeConfig({ level: moduleOptions.exposeLevel, ...(typeof moduleOptions.exposeConfig === 'object' ? moduleOptions.exposeConfig : {}) }) @@ -128,7 +133,7 @@ export default defineNuxtModule({ } // enabled only in development - if (nuxt.options.dev) { + if (nuxt.options.dev && !isNuxtMajorVersion(2, nuxt)) { // add tailwind-config-viewer endpoint if (moduleOptions.viewer) { const viewerConfig = resolvers.resolveViewerConfig(moduleOptions.viewer) @@ -150,6 +155,8 @@ export default defineNuxtModule({ } else { // production only + if (!nuxt.options.dev) return + if (moduleOptions.viewer) { const viewerConfig = resolvers.resolveViewerConfig(moduleOptions.viewer) @@ -157,6 +164,11 @@ export default defineNuxtModule({ } } }) + + if (nuxt.options.dev && moduleOptions.viewer && isNuxtMajorVersion(2, nuxt)) { + const viewerConfig = resolvers.resolveViewerConfig(moduleOptions.viewer) + setupViewer(nuxt2ViewerConfig, viewerConfig, nuxt) + } }, }) diff --git a/src/viewer.ts b/src/viewer.ts index 9523c00b..33585681 100644 --- a/src/viewer.ts +++ b/src/viewer.ts @@ -1,6 +1,6 @@ import { colors } from 'consola/utils' import { eventHandler, sendRedirect, H3Event } from 'h3' -import { addDevServerHandler, isNuxt2, isNuxt3, useNuxt } from '@nuxt/kit' +import { addDevServerHandler, isNuxtMajorVersion, useNuxt } from '@nuxt/kit' import { withTrailingSlash, withoutTrailingSlash, joinURL, cleanDoubleSlashes } from 'ufo' import loadConfig from 'tailwindcss/loadConfig.js' import { relative } from 'pathe' @@ -15,7 +15,7 @@ export const setupViewer = async (twConfig: string | TWConfig, config: ViewerCon const viewerServer = (await import('tailwind-config-viewer/server/index.js').then(r => r.default || r))({ tailwindConfigProvider: typeof twConfig === 'string' ? () => loadConfig(twConfig) : () => twConfig }).asMiddleware() const viewerDevMiddleware = eventHandler(event => viewerServer(event.node?.req || event.req, event.node?.res || event.res)) - if (isNuxt3()) { + if (!isNuxtMajorVersion(2, nuxt)) { addDevServerHandler({ handler: eventHandler((event) => { if (event.path === routeWithoutSlash) { @@ -25,8 +25,7 @@ export const setupViewer = async (twConfig: string | TWConfig, config: ViewerCon }) addDevServerHandler({ route, handler: viewerDevMiddleware }) } - - if (isNuxt2()) { + else { // @ts-expect-error untyped nuxt2 property nuxt.options.serverMiddleware.push( // @ts-expect-error untyped handler parameters