.opencode/skills/nx-import/references/VITE.md
Vite-specific guidance for nx import. For generic import issues (pnpm globs, root deps, project references, name collisions, ESLint, frontend tsconfig base settings, @nx/react typings, Jest preset, non-Nx source handling), see SKILL.md.
@nx/vite/plugin Typecheck Target@nx/vite/plugin defaults typecheckTargetName to "vite:typecheck". If the workspace expects "typecheck", set it explicitly in nx.json. If @nx/js/typescript is also registered, rename one target to avoid conflicts (e.g. "tsc-typecheck" for the JS plugin).
Keep both plugins only if the workspace has non-Vite pure TS libraries — @nx/js/typescript handles those while @nx/vite/plugin handles Vite projects.
Plugin init loads vite.config.ts before deps are available. Fix: pnpm add -wD vite @vitejs/plugin-react (or @vitejs/plugin-vue) first, then pnpm exec nx add @nx/vite.
resolve.alias and __dirname (Non-Nx Sources)__dirname undefined (CJS-only): Replace with fileURLToPath(new URL('./src', import.meta.url)) from 'node:url'.
@/ path alias: Vite's resolve.alias works at runtime but TS needs matching "paths". Set "baseUrl": "." in project tsconfig.
PostCSS/Tailwind: Verify content globs resolve correctly after import.
types (Non-Nx Sources)Non-Nx tsconfigs may not declare all needed types. Ensure Vite projects include "types": ["node", "vite/client"] in their tsconfig.
noEmit Fix: Vite-Specific NotesSee SKILL.md for the generic noEmit→composite fix. Vite-specific additions:
tsconfig.app.json and tsconfig.node.json with noEmit — fix both"files": [], "references": [...]) may lack extends. Add extends pointing to the dest root tsconfig.base.json so base settings (moduleResolution, lib) apply.Shared Vite deps (both frameworks): vite, vitest, jsdom, @types/node, typescript (dev)
Vite 6→7: Typecheck fails (Plugin<any> type mismatch); build/serve still works. Fix: align versions.
Vitest 3→4: Usually works; type conflicts may surface in shared test utils.
React Router 7 (@react-router/dev) uses Vite under the hood with a vite.config.ts and a react-router.config.ts. The @nx/vite/plugin detects vite.config.ts and creates inferred targets.
@nx/vite/plugin creates build, dev, serve targets. The build target invokes the script defined in package.json (usually react-router build), not vite build directly.
No separate typecheck target from @nx/vite/plugin — React Router 7 typegen is run as part of typecheck (e.g. react-router typegen && tsc). The typecheck target is inferred from the tsconfig. Keep the typecheck script in package.json if present; it is not rewritten.
React Router 7 uses a single tsconfig.json (no tsconfig.app.json/tsconfig.node.json split). It includes:
"rootDirs": [".", "./.react-router/types"] — for generated type files; keep as-is"paths": { "~/*": ["./app/*"] } — self-referential alias; keep as-is"noEmit": true — replace with composite settings per SKILL.mdReact Router 7 outputs to build/ (not dist/). Add build to the dest root .gitignore.
React Router 7 generates .react-router/ at the project root for route type generation. Add .react-router to the dest root .gitignore.
TanStack Start uses Vinxi under the hood, which wraps Vite. Projects have a standard vite.config.ts that @nx/vite/plugin detects normally.
@nx/vite/plugin creates build, dev, preview, serve-static, typecheck targets. The build target runs vite build which invokes the TanStack Start Vinxi pipeline (produces both client and SSR bundles).
TanStack Start uses a single tsconfig.json with "allowImportingTsExtensions": true and "noEmit": true. Apply the standard noEmit → composite fix. allowImportingTsExtensions is compatible with emitDeclarationOnly: true — no change needed.
paths AliasesTanStack Start commonly uses "#/*": ["./src/*"] and "@/*": ["./src/*"]. These are self-referential — keep as-is for a single-project app.
create-tan-stack initializes a git repo but does NOT make an initial commit. Before importing, commit first:
git -C /path/to/source add . && git -C /path/to/source commit -m "Initial commit"
TanStack Start / Vinxi / Nitro generate several directories that must be added to the dest root .gitignore:
.vinxi — Vinxi build cache.tanstack — TanStack generated files.nitro — Nitro build artifacts.output — server-side build output (SSR/edge)These are not covered by dist or build.
Production: react, react-dom
Dev: @types/react, @types/react-dom, @vitejs/plugin-react, @testing-library/react, @testing-library/jest-dom, jsdom
ESLint (Nx sources): eslint-plugin-import, eslint-plugin-jsx-a11y, eslint-plugin-react, eslint-plugin-react-hooks
ESLint (create-vite): eslint-plugin-react-refresh, eslint-plugin-react-hooks — self-contained flat configs can be left as-is
Nx plugins: @nx/react (generators), @nx/vite, @nx/vitest, @nx/eslint
Add "jsx": "react-jsx" — in tsconfig.base.json for single-framework workspaces, per-project for mixed (see Mixed section).
import nx from '@nx/eslint-plugin';
import baseConfig from '../../eslint.config.mjs';
export default [
...baseConfig,
...nx.configs['flat/react'],
{ files: ['**/*.ts', '**/*.tsx'], rules: {} },
];
React 18 (source) + React 19 (dest): pnpm may hoist mismatched react-dom, causing TypeError: Cannot read properties of undefined (reading 'S'). Fix: Align versions with pnpm.overrides.
@testing-library/jest-dom with VitestIf source used Jest: change import to @testing-library/jest-dom/vitest in test-setup.ts, add to tsconfig types.
Production: vue (plus vue-router, pinia if used)
Dev: @vitejs/plugin-vue, vue-tsc, @vue/test-utils, jsdom
ESLint: eslint-plugin-vue, vue-eslint-parser, @vue/eslint-config-typescript, @vue/eslint-config-prettier
Nx plugins: @nx/vue (generators), @nx/vite, @nx/vitest, @nx/eslint (install AFTER deps — see below)
Add to tsconfig.base.json (single-framework) or per-project (mixed):
{ "jsx": "preserve", "jsxImportSource": "vue", "resolveJsonModule": true }
vue-shims.d.tsVue SFC files need a type declaration. Usually exists in each project's src/ and imports cleanly. If missing:
declare module '*.vue' {
import { defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component;
}
vue-tsc Auto-DetectionBoth @nx/js/typescript and @nx/vite/plugin auto-detect vue-tsc when installed — no manual config needed. Remove source scripts like "typecheck": "vue-tsc --noEmit".
@nx/eslint init crashes if Vue ESLint deps aren't installed first (it loads all config files).
Correct order:
pnpm add -wD eslint@^9 eslint-plugin-vue vue-eslint-parser @vue/eslint-config-typescript @typescript-eslint/parser @nx/eslint-plugin typescript-eslinteslint.config.mjsnpx nx add @nx/eslintimport vue from 'eslint-plugin-vue';
import vueParser from 'vue-eslint-parser';
import tsParser from '@typescript-eslint/parser';
import baseConfig from '../../eslint.config.mjs';
export default [
...baseConfig,
...vue.configs['flat/recommended'],
{
files: ['**/*.vue'],
languageOptions: { parser: vueParser, parserOptions: { parser: tsParser } },
},
{
files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx', '**/*.vue'],
rules: { 'vue/multi-word-component-names': 'off' },
},
];
Important: vue-eslint-parser override must come AFTER base config — flat/typescript sets the TS parser globally without a files filter, breaking .vue parsing.
vue-eslint-parser must be an explicit pnpm dependency (strict resolution prevents transitive import).
Known issue: Some generated Vue ESLint configs omit vue-eslint-parser. Use the pattern above instead.
When both frameworks coexist, several settings become per-project.
jsx — Per-Project Only"jsx": "react-jsx" in project tsconfig"jsx": "preserve", "jsxImportSource": "vue" in project tsconfigjsx setting@nx/vite/plugin uses vue-tsc for Vue projects and tsc for React automatically.
{
"plugins": [
{ "plugin": "@nx/eslint/plugin", "options": { "targetName": "lint" } },
{
"plugin": "@nx/vite/plugin",
"options": {
"buildTargetName": "build",
"typecheckTargetName": "typecheck",
"testTargetName": "test"
}
}
]
}
Remove @nx/js/typescript if all projects use Vite. Keep it (renamed to "tsc-typecheck") only for non-Vite pure TS libs.
nx.configs['flat/react']vue.configs['flat/recommended'] + vue-eslint-parserRequired packages: Shared (eslint@^9, @nx/eslint-plugin, typescript-eslint, @typescript-eslint/parser), React (eslint-plugin-import, eslint-plugin-jsx-a11y, eslint-plugin-react, eslint-plugin-react-hooks), Vue (eslint-plugin-vue, vue-eslint-parser)
@nx/react/@nx/vue are for generators only — no target conflicts.
nx import copies package.json verbatim, so npm scripts come along. For Vite-based projects @nx/vite/plugin already infers the same targets from vite.config.ts — the npm scripts just shadow the plugin with weaker nx:run-script wrappers (no first-class caching inputs/outputs). Remove them after import.
create-vite)Remove the following scripts — every one is redundant:
| Script | Plugin replacement |
|---|---|
dev: vite | @nx/vite/plugin → dev |
build: tsc -b && vite build | @nx/vite/plugin → build; typecheck via @nx/js/typescript handles tsc |
preview: vite preview | @nx/vite/plugin → preview |
lint: eslint . | @nx/eslint/plugin → eslint:lint |
Remove build, dev, preview, and test scripts, but move any hardcoded --port flag to vite.config.ts first:
// vite.config.ts
export default defineConfig({
server: { port: 3000 }, // replaces `vite dev --port 3000`
...
})
Do not remove React Router 7 scripts. They use the framework CLI (react-router build, react-router dev, react-router-serve) which is not interchangeable with plain vite:
typecheck runs react-router typegen && tsc — typegen must precede tsc or it fails on missing route typesstart serves the SSR bundle — no plugin equivalent@nx/react typings)@nx/vite/plugin typecheck targetjsx: "react-jsx" (root or per-project)jsx: "preserve" + jsxImportSource: "vue"; verify vue-shims.d.ts; install ESLint deps before @nx/eslintjsx per-project; remove/rename @nx/js/typescriptnx sync --yes && nx reset && nx run-many -t typecheck,build,test,lintapps/<name> (see SKILL.md: "Application vs Library Detection")noEmit in all tsconfigs (app, node, etc. — non-Nx projects often have multiple)extends to solution-style tsconfigs so root settings applyresolve.alias / __dirname / baseUrltypes include vite/client and node@nx/vite manually if it failed during import@nx/vite/plugin infers them natively (see "Redundant npm Scripts" section)outDir + **/*.vue.d.ts to ESLint ignoresSee SKILL.md for generic multi-import (name collisions, dep refs). Vite-specific: fix tsconfig references paths for alternate directories (../../libs/ → ../../libs-beta/).
nx import whole-repo into apps/<name> (see SKILL.md: "Application vs Library Detection") → auto-installs @nx/vite, @nx/reactnode_modules/, package-lock.json, .gitignoretsconfig.json: noEmit → composite + emitDeclarationOnly + outDir + tsBuildInfoFilebuild and .react-router to dest root .gitignorereact-router build/dev), not plain vite (see "Redundant npm Scripts" above)npm install && nx reset && nx sync --yescreate-tan-stack does NOT auto-commit (see SKILL.md)nx import whole-repo into apps/<name> (see SKILL.md: "Application vs Library Detection") → auto-installs @nx/vite, @nx/vitestnode_modules/, package-lock.json, .gitignoretsconfig.json: noEmit → composite + emitDeclarationOnly + outDir + tsBuildInfoFileallowImportingTsExtensions — compatible with emitDeclarationOnly: true.vinxi, .tanstack, .nitro, .output to dest root .gitignore--port from dev script into vite.config.ts (server: { port: N })@nx/vite/plugin infers build, dev, preview, test (see "Redundant npm Scripts" above)npm install && nx reset && nx sync --yes| Aspect | React | Vue |
|---|---|---|
| Vite plugin | @vitejs/plugin-react | @vitejs/plugin-vue |
| Type checker | tsc | vue-tsc (auto-detected) |
| SFC support | N/A | vue-shims.d.ts needed |
| tsconfig jsx | "react-jsx" | "preserve" + "jsxImportSource": "vue" |
| ESLint parser | Standard TS | vue-eslint-parser + TS sub-parser |
| ESLint setup | Straightforward | Must install deps before @nx/eslint |
| Test utils | @testing-library/react | @vue/test-utils |
| Aspect | Vite (standalone) | React Router 7 | TanStack Start |
|---|---|---|---|
| Build config | vite.config.ts | vite.config.ts | vite.config.ts |
| Build output | dist/ | build/ | dist/ |
| SSR bundle | No | Yes (build/server/) | Yes (dist/server/) |
| tsconfig layout | app + node split | Single tsconfig | Single tsconfig |
| Auto-committed | Depends on tool | Usually yes | No — commit first |
nx import plugin | @nx/vite | @nx/vite, @nx/react | @nx/vite, @nx/vitest |
packages/*packages/<name>packages/.gitkeep and committedgit init && git add . && git commit in Vite app (no git at all)git add . && git commit in TanStack app (git init'd but no commits)npm exec nx -- import <source> packages/<name> --source=. --ref=main --no-interactive
@nx/eslint, @nx/next@nx/vite, @nx/react, @nx/docker (Dockerfile present)@nx/vitestnode_modules/, package-lock.json, .gitignore from each packageboard-games-nextjs/package.json (had "build": "nx next:build", etc.)tsconfig.base.json: nodenext → bundler, added dom/dom.iterable to lib, added jsx: react-jsxbuild to dest root .gitignore (CRA and React Router 7 output there)noEmit → composite + emitDeclarationOnly in: board-games-vite/tsconfig.app.json, board-games-vite/tsconfig.node.json, board-games-react-router/tsconfig.json, board-games-tanstack/tsconfig.jsontsBuildInfoFile paths from ./node_modules/.tmp/... to ./dist/...@types/react, @types/react-dom, @types/nodebuild for all 5 projects; typecheck for Vite/React Router/TanStack; next:build for Next.js