Skip to content

Commit e7133bb

Browse files
committed
chore(build): canonicalize on npm, add phantom-import guardrail
Two changes to prevent a repeat of the 14-hour production outage where Vercel's pnpm build couldn't resolve 'advanced-cropper' while local npm builds worked fine. 1. Delete pnpm-lock.yaml. Both lockfiles were tracked, and Vercel was picking pnpm on the tie-break. Everything else about the repo (package.json scripts, CLAUDE.md, README.md, docs/SETUP.md, docs/CONTRIBUTING.md, GitHub Actions CI) uses npm, so pnpm was the outlier. Keeping package-lock.json makes npm the single source of truth and eliminates drift between the two lockfiles. 2. Add the import/no-extraneous-dependencies ESLint rule (plugin is already in devDependencies). This catches any `import from 'foo'` where 'foo' is a transitive dependency instead of an explicit one — the exact failure mode that broke production. Verified locally: temporarily removing advanced-cropper from package.json triggers the expected error at CustomStencil.tsx:5. Test files, e2e specs, scripts, and config files are allowed to import from devDependencies.
1 parent e1abdee commit e7133bb

2 files changed

Lines changed: 25 additions & 8700 deletions

File tree

eslint.config.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import globals from 'globals'
33
import reactHooks from 'eslint-plugin-react-hooks'
44
import jsxA11y from 'eslint-plugin-jsx-a11y'
55
import nextPlugin from '@next/eslint-plugin-next'
6+
import importPlugin from 'eslint-plugin-import'
67
import tseslint from 'typescript-eslint'
78

89
export default tseslint.config(
@@ -18,6 +19,7 @@ export default tseslint.config(
1819
'react-hooks': reactHooks,
1920
'jsx-a11y': jsxA11y,
2021
'@next/next': nextPlugin,
22+
import: importPlugin,
2123
},
2224
rules: {
2325
...reactHooks.configs.recommended.rules,
@@ -31,6 +33,29 @@ export default tseslint.config(
3133
argsIgnorePattern: '^_',
3234
varsIgnorePattern: '^_',
3335
}],
36+
// Guardrail against phantom imports: catch any `import from 'foo'` where
37+
// 'foo' is only a transitive dep. This exact failure (advanced-cropper
38+
// imported but only reachable via react-advanced-cropper) broke the
39+
// Vercel production build for ~14h because pnpm's strict isolated
40+
// layout doesn't expose transitive deps the way npm's flat hoisting
41+
// does. Test files, configs, and scripts are allowed to use
42+
// devDependencies.
43+
'import/no-extraneous-dependencies': ['error', {
44+
devDependencies: [
45+
'**/*.test.{ts,tsx}',
46+
'**/*.spec.{ts,tsx}',
47+
'src/e2e/**',
48+
'scripts/**',
49+
'test-setup*.ts',
50+
'vitest.config.ts',
51+
'playwright.config.ts',
52+
'eslint.config.js',
53+
'next.config.ts',
54+
'sentry.*.config.ts',
55+
],
56+
optionalDependencies: false,
57+
peerDependencies: false,
58+
}],
3459
},
3560
},
3661
)

0 commit comments

Comments
 (0)