12월, 2023의 게시물 표시

GitLab Runner for Windows에서 filename too long 문제 발생

GitLab Runner for Windows에서 filename too long 문제 발생 Filename To Long… Electron 관련 프로젝트가 자동으로 배포되도록 파이프라인을 구성했다. 리눅스 쪽 러너에서는 문제가 없는데 Windows 러너쪽에서 계속 실패를 하여 로그를 확인해보니 filename too long 에러가 발생하고 있었다. 원인이 되는 경로는 node_modules/* 쪽이었는데 이걸 뭐 어떻게 건드릴 수 있는 상황이 아닌 건 둘째 치더라도, 현재 레지스트리에서 긴 파일 경로를 허용 해놓은 상태인데 이게 왜 뜨는지 알 수가 없었다. git config 원인은 엉뚱하게도 git 설정에 있었다. 발견했을 때는 황당했는데, 아무래도 내부적으로 git 관련 커맨드를 사용하는 게 아닌가 싶다. core.longpaths 이 증상을 해결하는 데 내가 사용한 방법은 core.longpaths 를 true 로 설정하는 것이다. git config --system core.longpaths true 위 명령어를 관리자 권한의 파워쉘에서 실행한 뒤 실패한 Job을 재가동하니 정상적으로 작동했다.

JetBrains WebStorm에서 Reference된 tsconfig 프로젝트를 인식하지 못하는 문제

이미지
JetBrains WebStorm에서 Reference된 tsconfig 프로젝트를 인식하지 못하는 문제 WebStorm이 tsconfig.*.json을 인식하지 못함 제목을 한 줄로 정리하려니 참 머리가 아프다. 제목만 보고 무슨 문제인지 잘 감이 안 잡힐 수도 있겠다 싶어서 방금 내가 겪은 일을 간단히 요약하고 들어가겠다. electron-vite 프로젝트 구성 : npx create electron-vite 명령어로 electron-vite 프로젝트를 구성했다. JetBrains WebStorm에서 프로젝트 열기 : 구성된 프로젝트를 JetBrains WebStorm으로 열었다. tsconfig.web.json의 compilerOptions.paths 에 alias 추가 : @renderer/*, @lib/* 등 path aliases를 추가했다. 코드 자동완성으로 import 시도 : @lib/abc 를 import하려 하였으나 ../../lib/abc 가 임포트됨 🤬 시도해 본 방법들 WebStorm이 업데이트된지 얼마 되지 않았기에 혹시 업데이트 관련해서 문제가 생긴 것인지 확인하기 위해 tsconfig.json 자체에서 paths를 추가해봤더니 정상 작동했다. 그 상태에서 tsconfig.web.json 의 paths를 제거해봤다. 기존 절대 경로 임포트들에서 에러가 발생했다. (IDE 자체 에러) tsconfig.paths.json 을 만들고 tsconfig.json 및 tsconfig.web.json 에서 reference를 해봤다. IDE에서는 잘 작동하는 것처럼 보이지만 프로젝트 전체 구성에 문제가 발생해 개발 및 프로덕션에서 사용할 수 없었다. 올바른 해결 방법 우선 문제를 확실히 하기 위해 완전히 새로운 electron-vite 프로젝트를 만들고 내 tsconfig.web.json 과 비교해 봤더니 기본적으로 @renderer/* 경로가 paths에 추가되어

puppeteer의 waitForXpath는 더 이상 사용되지 않는다. 대체 방법.

puppeteer의 waitForXpath는 더 이상 사용되지 않는다. Obsolete API - waitForXpath 조금 늦은 감이 있지만, 아무튼 Puppeteer 16.1.0 부터 waitForXpath 메서드 등 XPath 관련 독립 메서드들이 모두 더 이상 사용되지 않게 됐다. 그렇다고 더 이상 XPath를 사용하여 엘리먼트를 선택할 수 없는 것은 아니다. waitForSelector를 사용한 xpath 쿼리 이제부터는 waitForSelector를 사용해 xpath를 쿼리할 수 있다. 이렇게 하려면 셀렉터에 xpath/ prefix를 붙여주면 된다. await elementHandle . waitForSelector ( 'xpath/' + xpathExpression ) ; 즉 xpath/ 까지가 본체이고 이후에는 통상 xpath를 입력하면 된다는 말. 즉 ../input[@id='query'] 를 쿼리하고자 한다면 await elementHandle . waitForSelector ( 'xpath/../input[@id="query"]' ) ; 와 같이 사용하면 된다. //button[@type='submit'] 을 찾고자 한다면, 슬래쉬 세 개가 들어간다고 두려워하지 말고 await elementHandle . waitForSelector ( 'xpath///button[@type="submit"]' ) ; 과 같이 사용하면 된다. PuppeteerSharp puppeteer 의 C#용 포팅 라이브러리인 PuppeteerSharp 역시 이와 같은 변경 사항이 적용되었으니 같은 방식으로 사용하면 되겠다.

Safari의 100vh 문제

Safari의 100vh 문제 100vh? CSS의 vh 단위는 1% of Viewport Height 이다. vw 는 1% of Viewport Width 이고. 나는 이 단위를 알게 된 시점부터 지금까지 꾸준히 즐겨 사용하고 있었다. 이전에는 html, body 에 width, height 를 각각 100%로 지정하고, 하위 엘리먼트에서 또 적용하고 하는 식으로 페이지가 뷰포트에 꽉 차게 구현해야 했었지만 1 이 단위가 나오고 나서는 간단하게 뷰포트에 꽉 채울거면 너비는 100vw 로, 높이는 100vh 로 지정하면 됐기 때문이다. vw, vh가 만능은 아니다. 하지만 위 이야기는 데스크탑 버전의 웹 페이지를 작업할 때만 해당되는 말이다. 반응형 웹이랍시고 데스크탑과 모바일 모두에서 예쁘게 잘 보여야 제대로 만들어진 페이지란 소리를 듣는 요즘 세상에서는 vw, vh 도 만능은 아니다. 어디까지가 Viewport인가 그 이유는 바로 모바일 브라우저들의 지랄맞은 Address Bar(또는 Navigation Bar) 때문이다. 화면 크기가 제한적인 모바일 브라우저의 특성 때문에 모바일 브라우저의 주소창 영역은 그 높이가 일정하지 않다. 크롬, 사파리, 오페라, 웨일, 파이어폭스, 키위 등 브라우저마다 높이가 다른 것 은 둘째 치더라도, 하나의 브라우저에서도 주소창이 스크롤 중에 위나 아래로 쏙 들어가버리는 경우 가 생기기 때문에 항상 높이가 변한다고 봐도 무방하다. 문제는, 이런 상황에서 vh 유닛을 사용할 때 발생한다. Viewport는 Address Bar 영역도 포함한다. 이게 정말 사람을 미치게 하는 부분이다. 데스크탑용 브라우저에서 뷰포트라 하면 주소창 및 메뉴 영역을 제외한, 실제로 페이지가 렌더링되는 부분을 말한다. 즉 document 가 렌더링될 수 있는 영역만을 뷰포트라고 정의하고 이를 통해 직관적으로 vw, vh 를 사용할 수 있다. 그러나 모바일은 다르다. 일부 모바일 브라우저

윈도우 위젯을 엣지 대신 크롬에서 열게 해보자

이미지
윈도우 위젯을 엣지 대신 크롬에서 열게 해보자 엣지로 열리는 위젯 링크들 윈도우 11에는 작업 표시줄 좌측 하단 또는 Win + W키로 열 수 있는 위젯 기능이 탑재되어 있다. 위젯을 열면 날씨, 뉴스 등 관심사에 대한 정보를 빠르게 확인할 수 있어 유용하게 사용 중이었다. 하지만 단 하나 불편한 게 있다면 위젯이 무조건 엣지로 열린다는 것이다. 나는 크롬 및 파이어폭스를 주력으로 사용하고 있는데 뉴스나 날씨를 확인하려 위젯에서 아이템을 클릭할 때마다 엣지가 또 켜지는 것이 불편해서 방법이 없나 찾아보았다. 위젯 엣지로 열린 화면 MSEdgeRedirect 아니나 다를까 rcmaehl/MSEdgeRedirect 이라는 프로젝트가 2021년 7월부터 만들어져 있었다. 없으면 만들 생각을 하고 있었는데 역시 요즘 세상에 웬만한 건 죄다 누군가 만들어서 올려놓는단 것을 다시 한 번 깨닫게 되는 시간이었다. 설치 설치에는 몇가지 방법이 있다. 하나는 해당 프로젝트의 릴리즈 페이지 에서 설치하는 것이고, 다른 하나는 winget 을 이용하는 것이다. 물론 chocolatey 로도 가능하지만 이번 포스트에서는 winget 을 사용하는 방법에 대해 적겠다. WinGet을 이용한 설치 방법 이 방법은 당연히 WinGet이 지원되는 윈도우 업데이트가 설치되었거나, 수동으로 WinGet을 설치해놓은 컴퓨터에서만 사용할 수 있다. winget install MSEdgeRedirect -s winget 위 명령어를 입력하면 알아서 설치가 끝나게 된다. 사용 일단 기본적으로 설치가 완료되면 위젯 쪽의 링크는 알아서 리다이렉트된다. 일반적인 경우라면 더 손 댈 것은 없겠지만 그 외에도 몇가지 옵션을 지원하므로 살펴보도록 하겠다. Active Mode Options : 어떤 엣지 런타임 버전에 대해 리다이렉트를 수행할지 정한다. 기본값은 Edge Stable 만

package.json의 버전 특수문자들 (~, ^, ...)

이미지
package.json의 버전 특수문자들 (~, ^, ...) 풀스택 프리랜서로 일하면서 주력이었던 C# 1 에서 node 관련 작업으로 전환하게 되었다. 이 과정에서 버전 관리의 중요성을 깊이 깨달았다. 특히, node의 package.json 에서 버전을 지정하는 다양한 방법과 그 의미에 대해 더 자세히 알아보게 되었고, 이에 대한 나의 이해와 경험을 공유하고자 한다. 패키지 버전 노드 패키지 버전 포맷 노드는 Semantic Versioning 을 사용한다. 중학교 때부터 JetBrains ReSharper를 사용해오며 Calendar Versioning 에 익숙한 난 처음에 각각의 구분이 뭘 의미하는지 몰라서 대충 첫 번째가 바뀌면 엄청난 패치, 두 번째가 바뀌면 일반 패치, 세 번째가 바뀌면 소소한 패치 정도로 이해했는데 지금 보니 얼추 맞는 것 같기도 하다. 하지만 정확하지는 않다. 이는 버전 제한자, 버전 범위 에서 설명하도록 하겠다. package.json 노드는 package.json 파일로 패키지를 관리한다. 닷넷의 csproj 파일이랑 같은 역할을 한다고 봐도 무방할 것 같다. 여기에서 프로젝트 이름, 의존성 관리 등 프로젝트의 세부 사항을 관리하게 된다. 버전 제한자, 버전 범위 그리고 package.json에서는 버전 제한자를 사용하여 패키지 매니저 2 를 통해 의존성을 설치할 때 설치될 버전의 범위를 지정할 수 있다. 문제는 어떤 오픈소스 프로젝트는 ~ 를 앞에 붙이고, 어떤 건 ^ 를 앞에 붙이고, 어떤 건 아예 안 붙이고, 어떤 건 >, >=, <, <= 를 붙이고… 마지막 부등호들은 직관적으로 이해가 되는데 문제는 ^, ~ 는 뭐 하는 놈인지 알 수가 없었다. node-semver 해당 내용은 node-semver 리포지토리의 버전 섹션 에서 찾을 수 있었다. 특히 자주 쓰이는 ~(틸드) 와 ^(캐럿) 에 대해 설명해보자면 다음과 같다. 캐럿(

JetBrains Rider 2023.2.3에서 NUnit 4 지원 안 됨

JetBrains Rider 2023.2.3에서 NUnit 4 지원 안 됨 NUnit 4 2023년 11월 26일에 NUnit 4.0.0이 릴리즈되고 바로 이틀 전인 12월 2일에 4.0.1이 릴리즈되었다. 링크 문제는, 꽤 오랫동안 진행한 이전 프로젝트에서 xUnit을 써왔기에 이러한 사실을 전혀 모르고 있었다는 것이다. 최신 버전과 서드파티 IDE의 문제 문제는 이런 변경 사항에 대해 아무것도 모른 채 기존 .NET Framework 프로젝트를 .NET 7으로 마이그레이션하다가 테스트 프로젝트가 작동하지 않는 상황에 직면하게 되었다는 것이다. 분명 코드도 정상이고, IDE도 정상이고, NuGet 패키지도 잘 설치되었으며 dotnet test 로 테스트를 실행하면 잘 되는데 JetBrains Rider의 Unit Tests Explorer에서 테스트를 감지하지 못하는 것이었다. Visual Studio에서는? 이럴 때 뭘 해야 할까 생각해보다가 일단 Visual Studio에서 돌려보기로 했다. 왜냐하면 dotnet test 는 잘 돌아갔으므로 Visual Studio에서도 되지 않겠냐는 생각이 들었기 때문이다. 또, Visual Studio가 켜지고 ReSharper를 로드하는 모습을 보니 Visual Studio의 자체 단위 테스트 기능과 ReSharper를 비교해보면 더 확실히 할 수 있지 않을까 하는 생각이 들었다. 이 때까진 몰랐지. 이게 함정이 될 줄은. 아무튼 Visual Studio가 로드되고 프로젝트를 연 뒤, 우선은 ReSharper의 단위 테스트 기능을 먼저 실행하려 시도해봤다. 예상대로 작동하지 않는다. 증상 역시 똑같았다. 아예 단위 테스트 세션 자체가 생기질 않는다. 왜? 감지된 단위 테스트가 없으니까. 그래서 이제 Visual Studio의 자체 단위 테스트 윈도우를 열어봤더니, 아니나 다를까 정상적으로 로드되고 단위 테스트도 문제 없이 진행되는 것이 아닌가? 성급했던 결론

GitLab의 이름이 변경된 프로젝트로 계속 리다이렉트될 때

이미지
GitLab의 이름이 변경된 프로젝트로 계속 리다이렉트될 때 주의 들어가기 앞서, 이 글은 GitLab 호스팅이 아닌 GitLab 설치형 또는 옴니버스 기준으로 작성됨을 알린다. 리포지토리 이름 및 경로 변경 GitLab에서는 리포지토리의 이름을 바꾸거나 경로를 바꿀 수 있다. 이름만 바꾼다고 경로까지 바뀌지는 않고, 각각 따로 바꿀 수 있다. 리포지토리 이름 변경 리포지토리의 이름을 변경하려면 리포지토리의 Settings - General 로 이동하여 Naming, topics, avatar 섹션을 열고 Project Name 을 변경하면 된다. 리포지토리 이름 변경 리포지토리 경로 변경 하지만 리포지토리 이름을 변경한다고 해서 리포지토리 경로가 바뀌진 않는다. 예를 들어 기존에 https://honsal.io/honsals/HsStringTools 경로로 접근할 수 있었던 리포지토리의 이름을 HsStringTools 에서 HsStringToolsLegacy 로 변경한다고 해서 URL이 https://honsal.io/honsals/HsStringToolsLegacy 로 변경되지는 않는다는 말이다. 이걸 변경하려면 마찬가지로 Settings - General 로 이동하되 이번엔 Advanced 섹션에서 작업해야 한다. 경로 변경 경로 변경은 Change path 버튼을 누르면 적용된다. 리다이렉트 문제 내 생각에 대부분의 상황에서는 이렇게 하고 나서 아예 잊어버려도 아무런 문제가 없을 것이다. 심지어 기존 프로젝트 구성원에게 경로가 바뀌었으니 URL을 다르게 적용하라고 말하지 않아도 아무런 문제가 없을 것이다. 왜냐하면 GitLab이 (GitHub이 그렇듯이) 변경되기 전 경로를 자동으로 변경 후 URL로 리다이렉트 하기 때문이다. 문제는 리다이렉트하지 말아야 할 때 하지만 내 경우에는 이게 문제가 되었다. 이 GitLab 인스턴스는

Next.js You cannot dot into a client module from a server component 에러

Next.js You cannot dot into a client module from a server component 에러 Next.js 서버 컴포넌트 에러 Cannot access Box.prototype on the server. You cannot dot into a client module from a server component. You can only pass the imported name through. 세상이 좋아졌다. 분명 작년인지 재작년인지 까지만 해도 MUI 컴포넌트를 Next.js 서버 컴포넌트에서 사용할 수 없어 무조건 "use client" directive를 사용했어야 했던 것 같은데, 직렬화 가능하다는 전제조건 하에서 1 서버 사이드 렌더링이 가능해졌다. 문제는 졸린 와중에 작성한 코드에서 발생했다. 본 포스트 최상단에 기재해 놓은 에러가 바로 이번에 마주한 에러 메세지이다. 원인 파악 너무 졸려서 그랬을까? 혼란스러웠다. 왜냐하면 다른 페이지에서 사용하는 MUI Box 컴포넌트는 아무런 문제가 없었기 때문이다. 왜 이 페이지에서만 문제가 생겼을까 하는 생각에 커피를 한 잔 마시고 바람을 쐬고 다시 앉아 코드를 보니 차이점이 바로 보였다. .map() 원인은 바로 Array.map 을 사용해 컴포넌트를 생성하는 과정에 있었다. 어처구니 없게도, 아무리 졸렸다지만, 용납할 수 없게도 나는 해당 Box 컴포넌트를 key 프로퍼티 없이 생성해버렸다. { data . map ( ( channel ) => ( < Box > { channel . ownerName } < / Box > ) ) } 아래와 같이 변경하니 잘 되더라. { data . map ( ( channel , index ) => ( < Box key = { index } > { channel . ownerName }