ms clarity2023. 5. 26.
ms의 analytics 툴 clarity의 설치 스크립트는 이렇게 생겼다.
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
// ^^^^^^^^^^^^^ 귀엽...
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
// ...
</script>
Extracting Image Dimensions from Remote Sources2023. 5. 25.
Before
- til을 위해 repo issues를 cms로 쓰고 있었고,
- issue body render를 위해 github api reponse 중
bodyHTML
을dangerously...
에 넣어주고 있었음. - 근데 이러면 next가 해주는 이것저것이 아까우므로,
- api response 중
body
(markdown string)을 mdx renderer에 넘겨서 써야겠다고 생각.
Issues
- next-mdx-remote를 쓰면 되고 딱히 별 문제는 없음(rsc도 지원).
- 한가지, 이미지 최적화 기능을 위해선
next/image
를 써야하는데, - static import일 경우엔 알아서 해주지만,
- remote url일 경우엔
width
/height
정보를 넘겨줘야함. - 근데 이걸 어떠케 알어요...
How?
- probe-image-size라는 라이브러리가 있고,
- mdx renderer option의
component
설정시<img />
-><Image />
로 replace 하면서 요걸 사용해서width
/height
정보를 넘겨주면 됨. - 코드는 대충 이런식:
import probe from "probe-image-size" // ... const components: MDXRemoteProps["components"] = { // ... // @ts-expect-error <- ts는 아직 async 컴포넌트를 모르지만 우리는 rsc 세계로 넘어왔으므로 ok. img: async ({ src, alt }) => { if (!src) return null const { width, height } = await probe(src ?? "") // ^^^^^ rsc ftw... if (!width || !height) return null return <Image src={src} alt={alt ?? ""} width={width} height={height} /> }, // ... } // ...
import probe from "probe-image-size" // ... const components: MDXRemoteProps["components"] = { // ... // @ts-expect-error <- ts는 아직 async 컴포넌트를 모르지만 우리는 rsc 세계로 넘어왔으므로 ok. img: async ({ src, alt }) => { if (!src) return null const { width, height } = await probe(src ?? "") // ^^^^^ rsc ftw... if (!width || !height) return null return <Image src={src} alt={alt ?? ""} width={width} height={height} /> }, // ... } // ...
Result
최종 렌더된 이미지의 url을 보면
next가 잘 처리하고 있음을 알 수 있음.
Conclusion
RSC는 대박이다...
`generateStaticParams`를 사용하는 페이지에서 서버 액션을 호출하면 `405` 에러 (2023-05-24 현재)2023. 5. 24.
좋아요 버튼을 달려고 @vercel/kv 랑 요렇게 저렇게 해보고 있었는데 아래 에러가 무한히 발생했다.
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
at AppContainer (/Users/sehyunchung/personal/sehyunchung.dev/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/server/render.js:337:29)
at AppContainerWithIsomorphicFiberStructure (/Users/sehyunchung/personal/sehyunchung.dev/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/server/render.js:373:57)
at div
at Body (/Users/sehyunchung/personal/sehyunchung.dev/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/server/render.js:673:21)
Warning: Detected multiple renderers concurrently rendering the same context provider. This is currently unsupported.
..
검색을 해봐도 뭐가 안나와서 'use server'
를 파일에 넣었다 함수에 넣었다 이케저케 해봐도 안됐는데 어쩌다 브라우저 콘솔을 열어보니
네트워크 탭을 확인해보니
요걸로 검색해보니 아래 이슈가 나왔다.
[NEXT-1167] Server Actions 405 "Method Not Allowed" when using generateStaticParams #49408
생각해보면 말이 되는 것 같기도... 근데 안되면 안되는데?
`@vercel/og` Cheatsheet (?)2023. 5. 24.
- @vercel/og
- Edge Runtime 환경 기반으로 동작함.
- 이미지 렌더에 satori를 사용하는데,
- react element를
svg
로 변환하는 라이브러리이고, - React Native의 Flexbox layout engine을 사용하므로, css의 모든 기능을 사용할 순 없다.
- e.g.
z-index
,calc()
등 사용 불가능.
- e.g.
- react element를
- app router 사용시
app/og/route.tsx
혹은app/og.tsx
등등으로 파일을 만들면 됨..ts
도 사용할 수 있으나 고러면jsx
를 사용할 수 없겟쥬
- 커스텀 폰트를 사용할 수 있으나
next/font
외에 별도로 로컬에서 폰트 파일을 가져와야 함. (리모트는 아직 안해봄).ttf
,.woff
사용 가능 (.woff2
는 안됨)
- 대략의 api는 아래와 같음.
new ImageResponse( element: ReactElement, options: { width?: number = 1200 height?: number = 630 emoji?: 'twemoji' | 'blobmoji' | 'noto' | 'openmoji' = 'twemoji', // emoji render에 어떤 lib을 사용할 것인지 fonts?: { name: string, data: ArrayBuffer, // 폰트 파일 데이터. fetch(URL).then(res => res.imageBuffer())로 가져오면 된다. weight: number, style: 'normal' | 'italic' }[] debug?: boolean = false // true 일 경우 각 element의 border, line-height 등이 표시됨. status?: number = 200 statusText?: string headers?: Record<string, string> }, )
new ImageResponse( element: ReactElement, options: { width?: number = 1200 height?: number = 630 emoji?: 'twemoji' | 'blobmoji' | 'noto' | 'openmoji' = 'twemoji', // emoji render에 어떤 lib을 사용할 것인지 fonts?: { name: string, data: ArrayBuffer, // 폰트 파일 데이터. fetch(URL).then(res => res.imageBuffer())로 가져오면 된다. weight: number, style: 'normal' | 'italic' }[] debug?: boolean = false // true 일 경우 각 element의 border, line-height 등이 표시됨. status?: number = 200 statusText?: string headers?: Record<string, string> }, )
- 대략의 사용례는 아래와 같음.
// app/og/route.tsx import { ImageResponse } from 'next/server'; // app router 사용시 @verce/og가 포함되어 있음 export const runtime = 'edge'; const font = fetch(new URL('../path/to/font/Font.woff', import.meta.url)).then( (res) => res.arrayBuffer(), ); export async function GET(request: Request) { const fontData = await font; // query param으로 이런 저런 텍스트를 동적으로 넣을 수 있음. const url = new URL(request.url) const searchParams = url.searchParams const title = searchParams.has("title") ? searchParams.get("title") : null return new ImageResponse( ( <div style={{ backgroundColor: 'white', height: '100%', width: '100%', fontSize: 100, fontFamily: '"Font"', paddingTop: '100px', paddingLeft: '50px', }} > {title ? title : 'Hello World!'} </div> ), { width: 1200, height: 630, fonts: [ { name: 'Font', data: fontData, style: 'normal', }, ], }, ); }
// app/og/route.tsx import { ImageResponse } from 'next/server'; // app router 사용시 @verce/og가 포함되어 있음 export const runtime = 'edge'; const font = fetch(new URL('../path/to/font/Font.woff', import.meta.url)).then( (res) => res.arrayBuffer(), ); export async function GET(request: Request) { const fontData = await font; // query param으로 이런 저런 텍스트를 동적으로 넣을 수 있음. const url = new URL(request.url) const searchParams = url.searchParams const title = searchParams.has("title") ? searchParams.get("title") : null return new ImageResponse( ( <div style={{ backgroundColor: 'white', height: '100%', width: '100%', fontSize: 100, fontFamily: '"Font"', paddingTop: '100px', paddingLeft: '50px', }} > {title ? title : 'Hello World!'} </div> ), { width: 1200, height: 630, fonts: [ { name: 'Font', data: fontData, style: 'normal', }, ], }, ); }
- tailwind 사용이 가능한데 아직
experimental
이 붙어있고className
말고tw
를 사용하도록 되어있음. - Hobby plan일 경우 단일 function당 1MB 제한이 있어 한글 커스텀 폰트를 추가하긴 쉽지 않았음.
- sehyunchung.dev에 적용해본 결과 -> https://sehyunchung.dev/og?title=암온더넧렙을&description=절대적룰을지켜
Urge Surfing2023. 5. 23.
"...general principle is that if we look at the Mind urges or Cravings arise but if we're able to tolerate that for some amount of time if were able to surf on top of the urge instead of give in to it over time that urge will actually go away."
The Real Reason You Never Follow Through (And How to Fix It)
Vercel Edge Function size limit2023. 5. 22.
@vercel/og
로 og image generation을 하는 김에 폰트도 맞춰보려고 일케절케 하다보니
Error: The Edge Function "api/og" size is X MB and your plan size limit is 1 MB. Learn More: https://vercel.link/edge-function-size
라면서 빌드가 터짐.
왜냐?
- og image generation에 커스텀 폰트를 사용하려면
.ttf
혹은.woff
(.woff2
는 안됨)를fetch
로 불러와서arrayBuffer
로 만들어야 함 - 영어 폰트의 자수는 72자
- 근데 한글 폰트는 서브셋 처리를 해도 2,350자
- 그래서 한글 폰트를 일단 불러오면 1MB 안엔 안들어감
- 돈을 더 내거나 더 줄인 서브셋을 만들어야 함
- 돈을 더 낼 순 없다 왜냐면 암것도 모르는 영어권 놈들(...)이 책정한 가격이니까
- 자수를 더 줄인 서브셋 만들기는 아직 방법도 모르므로 이후로 미룸
- 일단 한글 커스텀 폰트를 뺐더니
- 빌드에 성공함
- 영어!!!! ㅠㅠㅠ
Changing Learning Environment IS Beneficial2023. 5. 22.
Q: How important is routine when it comes to learning? For example, is it important to have a dedicated study area?
A: Not at all. Most people do better over time by varying their study or practice locations. The more environments in which you rehearse, the sharper and more lasting the memory of that material becomes—and less strongly linked to one “comfort zone.” That is, knowledge becomes increasingly independent of surroundings the more changes you make—taking your laptop onto the porch, out to a café, on the plane. The goal, after all, is to be able to perform well in any conditions. Changing locations is not the only way to take advantage of the so-called context effect on learning, however. Altering the time of day you study also helps, as does changing how you engage the material, by reading or discussing, typing into a computer or writing by hand, reciting in front of a mirror or studying while listening to music: Each counts as a different learning “environment” in which you store the material in a different way.
Benedict Carey, How We Learn. Random House Trade Paperbacks; Reprint edition (June 9, 2015) p. 201
Why does Windows use `\` while everyone else uses `/`?2023. 5. 20.
Me: "Why does Windows use \
while everyone else uses /
?"
GPT-4: "The reason for the difference lies in the history of the two operating systems and the choices made by their developers.
Microsoft's Windows OS uses backslashes (\
) as a path separator due to its legacy of MS-DOS. MS-DOS was heavily influenced by an older operating system named CP/M, which did not have a hierarchical file system, meaning it did not have directories/folders and therefore did not need a directory separator character. When Microsoft introduced directories in MS-DOS 2.0, they needed a character to act as a directory separator, but the forward slash (/
) was already being used as the switch character (a kind of option flag) for command-line arguments. Therefore, Microsoft chose the backslash (\
) to avoid breaking compatibility with existing software.
On the other side, Unix and Unix-like systems (including Linux and MacOS), use the forward slash (/
) as a path separator. The forward slash was chosen as a directory separator in Unix due to its simplicity and ease of use in a command line interface. The forward slash was available because Unix uses the hyphen - for command-line options, not the forward slash.
It's worth noting that although Windows primarily uses backslashes for paths, it does understand forward slashes in most contexts. However, because the backslash is the standard, Windows software often expects paths to be written with backslashes and can behave unexpectedly if they're not."
Split string into array2023. 5. 18.
words="hello hello how low?"
array=($words);
for word in "${array[@]}"; do
echo $word
done
words="hello hello how low?"
array=($words);
for word in "${array[@]}"; do
echo $word
done
hello
hello
how
low?
hello
hello
how
low?
git diff current branch against upstream2023. 3. 24.
git diff HEAD..@{u}
git diff HEAD..@{u}