Frontend Troubleshooting
Cannot find module ‘@granit/xxx’
Section titled “Cannot find module ‘@granit/xxx’”TypeScript or Vite fails to resolve a @granit/* import:
Cannot find module '@granit/authentication' or its corresponding type declarations.Fix: verify both the link: dependency and the Vite alias are configured:
{ "dependencies": { "@granit/authentication": "link:../granit-front/packages/@granit/authentication" }}resolve: { alias: { '@granit/authentication': path.join(GRANIT, 'authentication/src/index.ts'), },}Then run pnpm install in the consuming application.
TypeScript path resolution
Section titled “TypeScript path resolution”TypeScript reports TS2307 even though link: is configured:
TS2307: Cannot find module '@granit/utils' or its corresponding type declarations.Fix: add paths in every tsconfig (tsconfig.app.json, tsconfig.test.json,
tsconfig.storybook.json):
{ "compilerOptions": { "paths": { "@granit/utils": ["../granit-front/packages/@granit/utils/src/index.ts"] } }}Vitest alias not resolved
Section titled “Vitest alias not resolved”Tests fail with a module resolution error for a @granit/* package:
Error: Failed to resolve import "@granit/querying" from "src/components/..."Fix: in vitest.config.ts, declare sub-paths before the main path:
resolve: { alias: { // Sub-paths first '@granit/querying/types': path.join(GRANIT, 'querying/src/types/index.ts'), // Main path after '@granit/querying': path.join(GRANIT, 'querying/src/index.ts'), },}Vitest resolves aliases in declaration order. If the main path is listed first, sub-paths are never reached.
ESLint import order errors
Section titled “ESLint import order errors”ESLint reports import-x/order after creating a new file:
error There should be no empty line within import group import-x/orderFix: run the auto-fixer, then verify there are no blank lines between imports of the same group:
npx eslint --fix packages/@granit/my-package/src/my-file.tsImport order: external imports (sorted alphabetically), then internal imports,
then type imports.
SignalR mock issues in tests
Section titled “SignalR mock issues in tests”Tests in @granit/notifications fail with:
ReferenceError: HubConnectionBuilder is not definedFix: ensure the mock is hoisted via vi.hoisted in the test setup:
const mockConnection = vi.hoisted(() => ({ start: vi.fn().mockResolvedValue(undefined), stop: vi.fn().mockResolvedValue(undefined), on: vi.fn(), off: vi.fn(), invoke: vi.fn(), state: 'Connected',}));
vi.mock('@microsoft/signalr', () => ({ HubConnectionBuilder: vi.fn(() => ({ withUrl: vi.fn().mockReturnThis(), withAutomaticReconnect: vi.fn().mockReturnThis(), build: vi.fn(() => mockConnection), })), HubConnectionState: { Connected: 'Connected', Disconnected: 'Disconnected', },}));Readonly array type mismatch
Section titled “Readonly array type mismatch”TypeScript reports a type error when returning an array:
Type 'readonly string[]' is not assignable to type 'string[]'.Fix: use readonly T[] in return types of hooks and functions:
// Correctfunction useItems(): readonly string[] { ... }Pre-commit hook failures
Section titled “Pre-commit hook failures”The commit is blocked by a Husky hook:
husky - pre-commit hook exited with code 1Fix: address the specific failure:
- Lint errors — fix ESLint issues:
pnpm lintornpx eslint --fix ... - TypeScript errors — fix compilation:
pnpm tsc - commitlint — use Conventional Commits format:
feat:,fix:,docs:,chore:,refactor:,test:
Fix the issues, re-stage files (git add), and commit again. Never use
--no-verify to bypass hooks.
See also
Section titled “See also”- Frontend Quick Start — initial setup
- Frontend Testing — test conventions
- Frontend CI/CD — pipeline configuration