Skip to content

Conversation

ShadiBitaraf
Copy link

@ShadiBitaraf ShadiBitaraf commented Sep 30, 2025

Overview

Official Nuxt codemods for migrating from v3 to v4, automating breaking change transformations through 5 specialized codemods that handle API updates and deprecated patterns.

Key Features

  • Path Normalization: Updates nuxt.hook('builder:watch') to use absolute paths
  • Data Fetching Updates: Transforms null checks to undefined for useAsyncData/useFetch, adds { deep: true } options
  • Template Migration: Converts addTemplate from src property to getContents function
  • Dedupe Modernization: Changes boolean dedupe values to string format in refresh() calls
  • Registry Ready: Available via npx codemod@latest @nuxt-v3-to-v4

Impact

  • Automated Migration: Handles all major v3 → v4 breaking changes programmatically
  • Tested Transformations: Each codemod validated with input/output test cases
  • Production Safe: Preserves functionality while updating to v4 patterns

Files Modified

  • Codemods: 5 transformation scripts handling specific breaking changes
  • Utils: Modular utilities (ast-utils.ts, import-utils.ts, nuxt-patterns.ts)
  • Tests: Input/expected output pairs for each transformation
  • Config: codemod.yaml, workflow.yaml, package.json for Registry integration
  • Docs: Installation and usage instructions

- Add 5 codemod scripts for nuxt v3 to v4 migration
- Add comprehensive test cases with input/expected outputs
- Cover absolute-watch-path, data-error-value, dedupe-value, reactivity, template changes
- Add codemod-utils for common transformations
- Add import-utils for import management
- Add nuxt-patterns for reusable AST patterns
- Add test-utils for testing helpers
- Add codemod.yaml with metadata and registry config
- Add workflow.yaml with 5-step transformation pipeline
- Add package.json with jssg dependencies and npm scripts
- Add tsconfig.json for typescript compilation
- Add npm test command to validate all codemods
- Check file structure, imports, and syntax
- Provide developer-friendly test output and instructions
- Add comprehensive documentation for codemod usage
- Add gitignore for node_modules and build artifacts
…ompatibility

- All codemod scripts now use proper ES module imports with .js extensions
- Added missing Edit type imports for better type safety
- Improved type annotations and fixed TypeScript strict mode issues
- Created ast-utils.ts with core AST manipulation functions (hasContent, applyEdits, findFunctionCalls, etc.)
- Completely rewrote import-utils.ts with better import analysis and management capabilities
- Restructured nuxt-patterns.ts to use constants and cleaner pattern definitions
- Removed unused codemod-utils.ts and test-utils.ts files
- Updated index.ts to export from new focused module structure
- Improved TypeScript generics and type safety throughout utils
…sformations, proper installation instructions, focused important notes about edge cases, and links to official Nuxt v4 migration resources
/**
* Quick check if file contains specific content before processing
*/
export function hasContent<T extends Record<string, any>>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export function hasContent<T extends Record<string, any>>(
export function hasContent<T extends TypesMap>(

Comment on lines 14 to 16
if (!hasAnyContent(root, DATA_FETCH_HOOKS)) {
return null;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't encourage string ops, and this is a bad practice imo. This is also a duplicate check. You're already performing an ast-based search later.

}

// Extract data and error variable names from destructuring
const dataErrorVars = new Set<string>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be file-wide.

Imagine you have:

function X() {
  const { data: listData, error: listError } = useFetch(
    () => client.value.v1.lists.fetch(),
    {
      default: () => shallowRef(),
    }
  );
}


function Y() {
  const listData = ...

  
  if (userData.value === null) {
  }
}

listData is marked as dataErrorVar in the entire file, while in function Y, we don't care about this var.

- Implement ensureImport() for import detection and insertion
- Support both named and default imports with type/runtime distinction
- Handle import deduplication, quote style detection, and alias resolution
- Fix AST parsing for import_clause and named_imports fields
- Add logic to distinguish type conversion vs mixed import scenarios
- Preserve existing imports when adding different import types
- Reduce string ops to proper AST node replacement as much as possible
- Use ensureImport utility for cleaner import management
- Fix import placement to avoid duplicate imports
- Change all import paths from .js to .ts extensions for consistency
- Remove comprehensive-test-runner.ts (it was unnessary)
- Update TypeScript types from Record<string, any> to proper TypesMap
- Remove tsconfig exclude patterns that are no longer needed
- Migrate template-compilation-changes to proper AST manipulation with ensureImport
- Remove redundant content checks that were causing false negatives
…ed transformation

- Replace fragile regex matching with proper AST node traversal
- Use ensureImport utility for reliable import management instead of manual string manipulation
- Fix absolute-watch-path expected formatting to use consistent multi-line style
- Remove duplicate imports from template-compilation-changes expected output
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants