feat: migrate module to Nuxt 4 and add Tailwind v4 support#1280
feat: migrate module to Nuxt 4 and add Tailwind v4 support#1280Jeanspkdz wants to merge 4 commits intopingdotgg:mainfrom
Conversation
🦋 Changeset detectedLatest commit: 12dd75c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@Jeanspkdz is attempting to deploy a commit to the Ping Labs Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughMigrates Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer (build/dev)
participant NuxtModule as Nuxt Module
participant FileRouter as User fileRouter
participant Generator as Build-time Generator
participant NuxtRuntime as Nuxt Runtime
Dev->>NuxtModule: run nuxt dev/build
NuxtModule->>FileRouter: resolve & import `fileRouterPath`/`fileRouterExport`
FileRouter-->>NuxtModule: router definitions (types/exports)
NuxtModule->>Generator: generate typed components, helpers, API handler, CSS
Generator-->>NuxtModule: emit artifacts (TS/MJS/CSS)
NuxtModule->>NuxtRuntime: register components, alias `#ut-router`, inject runtime config, expose generated /api/uploadthing
NuxtRuntime-->>Dev: runtime with generated components + API handler available
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
Greptile SummaryThis PR migrates
Confidence Score: 3/5Not safe to merge without addressing the two P1 issues: missing CSS fallback and wrong package name in docs. Two P1 defects: the Tailwind v3 path leaves components completely unstyled in production, and the README install command points to a non-existent package name, making the docs immediately broken for new users. packages/nuxt/src/module.ts (Tailwind v3 CSS fallback) and packages/nuxt/README.md (package name). Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Nuxt Module Setup] --> B[Resolve fileRouterPath]
B --> C{Router file exists?}
C -- No --> D[Alias #ut-router → empty stub]
C -- Yes --> E[Alias #ut-router → user file]
D & E --> F[applyUploadthingStyles]
F --> G{useTailwindStyles?}
G -- false --> H[registerUploadthingCss\npush @uploadthing/vue/styles.css]
G -- true --> I[getTailwindVersion]
I --> J{Version?}
J -- null --> K[warn + registerUploadthingCss]
J -- 3 --> L[warn only ⚠️ no CSS applied]
J -- 4 --> M[resolveUploadthingVueDist]
M --> N{dist found?}
N -- No --> O[warn + registerUploadthingCss]
N -- Yes --> P[registerUploadthingTailwindCss\n@import uploadthing/tw/v4]
F --> Q[generateUploadthingArtifacts]
Q --> R[addTemplate upload-button.ts]
Q --> S[addTemplate upload-dropzone.ts]
Q --> T[addTemplate upload-helpers.ts]
Q --> U[addTemplate server handler]
U --> V[addServerHandler /api/uploadthing]
Q --> W[addComponentsDir runtime/components]
Q --> X[addImportsDir runtime/utils]
Prompt To Fix All With AIThis is a comment left during a code review.
Path: packages/nuxt/src/module.ts
Line: 155-160
Comment:
**Missing CSS fallback for Tailwind v3**
When `useTailwindStyles: true` and Tailwind v3 is detected, the function logs a warning and returns without applying *any* CSS. Components will be completely unstyled unless the user also manually sets up `withUt`. The other two error branches both call `registerUploadthingCss()` as a fallback, but this branch does not.
```suggestion
if (tailwindVersion === '3') {
logger.warn(
'[nuxt-uploadthing] Tailwind CSS v3 detected. To enable UploadThing Tailwind integration, wrap your Tailwind config with `withUt` from "uploadthing/tw". See: https://docs.uploadthing.com/concepts/theming#configuring-tailwind-css. Falling back to default UploadThing CSS.',
)
return registerUploadthingCss()
}
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: packages/nuxt/README.md
Line: 69-71
Comment:
**Wrong package name in install instructions**
The README tells users to install `nuxt-uploadthing`, but `package.json` still declares `"name": "@uploadthing/nuxt"` and the changeset also references `@uploadthing/nuxt`. The badges at the top also link to the `nuxt-uploadthing` npm slug, which would 404 unless this package is being renamed (but the package.json has not changed its `name` field).
```suggestion
pnpm add @uploadthing/nuxt uploadthing
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: packages/nuxt/src/module.ts
Line: 316-339
Comment:
**`createRouteHandler` reconstructed on every request**
`createRouteHandler(...)` is called inside `defineEventHandler`, so a new handler is instantiated for every incoming HTTP request. This is wasteful (potential connection pooling, middleware setup, etc. repeated per request). The handler should be created once outside the event handler and reused.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: packages/nuxt/src/module.ts
Line: 113-117
Comment:
**Leftover commented-out code**
Two stale comments remain in the module — `// const _require = createRequire(import.meta.url)` here and `// const relativeDist = ...` / `// return relativeDist` in `resolveUploadthingVueDist`. These should be removed before merging.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat: migrate module to Nuxt 4 and add T..." | Re-trigger Greptile |
| if (tailwindVersion === '3') { | ||
| logger.warn( | ||
| '[nuxt-uploadthing] Tailwind CSS v3 detected. To enable UploadThing Tailwind integration, wrap your Tailwind config with `withUt` from "uploadthing/tw". See: https://docs.uploadthing.com/concepts/theming#configuring-tailwind-css.', | ||
| ) | ||
| return | ||
| } |
There was a problem hiding this comment.
Missing CSS fallback for Tailwind v3
When useTailwindStyles: true and Tailwind v3 is detected, the function logs a warning and returns without applying any CSS. Components will be completely unstyled unless the user also manually sets up withUt. The other two error branches both call registerUploadthingCss() as a fallback, but this branch does not.
| if (tailwindVersion === '3') { | |
| logger.warn( | |
| '[nuxt-uploadthing] Tailwind CSS v3 detected. To enable UploadThing Tailwind integration, wrap your Tailwind config with `withUt` from "uploadthing/tw". See: https://docs.uploadthing.com/concepts/theming#configuring-tailwind-css.', | |
| ) | |
| return | |
| } | |
| if (tailwindVersion === '3') { | |
| logger.warn( | |
| '[nuxt-uploadthing] Tailwind CSS v3 detected. To enable UploadThing Tailwind integration, wrap your Tailwind config with `withUt` from "uploadthing/tw". See: https://docs.uploadthing.com/concepts/theming#configuring-tailwind-css. Falling back to default UploadThing CSS.', | |
| ) | |
| return registerUploadthingCss() | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/nuxt/src/module.ts
Line: 155-160
Comment:
**Missing CSS fallback for Tailwind v3**
When `useTailwindStyles: true` and Tailwind v3 is detected, the function logs a warning and returns without applying *any* CSS. Components will be completely unstyled unless the user also manually sets up `withUt`. The other two error branches both call `registerUploadthingCss()` as a fallback, but this branch does not.
```suggestion
if (tailwindVersion === '3') {
logger.warn(
'[nuxt-uploadthing] Tailwind CSS v3 detected. To enable UploadThing Tailwind integration, wrap your Tailwind config with `withUt` from "uploadthing/tw". See: https://docs.uploadthing.com/concepts/theming#configuring-tailwind-css. Falling back to default UploadThing CSS.',
)
return registerUploadthingCss()
}
```
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| 2. Mount a component in your app and start uploading files: | ||
| 3) Use generated components anywhere in your app | ||
|
|
There was a problem hiding this comment.
Wrong package name in install instructions
The README tells users to install nuxt-uploadthing, but package.json still declares "name": "@uploadthing/nuxt" and the changeset also references @uploadthing/nuxt. The badges at the top also link to the nuxt-uploadthing npm slug, which would 404 unless this package is being renamed (but the package.json has not changed its name field).
| 2. Mount a component in your app and start uploading files: | |
| 3) Use generated components anywhere in your app | |
| pnpm add @uploadthing/nuxt uploadthing |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/nuxt/README.md
Line: 69-71
Comment:
**Wrong package name in install instructions**
The README tells users to install `nuxt-uploadthing`, but `package.json` still declares `"name": "@uploadthing/nuxt"` and the changeset also references `@uploadthing/nuxt`. The badges at the top also link to the `nuxt-uploadthing` npm slug, which would 404 unless this package is being renamed (but the package.json has not changed its `name` field).
```suggestion
pnpm add @uploadthing/nuxt uploadthing
```
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| const emptyStringToUndefined = (obj) => { | ||
| const next = {} | ||
| for (const key in obj) { | ||
| next[key] = obj[key] === '' ? undefined : obj[key] | ||
| } | ||
| return next | ||
| } | ||
|
|
||
| export default defineEventHandler((event) => { | ||
| const runtime = useRuntimeConfig() | ||
| const config = emptyStringToUndefined(runtime.uploadthing?.routeHandlerConfig ?? {}) | ||
| const hasConfig = Object.keys(config).length > 0 | ||
|
|
||
|
|
||
| const router = RouterModule[ROUTER_EXPORT] | ||
| if (!router) { | ||
| throw new Error('[nuxt-uploadthing] Router export not found: ' + ROUTER_EXPORT) | ||
| } | ||
|
|
||
| return createRouteHandler({ | ||
| router, | ||
| ...(hasConfig ? { config } : {}), | ||
| })(event) |
There was a problem hiding this comment.
createRouteHandler reconstructed on every request
createRouteHandler(...) is called inside defineEventHandler, so a new handler is instantiated for every incoming HTTP request. This is wasteful (potential connection pooling, middleware setup, etc. repeated per request). The handler should be created once outside the event handler and reused.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/nuxt/src/module.ts
Line: 316-339
Comment:
**`createRouteHandler` reconstructed on every request**
`createRouteHandler(...)` is called inside `defineEventHandler`, so a new handler is instantiated for every incoming HTTP request. This is wasteful (potential connection pooling, middleware setup, etc. repeated per request). The handler should be created once outside the event handler and reused.
How can I resolve this? If you propose a fix, please make it concise.| function getTailwindVersion(): '3' | '4' | null { | ||
| try { | ||
| const nuxt = useNuxt() | ||
| // const _require = createRequire(import.meta.url) | ||
| const _require = createRequire(nuxt.options.rootDir + '/') |
There was a problem hiding this comment.
Two stale comments remain in the module — // const _require = createRequire(import.meta.url) here and // const relativeDist = ... / // return relativeDist in resolveUploadthingVueDist. These should be removed before merging.
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/nuxt/src/module.ts
Line: 113-117
Comment:
**Leftover commented-out code**
Two stale comments remain in the module — `// const _require = createRequire(import.meta.url)` here and `// const relativeDist = ...` / `// return relativeDist` in `resolveUploadthingVueDist`. These should be removed before merging.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/nuxt/package.json (1)
58-60:⚠️ Potential issue | 🟠 MajorAdd Nuxt to peerDependencies to match framework integration pattern.
All other framework-specific packages in this workspace declare their framework as a peer dependency (
@uploadthing/react,@uploadthing/vue,@uploadthing/svelte,@uploadthing/solid,@uploadthing/expo). The Nuxt package should do the same, especially since it:
- Imports Nuxt runtime APIs (
defineNuxtModule,useNuxt) from@nuxt/kitin its dependencies- Just migrated to Nuxt 4+ as a breaking change
- Needs to signal the Nuxt version requirement at install time
Proposed fix
"peerDependencies": { + "nuxt": "^4.0.0", "uploadthing": "^7.2.0" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxt/package.json` around lines 58 - 60, The Nuxt package.json is missing Nuxt as a peerDependency; update the "peerDependencies" block in package.json to declare "nuxt" with an appropriate range (e.g. "^4.0.0" or ">=4 <5") so installs will warn about the required Nuxt major; this aligns with other framework packages and the fact the code imports Nuxt runtime APIs (defineNuxtModule, useNuxt) from `@nuxt/kit` and was migrated to Nuxt 4+. Ensure the peerDependencies entry is added alongside "uploadthing" under the existing peerDependencies object.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/nuxt/README.md`:
- Around line 41-42: The docs show inconsistent casing for the componentPrefix
option: replace the lowercase variant with the exact casing used elsewhere so
examples match; update occurrences of componentPrefix values that read
"Uploadthing" to "UploadThing" (search for the symbol componentPrefix and the
example values to locate and unify them) so generated component names described
in the README are consistent across examples.
- Around line 25-26: Replace all instances of the incorrect package identifier
"nuxt-uploadthing" with the canonical scoped name "@uploadthing/nuxt" throughout
the README: update the install command to "pnpm add `@uploadthing/nuxt`
uploadthing", fix module config examples and any comments referencing
"nuxt-uploadthing", and update npm badge URLs/text to point to the scoped
package "@uploadthing/nuxt" so examples and links match the package manifest.
In `@packages/nuxt/src/module.ts`:
- Around line 195-202: registerUploadthingTailwindCss currently generates
uploadthing-tw.css via addTemplate but never registers it with Nuxt's CSS
pipeline; after the addTemplate call in registerUploadthingTailwindCss, push the
generated CSS into nuxt.options.css (e.g.
nuxt.options.css.push(resolver.resolve('./runtime/uploadthing-tw.css'))),
mirroring the pattern used in registerUploadthingCss (which calls
nuxt.options.css.push('@uploadthing/vue/styles.css')) so the Tailwind v4
stylesheet is actually loaded by Nuxt.
- Around line 231-235: The generated artifacts (upload-button, dropzone,
helpers, CSS, and import entries) are being written directly into the package
source via dst: resolver.resolve('./runtime/...'), which breaks immutable
installs; instead, call addTemplate(...) without forcing a src package path,
capture the returned template objects (e.g., the result of addTemplate for
'upload-button.ts' and other files), then use each template.dst value when
registering components/imports (mirror the server handler pattern used around
the server handler code that already uses template.dst); update usages in
addComponentsDir, addImportsDir and CSS registration to reference those
template.dst paths rather than resolver.resolve('./runtime/...') so Nuxt emits
into its build output directory.
---
Outside diff comments:
In `@packages/nuxt/package.json`:
- Around line 58-60: The Nuxt package.json is missing Nuxt as a peerDependency;
update the "peerDependencies" block in package.json to declare "nuxt" with an
appropriate range (e.g. "^4.0.0" or ">=4 <5") so installs will warn about the
required Nuxt major; this aligns with other framework packages and the fact the
code imports Nuxt runtime APIs (defineNuxtModule, useNuxt) from `@nuxt/kit` and
was migrated to Nuxt 4+. Ensure the peerDependencies entry is added alongside
"uploadthing" under the existing peerDependencies object.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0ffe732f-77a3-4b19-9333-181b32ef60e6
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (14)
.changeset/beige-camels-shout.mdpackages/nuxt/.nuxtrcpackages/nuxt/README.mdpackages/nuxt/eslint.config.jspackages/nuxt/package.jsonpackages/nuxt/postbuild.tspackages/nuxt/src/module.tspackages/nuxt/src/runtime/components/button.tspackages/nuxt/src/runtime/components/dropzone.tspackages/nuxt/src/runtime/composables/useUploadThing.tspackages/nuxt/src/runtime/server/api/uploadthing.tspackages/nuxt/src/runtime/server/router.tspackages/nuxt/src/runtime/uploadthing-tw.csspackages/nuxt/tsconfig.json
💤 Files with no reviewable changes (5)
- packages/nuxt/src/runtime/composables/useUploadThing.ts
- packages/nuxt/src/runtime/components/button.ts
- packages/nuxt/src/runtime/server/api/uploadthing.ts
- packages/nuxt/src/runtime/components/dropzone.ts
- packages/nuxt/postbuild.ts
| function registerUploadthingTailwindCss(distPath: string) { | ||
| addTemplate({ | ||
| write: true, | ||
| filename: 'uploadthing-tw.css', | ||
| dst: resolver.resolve('./runtime/uploadthing-tw.css'), | ||
| getContents: () => | ||
| `@import "uploadthing/tw/v4";\n@source "${distPath}";\n`, | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the actual file and the specific lines mentioned
cd /tmp/repo && head -250 packages/nuxt/src/module.ts | tail -100Repository: pingdotgg/uploadthing
Length of output: 125
🏁 Script executed:
# Get the complete context around the registerUploadthingTailwindCss function
cat -n packages/nuxt/src/module.ts | sed -n '190,210p'Repository: pingdotgg/uploadthing
Length of output: 817
🏁 Script executed:
# Search for registerUploadthingCss to see how it handles CSS registration (for comparison)
rg -A 10 "function registerUploadthingCss" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 389
🏁 Script executed:
# Search for useTailwindStyles to understand the flow
rg -B 5 -A 10 "useTailwindStyles" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 1941
🏁 Script executed:
# Check if addTemplate is used elsewhere with CSS registration
rg -B 2 -A 5 "nuxt.options.css" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 249
🏁 Script executed:
# Let's see the complete applyUploadthingStyles function to understand the full flow
rg -A 30 "function applyUploadthingStyles" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 1171
🏁 Script executed:
# Check if registerUploadthingTailwindCss is actually called and from where
rg "registerUploadthingTailwindCss" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 164
🏁 Script executed:
# Let's see the full registerUploadthingCss function for comparison
rg -A 15 "function registerUploadthingCss" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 431
🏁 Script executed:
# Get the complete registerUploadthingCss function
cat -n packages/nuxt/src/module.ts | sed -n '185,203p'Repository: pingdotgg/uploadthing
Length of output: 679
🏁 Script executed:
# Look for any implicit CSS registration mechanism or higher-level registration
rg -B 10 "applyUploadthingStyles()" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 411
🏁 Script executed:
# Let's see if addTemplate return value is used elsewhere with CSS
rg -B 5 -A 5 "const.*=.*addTemplate" packages/nuxt/src/module.ts | head -50Repository: pingdotgg/uploadthing
Length of output: 393
🏁 Script executed:
# Check if there's any automatic CSS discovery or scanning mechanism
rg "\.css|CSS" packages/nuxt/src/module.ts | grep -v "uploadthing-tw.css" | head -20Repository: pingdotgg/uploadthing
Length of output: 949
🏁 Script executed:
# Look for any Nuxt hooks or build-time processing that might handle templates
rg "addTemplate|useNuxt" packages/nuxt/src/module.ts | head -30Repository: pingdotgg/uploadthing
Length of output: 470
🏁 Script executed:
# Let's look at the complete applyUploadthingStyles to see how registerUploadthingTailwindCss is called
cat -n packages/nuxt/src/module.ts | sed -n '145,180p'Repository: pingdotgg/uploadthing
Length of output: 1486
🏁 Script executed:
# Check how addTemplate is used in the uploadthingHandlerTemplate (which has a return value assigned)
cat -n packages/nuxt/src/module.ts | sed -n '105,135p'Repository: pingdotgg/uploadthing
Length of output: 1133
🏁 Script executed:
# Let's see if uploadthingHandlerTemplate is used after assignment
rg "uploadthingHandlerTemplate" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 161
🏁 Script executed:
# Let's check Nuxt's addTemplate documentation or comments in the codebase about how templates work
rg -B 3 "addTemplate" packages/nuxt/src/module.ts | grep -A 3 "^--$" | head -30Repository: pingdotgg/uploadthing
Length of output: 446
🏁 Script executed:
# Let's see if there's a pattern where template.dst is used with nuxt.options.css elsewhere
rg -B 2 -A 2 "template\.dst" packages/nuxt/src/module.tsRepository: pingdotgg/uploadthing
Length of output: 47
🏁 Script executed:
# Check what the addTemplate return type looks like by examining how uploadthingHandlerTemplate is used
cat -n packages/nuxt/src/module.ts | sed -n '65,100p'Repository: pingdotgg/uploadthing
Length of output: 1276
Register the generated Tailwind CSS file with Nuxt's CSS pipeline.
registerUploadthingTailwindCss() generates uploadthing-tw.css but never adds it to nuxt.options.css. Unlike registerUploadthingCss() (which calls nuxt.options.css.push('@uploadthing/vue/styles.css')), the Tailwind variant omits this registration, so the generated stylesheet is never loaded by Nuxt. This breaks the Tailwind v4 integration when useTailwindStyles: true is enabled.
Suggested fix
function registerUploadthingTailwindCss(distPath: string) {
- addTemplate({
- write: true,
- filename: 'uploadthing-tw.css',
- dst: resolver.resolve('./runtime/uploadthing-tw.css'),
- getContents: () =>
- `@import "uploadthing/tw/v4";\n@source "${distPath}";\n`,
- })
+ const nuxt = useNuxt()
+ const template = addTemplate({
+ filename: 'uploadthing/uploadthing-tw.css',
+ getContents: () =>
+ `@import "uploadthing/tw/v4";\n@source "${distPath}";\n`,
+ })
+ nuxt.options.css.push(template.dst)
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function registerUploadthingTailwindCss(distPath: string) { | |
| addTemplate({ | |
| write: true, | |
| filename: 'uploadthing-tw.css', | |
| dst: resolver.resolve('./runtime/uploadthing-tw.css'), | |
| getContents: () => | |
| `@import "uploadthing/tw/v4";\n@source "${distPath}";\n`, | |
| }) | |
| function registerUploadthingTailwindCss(distPath: string) { | |
| const nuxt = useNuxt() | |
| const template = addTemplate({ | |
| filename: 'uploadthing/uploadthing-tw.css', | |
| getContents: () => | |
| `@import "uploadthing/tw/v4";\n@source "${distPath}";\n`, | |
| }) | |
| nuxt.options.css.push(template.dst) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/module.ts` around lines 195 - 202,
registerUploadthingTailwindCss currently generates uploadthing-tw.css via
addTemplate but never registers it with Nuxt's CSS pipeline; after the
addTemplate call in registerUploadthingTailwindCss, push the generated CSS into
nuxt.options.css (e.g.
nuxt.options.css.push(resolver.resolve('./runtime/uploadthing-tw.css'))),
mirroring the pattern used in registerUploadthingCss (which calls
nuxt.options.css.push('@uploadthing/vue/styles.css')) so the Tailwind v4
stylesheet is actually loaded by Nuxt.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
packages/nuxt/src/module.ts (2)
175-180:⚠️ Potential issue | 🟠 MajorAvoid writing generated CSS into the module source runtime path.
On Line 179, forcing
dsttoresolver.resolve('./runtime/uploadthing-tw.css')can attempt writes under installed package files; use Nuxt build templates instead.Proposed fix
function registerUploadthingCss() { - addTemplate({ - write: true, - filename: 'uploadthing-tw.css', - dst: resolver.resolve('./runtime/uploadthing-tw.css'), - getContents: () => - ` -/** - * Tailwind styles are disabled. - * UploadThing default CSS is being used instead. - * This file is intentionally left empty. - */ - `, - }) - const nuxt = useNuxt() return nuxt.options.css.push('@uploadthing/vue/styles.css') }#!/bin/bash # Verify `dst` points to package runtime path in fallback CSS registration sed -n '174,192p' packages/nuxt/src/module.ts | cat -n # Expected: `dst: resolver.resolve('./runtime/uploadthing-tw.css')` is present.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxt/src/module.ts` around lines 175 - 180, The addTemplate call in registerUploadthingCss currently forces dst to resolver.resolve('./runtime/uploadthing-tw.css'), which may write into installed package files; remove the dst property (or stop resolving into ./runtime) so Nuxt's addTemplate controls the output path (use only filename and getContents) and let Nuxt place the generated CSS into the build/templates output instead of the package runtime; update the addTemplate invocation in registerUploadthingCss to omit dst and keep write/filename/getContents.
194-202:⚠️ Potential issue | 🟠 MajorTailwind v4 template is generated but never loaded by Nuxt.
On Line 195, the Tailwind stylesheet template is created, but there is no
nuxt.options.css.push(...)to register it, so v4 styles won’t be applied.Proposed fix
function registerUploadthingTailwindCss(distPath: string) { - addTemplate({ - write: true, - filename: 'uploadthing-tw.css', - dst: resolver.resolve('./runtime/uploadthing-tw.css'), + const nuxt = useNuxt() + const template = addTemplate({ + filename: 'uploadthing/uploadthing-tw.css', getContents: () => `@import "uploadthing/tw/v4";\n@source "${distPath}";\n`, }) + nuxt.options.css.push(template.dst) }#!/bin/bash # Verify current Tailwind registration path is not pushed to Nuxt CSS sed -n '190,206p' packages/nuxt/src/module.ts | cat -n rg -n "registerUploadthingTailwindCss|nuxt\\.options\\.css\\.push" packages/nuxt/src/module.ts -A8 -B4 # Expected: no css.push inside registerUploadthingTailwindCss in current code.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/nuxt/src/module.ts` around lines 194 - 202, The registerUploadthingTailwindCss function creates the uploadthing-tw.css template but never registers it with Nuxt; update registerUploadthingTailwindCss (the function that calls addTemplate and generates 'uploadthing-tw.css' via resolver.resolve('./runtime/uploadthing-tw.css')) to push the generated template path into nuxt.options.css (e.g., nuxt.options.css.push(<template dst or filename>)) after addTemplate so the Tailwind v4 stylesheet is actually loaded by Nuxt.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/nuxt/src/module.ts`:
- Around line 175-180: The addTemplate call in registerUploadthingCss currently
forces dst to resolver.resolve('./runtime/uploadthing-tw.css'), which may write
into installed package files; remove the dst property (or stop resolving into
./runtime) so Nuxt's addTemplate controls the output path (use only filename and
getContents) and let Nuxt place the generated CSS into the build/templates
output instead of the package runtime; update the addTemplate invocation in
registerUploadthingCss to omit dst and keep write/filename/getContents.
- Around line 194-202: The registerUploadthingTailwindCss function creates the
uploadthing-tw.css template but never registers it with Nuxt; update
registerUploadthingTailwindCss (the function that calls addTemplate and
generates 'uploadthing-tw.css' via
resolver.resolve('./runtime/uploadthing-tw.css')) to push the generated template
path into nuxt.options.css (e.g., nuxt.options.css.push(<template dst or
filename>)) after addTemplate so the Tailwind v4 stylesheet is actually loaded
by Nuxt.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: fe020624-5bf9-473d-8df3-d2746a70153d
📒 Files selected for processing (3)
packages/nuxt/README.mdpackages/nuxt/package.jsonpackages/nuxt/src/module.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/nuxt/README.md
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/nuxt/src/module.ts`:
- Around line 68-70: The default option fileRouterExport currently set to
'fileRouter' doesn't match the fallback router module's export name
uploadRouter, causing the generated handler (which accesses
RouterModule["fileRouter"]) to fail; fix by making them consistent—either change
the defaults.fileRouterExport value back to 'uploadRouter' or update the
fallback '#ut-router' module to export 'fileRouter' (ensure the symbol names
match the generated handler's lookup RouterModule["fileRouter"]).
- Around line 320-325: The helper emptyStringToUndefined is untyped and uses an
untyped next object which breaks strict TS; update emptyStringToUndefined to
accept a properly typed input (e.g. obj: Record<string, string | undefined> or a
generic <T extends Record<string, string | undefined>>(obj: T)) and type next to
the corresponding output shape (e.g. Record<keyof T, string | undefined> or
Partial<T>) and annotate the function return type to match before passing its
result into createRouteHandler(); ensure all property accesses use the typed
index signature so the compiler accepts next[key] assignments.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7e77a085-93ca-4f6a-8f9a-46d7a961704d
📒 Files selected for processing (1)
packages/nuxt/src/module.ts
| defaults: { | ||
| routerPath: "~/server/uploadthing", | ||
| injectStyles: true, | ||
| // Need to manually set these for static analysis to work, even if they're set to undefined | ||
| token: undefined, | ||
| isDev: undefined, | ||
| logLevel: undefined, | ||
| logFormat: undefined, | ||
| ingestUrl: undefined, | ||
| callbackUrl: undefined, | ||
| fileRouterPath: '@@/server/uploadthing', | ||
| fileRouterExport: 'fileRouter', |
There was a problem hiding this comment.
Align the default router export name with the fallback router module.
fileRouterExport now defaults to fileRouter, but the fallback #ut-router module still exports uploadRouter. With the out-of-the-box config, the generated handler looks up RouterModule["fileRouter"] and throws unless users override the option. Either switch this default back to uploadRouter or rename the fallback export to match.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/module.ts` around lines 68 - 70, The default option
fileRouterExport currently set to 'fileRouter' doesn't match the fallback router
module's export name uploadRouter, causing the generated handler (which accesses
RouterModule["fileRouter"]) to fail; fix by making them consistent—either change
the defaults.fileRouterExport value back to 'uploadRouter' or update the
fallback '#ut-router' module to export 'fileRouter' (ensure the symbol names
match the generated handler's lookup RouterModule["fileRouter"]).
| const emptyStringToUndefined = (obj) => { | ||
| const next = {} | ||
| for (const key in obj) { | ||
| next[key] = obj[key] === '' ? undefined : obj[key] | ||
| } | ||
| return next |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the file
fd -t f "module.ts" packages/nuxt/srcRepository: pingdotgg/uploadthing
Length of output: 93
🏁 Script executed:
# Get the file content around lines 320-325
if [ -f "packages/nuxt/src/module.ts" ]; then
wc -l packages/nuxt/src/module.ts
fiRepository: pingdotgg/uploadthing
Length of output: 97
🏁 Script executed:
# Read the specific section mentioned in the review
sed -n '310,335p' packages/nuxt/src/module.ts | cat -nRepository: pingdotgg/uploadthing
Length of output: 1004
🏁 Script executed:
# Check the broader context for how emptyStringToUndefined is used
rg -n "emptyStringToUndefined" packages/nuxt/src/module.ts -A 3 -B 3Repository: pingdotgg/uploadthing
Length of output: 630
🏁 Script executed:
# Check tsconfig files
find . -name "tsconfig*.json" | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && cat {}'Repository: pingdotgg/uploadthing
Length of output: 3157
🏁 Script executed:
# Check if RouteHandlerConfig exists in uploadthing/types
rg -n "RouteHandlerConfig" packages/ --type ts --type tsxRepository: pingdotgg/uploadthing
Length of output: 93
🏁 Script executed:
# Check the context after line 333 to see how config is used
sed -n '333,350p' packages/nuxt/src/module.ts | cat -nRepository: pingdotgg/uploadthing
Length of output: 652
🏁 Script executed:
# Check if there are h3-specific imports and see the createRouteHandler usage
sed -n '320,356p' packages/nuxt/src/module.ts | cat -nRepository: pingdotgg/uploadthing
Length of output: 1191
🏁 Script executed:
# Search for RouteHandlerConfig in the uploadthing package
rg "RouteHandlerConfig" packages/ -t tsRepository: pingdotgg/uploadthing
Length of output: 47
🏁 Script executed:
# Check the uploadthing types exports
find . -path "*/uploadthing/types*" -o -path "*/uploadthing/src/types*" | head -10Repository: pingdotgg/uploadthing
Length of output: 101
🏁 Script executed:
# Look for RouteHandlerConfig definition more broadly
rg "RouteHandlerConfig" . --type ts -lRepository: pingdotgg/uploadthing
Length of output: 177
🏁 Script executed:
# Check h3 types in uploadthing
rg "RouteHandlerConfig\|createRouteHandler" packages/core/src/ -A 2 -B 2Repository: pingdotgg/uploadthing
Length of output: 124
🏁 Script executed:
# Check the uploadthing types file
cat packages/uploadthing/src/types.tsRepository: pingdotgg/uploadthing
Length of output: 8141
🏁 Script executed:
# Look for h3 related files
find packages -name "*h3*" -type fRepository: pingdotgg/uploadthing
Length of output: 96
🏁 Script executed:
# Search for createRouteHandler definition
rg "createRouteHandler" packages/ -A 5 -B 2Repository: pingdotgg/uploadthing
Length of output: 47
🏁 Script executed:
# Check the h3.ts file
cat packages/uploadthing/src/h3.tsRepository: pingdotgg/uploadthing
Length of output: 1262
🏁 Script executed:
# Also check what's exported from uploadthing/h3
rg "export" packages/uploadthing/src/h3.tsRepository: pingdotgg/uploadthing
Length of output: 227
Type the generated config sanitizer before this lands.
This template will fail strict TypeScript checks: obj is implicitly any, and next[key] indexes a plain {}. Give the helper an explicit object type and type next accordingly before passing the result into createRouteHandler().
Suggested fix
import { createRouteHandler } from 'uploadthing/h3'
+import type { RouteHandlerConfig } from 'uploadthing/types'
import * as RouterModule from '#ut-router'
@@
-const emptyStringToUndefined = (obj) => {
- const next = {}
- for (const key in obj) {
- next[key] = obj[key] === '' ? undefined : obj[key]
+const emptyStringToUndefined = (obj: Record<string, unknown>) => {
+ const next: Record<string, unknown> = {}
+ for (const [key, value] of Object.entries(obj)) {
+ next[key] = value === '' ? undefined : value
}
return next
}
@@
- const config = emptyStringToUndefined(runtime.uploadthing?.routeHandlerConfig ?? {})
+ const config = emptyStringToUndefined(
+ (runtime.uploadthing?.routeHandlerConfig ?? {}) as Record<string, unknown>,
+ ) as RouteHandlerConfig📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const emptyStringToUndefined = (obj) => { | |
| const next = {} | |
| for (const key in obj) { | |
| next[key] = obj[key] === '' ? undefined : obj[key] | |
| } | |
| return next | |
| const emptyStringToUndefined = (obj: Record<string, unknown>) => { | |
| const next: Record<string, unknown> = {} | |
| for (const [key, value] of Object.entries(obj)) { | |
| next[key] = value === '' ? undefined : value | |
| } | |
| return next | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/nuxt/src/module.ts` around lines 320 - 325, The helper
emptyStringToUndefined is untyped and uses an untyped next object which breaks
strict TS; update emptyStringToUndefined to accept a properly typed input (e.g.
obj: Record<string, string | undefined> or a generic <T extends Record<string,
string | undefined>>(obj: T)) and type next to the corresponding output shape
(e.g. Record<keyof T, string | undefined> or Partial<T>) and annotate the
function return type to match before passing its result into
createRouteHandler(); ensure all property accesses use the typed index signature
so the compiler accepts next[key] assignments.
Summary
This PR migrates the Nuxt UploadThing module to Nuxt 4 and adds Tailwindv4 support
What changed
fileRouterPathfileRouterExportcomponentPrefixuseTailwindStylesrouteHandlerConfigpostbuild.tsworkaround.packages/nuxt/README.mdwith updated setup instructions.Breaking Changes
Summary by CodeRabbit
New Features
Breaking Changes
Documentation