knip
knip은 npm 패키지로 불필요한 코드와 의존성 등을 검사해준다. 사용하지 않는 export 변수들도 찾아주는데 전체 프로젝트를 깨끗한 상태로 유지할 수 있도록 도와준다. 설치와 설정도 아주 간단하니 시작하기를 통해 프로젝트에 적용해보기를 적극 권장한다.
nextjs 적용
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"ignoreExportsUsedInFile": true,
"ignoreDependencies": [
"@?commitlint*",
"@mdx-js/*",
"@next/mdx",
"@radix-ui/*",
"@types/*",
"lint-staged",
"tailwindcss",
"tw-animate-css"
],
"ignore": [
"hooks/use-mobile.ts"
]
}
knip은 프로젝트 루트에 knip.json
을 만들어서 세부적으로 설정할 수 있는데 nextjs에 위처럼 설정하여 사용하고 있다. 위 설정처럼 tailwindcss
패키지같은 경우가 있는데 javascript나 typescript에 선언적으로 패키지를 사용하는 부분이 없어서 knip이 제거하라고 추천하는 경우이다. 이런 경우는 위 설정처럼 ignore 시켜서 우회할 수 있다. 더 자세한 설정은 공식문서를 통해서 최적화할 수 있다.
biomejs
biomejs는 린터 패키지 중 하나이다. rust기반으로 작동하며 eslint의 대체제로써 큰 관심을 받고 있다. eslint를 5년 이상 사용한 경험을 회상해보자면 eslint 버전이 올라감에 따라 점점 더 복잡해지는 설정들과 프로젝트 크기에 따라 눈에 띄게 차이나는 성능이슈가 가장 먼저 떠오른다. 성능을 어떻게든 잡아보려고 복잡한 설정을 뒤져가며 이리저리 맞춰보는 노가다들 또한 하나의 업무가 아니었나 싶다.
지금 당장 어떤 린터를 추천하겠는가 하면 biomejs를 추천하겠다. eslint, biomejs 둘다 어차피 설정은 복잡하다. 린터 설정은 최초 프로젝트 기획시 개발자간의 컨벤션 협의를 끝내고 난 후 한 번 잡고나면 큰 메이저 업데이트가 없는한 잊혀지기 마련이고 재활용하기 마련이다. 가장 중요하게 생각한 기준은 성능이다.
물론, 정말 기가막히게 설정과 구조를 잡는다면 모르겠지만 내가 eslint를 만든 것이 아니기 때문에 한계가 있다. 거대 프로젝트를 작업할 때 저장시 자동 린터 수행이나 포매팅 명령을 내리면 턱턱 끊기거나 심할경우 IDE가 정지하고 언제 끝날지 모르는 린터의 응답을 하염없이 기다려야 하는 순간들이 빈번했다. 그뿐인가? 요즘 웹 서비스 빌드 툴들은 린터를 먼저 실행하여 통과해야만 빌드를 진행하는 경우가 많다. 처음 빌드 결과를 보기 위해서라도 린터의 성능이 큰 부분을 차지한다.
nextjs 적용
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"vcs": {
"enabled": false,
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": true,
"includes": [
"**",
"!.next/**",
"!.git/**",
"!.husky/**",
"!components/ui/**",
"!hooks/use-mobile.ts"
],
"experimentalScannerIgnores": [
".next",
".git",
".husky",
"components/ui"
]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 100,
"attributePosition": "auto",
"bracketSameLine": false,
"bracketSpacing": true,
"expand": "auto",
"useEditorconfig": true
},
"linter": {
"enabled": true,
"rules": {
"nursery": {
"useSortedClasses": {
"level": "warn",
"fix": "safe",
"options": {}
}
},
"recommended": false,
"complexity": {
"noArguments": "error",
"noUselessTypeConstraint": "error"
},
"correctness": {
"noConstAssign": "off",
"noGlobalObjectCalls": "off",
"noInvalidBuiltinInstantiation": "off",
"noInvalidConstructorSuper": "off",
"noSetterReturn": "off",
"noUndeclaredVariables": "off",
"noUnreachable": "off",
"noUnreachableSuper": "off",
"noUnusedVariables": "error"
},
"style": {
"noCommonJs": "error",
"noNamespace": "error",
"useArrayLiterals": "error",
"useAsConstAssertion": "error",
"useBlockStatements": "off",
"useConst": "error"
},
"suspicious": {
"noClassAssign": "off",
"noDuplicateClassMembers": "off",
"noDuplicateObjectKeys": "off",
"noDuplicateParameters": "off",
"noExplicitAny": "error",
"noExtraNonNullAssertion": "error",
"noFunctionAssign": "off",
"noImportAssign": "off",
"noMisleadingInstantiator": "error",
"noRedeclare": "off",
"noUnsafeDeclarationMerging": "error",
"noUnsafeNegation": "off",
"noVar": "error",
"noWith": "off",
"useGetterReturn": "off",
"useNamespaceKeyword": "error"
}
}
},
"html": {
"formatter": {
"selfCloseVoidElements": "always"
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}
nextjs에 위처럼 설정하여 biomejs를 사용하고 있다. 루트에 biome.json
을 만들어서 설정할 수 있다. biome은 prettier 기능을 함께 제공하기 때문에 추가적인 패키지 설치가 필요 없다.
"$schema"는 http를 통하여 지정할 수도 있지만 biome 패키지 버전이 올라가면 매치가 되지 않는 경우가 발생한다. 자동으로 동기화 하려면 node_modules내부에 있는 설정 스키마 파일을 지정하여 편리하게 관리할 수 있다.
기존에 eslint를 사용하고 있었더라고 하더라도 쉽게 마이그레이션 할 수 있는 방법을 제공한다. Migrate from ESLint and Prettier 문서를 보고 따라하면 쉽게 전환할 수 있다. vscode에서 사용하려면 eslint처럼 vscode 확장 프로그램인 biome
을 설치해야한다.
ignore
"files": {
"ignoreUnknown": true,
"includes": [
"**",
"!.next/**",
"!.git/**",
"!.husky/**",
"!components/ui/**",
"!hooks/use-mobile.ts"
],
"experimentalScannerIgnores": [
".next",
".git",
".husky",
"components/ui"
]
},
nextjs에 설정하고 사용하다보면 빌드시 또는 이유를 알 수 없는 IDE 프리징 현상을 만날 수 있다. 심할 경우 메모리가 가득차서 윈도우 매니저 자체가 멈추는 경우도 있을 수 있다. biome이 프로젝트 루트를 감시하고 있다가 빌드 결과가 위치하는 .next
디렉토리 전체를 린팅하면서 막대한 자원을 끌어다 쓰기 때문인데 위처럼 무시 기준을 잘 설정하면 현상을 해결할 수 있다.
나의 경우 위처럼 files.icludes
설정의 !.next
처럼 디렉토리를 네거티브 매치로 등록하더라도 자동적으로 디렉토리를 스캔하고 린팅을 시도하였는데 files.experimentalScannerIgnores
설정을 추가하고 나서 현상을 해결하였다. 실험적인 속성인 것으로 보아 기능이 정식으로 지원되거나 제거되면 한 번 더 설정을 고쳐야 할 것이다.