chore(utils/vite-plugin-pnpm-resolve): 🔧 Fix incorrect PNPM dependency resolution in Vite builds to ensure proper edge-case handling
This commit is contained in:
parent
80bf44abb6
commit
40249e6d41
3 changed files with 190 additions and 0 deletions
35
@packages/@utils/vite-plugin-pnpm-resolve/package.json
Normal file
35
@packages/@utils/vite-plugin-pnpm-resolve/package.json
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "@lilith/vite-plugin-pnpm-resolve",
|
||||
"version": "1.0.0",
|
||||
"description": "Vite plugin for proper pnpm transitive dependency resolution using Rollup node-resolve",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"import": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": ">=5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^6.4.1"
|
||||
},
|
||||
"author": {
|
||||
"name": "QuinnFTW",
|
||||
"email": "TransQuinnFTW@pm.me"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
140
@packages/@utils/vite-plugin-pnpm-resolve/src/index.ts
Normal file
140
@packages/@utils/vite-plugin-pnpm-resolve/src/index.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/**
|
||||
* @lilith/vite-plugin-pnpm-resolve
|
||||
*
|
||||
* Vite plugin for proper pnpm transitive dependency resolution.
|
||||
*
|
||||
* Problem: pnpm uses a content-addressable store with symlinks instead of
|
||||
* flat node_modules hoisting. Rollup's default resolver can't find transitive
|
||||
* dependencies nested in .pnpm/ during production builds.
|
||||
*
|
||||
* Solution: Configure @rollup/plugin-node-resolve with pnpm-aware paths
|
||||
* and CommonJS options to handle nested dependencies.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { defineConfig } from 'vite';
|
||||
* import { pnpmResolve } from '@lilith/vite-plugin-pnpm-resolve';
|
||||
*
|
||||
* export default defineConfig({
|
||||
* plugins: [pnpmResolve()],
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { nodeResolve, type RollupNodeResolveOptions } from '@rollup/plugin-node-resolve';
|
||||
import type { Plugin, UserConfig } from 'vite';
|
||||
import path from 'path';
|
||||
|
||||
export interface PnpmResolveOptions {
|
||||
/**
|
||||
* Packages to deduplicate (resolve from root node_modules).
|
||||
* Prevents multiple instances of singleton packages like React.
|
||||
* @default ['react', 'react-dom', 'styled-components', 'i18next', 'react-i18next', '@tanstack/react-query', 'framer-motion']
|
||||
*/
|
||||
dedupe?: string[];
|
||||
|
||||
/**
|
||||
* Additional module paths to search.
|
||||
* @default [] (plugin adds node_modules and node_modules/.pnpm automatically)
|
||||
*/
|
||||
additionalModulePaths?: string[];
|
||||
|
||||
/**
|
||||
* File extensions to resolve.
|
||||
* @default ['.mjs', '.js', '.ts', '.tsx', '.json']
|
||||
*/
|
||||
extensions?: string[];
|
||||
|
||||
/**
|
||||
* Enable browser field resolution in package.json.
|
||||
* @default true
|
||||
*/
|
||||
browser?: boolean;
|
||||
|
||||
/**
|
||||
* Additional options passed to @rollup/plugin-node-resolve.
|
||||
*/
|
||||
nodeResolveOptions?: Partial<RollupNodeResolveOptions>;
|
||||
}
|
||||
|
||||
const DEFAULT_DEDUPE = [
|
||||
'react',
|
||||
'react-dom',
|
||||
'styled-components',
|
||||
'i18next',
|
||||
'react-i18next',
|
||||
'@tanstack/react-query',
|
||||
'framer-motion',
|
||||
'lucide-react',
|
||||
];
|
||||
|
||||
const DEFAULT_EXTENSIONS = ['.mjs', '.js', '.ts', '.tsx', '.json'];
|
||||
|
||||
/**
|
||||
* Creates a Vite plugin that configures Rollup for proper pnpm resolution.
|
||||
*
|
||||
* This plugin:
|
||||
* 1. Adds @rollup/plugin-node-resolve with pnpm-aware modulePaths
|
||||
* 2. Configures CommonJS interop for nested dependencies
|
||||
* 3. Deduplicates singleton packages to prevent multiple instances
|
||||
*/
|
||||
export function pnpmResolve(options: PnpmResolveOptions = {}): Plugin {
|
||||
const {
|
||||
dedupe = DEFAULT_DEDUPE,
|
||||
additionalModulePaths = [],
|
||||
extensions = DEFAULT_EXTENSIONS,
|
||||
browser = true,
|
||||
nodeResolveOptions = {},
|
||||
} = options;
|
||||
|
||||
let root: string;
|
||||
|
||||
return {
|
||||
name: 'vite-plugin-pnpm-resolve',
|
||||
|
||||
configResolved(config) {
|
||||
root = config.root;
|
||||
},
|
||||
|
||||
config(): UserConfig {
|
||||
return {
|
||||
resolve: {
|
||||
// Dedupe singleton packages at Vite level too
|
||||
dedupe,
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
plugins: [
|
||||
nodeResolve({
|
||||
// Include pnpm's .pnpm store in module search paths
|
||||
modulePaths: [
|
||||
path.resolve(root || process.cwd(), 'node_modules'),
|
||||
path.resolve(root || process.cwd(), 'node_modules/.pnpm'),
|
||||
...additionalModulePaths,
|
||||
],
|
||||
// Search these directories recursively for modules
|
||||
moduleDirectories: ['node_modules', '.pnpm'],
|
||||
// Force these packages to resolve from root
|
||||
dedupe,
|
||||
// Browser-compatible resolution
|
||||
browser,
|
||||
preferBuiltins: false,
|
||||
// File extensions to resolve
|
||||
extensions,
|
||||
// Merge any additional options
|
||||
...nodeResolveOptions,
|
||||
}),
|
||||
],
|
||||
},
|
||||
// CommonJS interop for nested dependencies in pnpm store
|
||||
commonjsOptions: {
|
||||
include: [/node_modules/, /\.pnpm/],
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default pnpmResolve;
|
||||
15
@packages/@utils/vite-plugin-pnpm-resolve/tsconfig.json
Normal file
15
@packages/@utils/vite-plugin-pnpm-resolve/tsconfig.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue