Solid 2는 엄청난 업데이트입니다 (SolidStart 안녕)

BBetter Stack
컴퓨터/소프트웨어AI/미래기술

스크립트

00:00:00Solid 2가 드디어 출시되었으며, 이번 업데이트는 규모가 매우 큽니다.
00:00:03프레임워크에서 비동기 처리 방식을 완전히 개편하여 일등 시민(First-class) 기능으로 만들었으며,
00:00:07데이터 패칭, 로딩 상태, 반응성 측면에서 훨씬 더 뛰어난 개발자 경험을 제공합니다.
00:00:11이펙트(Effects)가 변경되었고, 스토어와 경계(Boundaries)도 바뀌었으며,
00:00:14수많은 SolidJSX 구문이 변경되었습니다. 그것만으로는 부족하다는 듯이,
00:00:17러스트(Rust)로 작성되어 이전보다 20배 이상 빠른 새로운 컴파일러 도구 체인이 추가되었고,
00:00:21플러그인에는 이제 start 모드가 기본 포함되어 Solid Start가 아예 필요 없게 되었습니다.
00:00:25사실 몇 주 전에 Solid Start 2가 출시되었지만,
00:00:27이번 업데이트를 통해 이제 이별을 고할 수 있게 되었습니다.
00:00:29이번 업데이트 전체가 프론트엔드 프레임워크의 진정한 혁신처럼 느껴지므로,
00:00:32어떤 점들이 바뀌었는지 자세히 살펴보겠습니다.
00:00:39Solid 2의 가장 큰 핵심은 비동기가 이제 반응형 그래프의 일부가 되었다는 점입니다.
00:00:44Solid 1에서는 비동기 데이터를 관리하기 위해 특별한 create resource 프리미티브를 사용해야만 했지만,
00:00:48여기서 fetch user로 하는 것처럼 말이죠. 그리고 그 리소스로부터,
00:00:50최신 해결된 값, 로딩 상태, 에러에 접근할 수 있었습니다.
00:00:54하지만 Solid 2에서는 이 과정이 훨씬 간단해집니다.
00:00:56이제 연산(Computations)이 직접 프로미스(Promises)를 반환할 수 있으므로, create memo 내부에서
00:00:59fetch user를 사용할 수 있습니다. 이제 user는 단순히 비동기인 메모(memo)일 뿐이며,
00:01:03하위의 모든 요소가 이를 자연스럽게 이해합니다.
00:01:05create resource는 제거되었습니다.
00:01:07눈치채셨겠지만 서스펜스 경계(suspense boundary)도 loading으로 대체되었습니다.
00:01:10모든 경계들이 새롭게 개편되어,
00:01:12suspense가 이제 제거되고 loading 경계를 사용하게 됩니다.
00:01:15데이터가 아직 없을 때(즉, 첫 결과가 없을 때) 폴백(fallback)을 렌더링하며,
00:01:18그 이후에는 새로운 값이 가져와지고 있는지 추적하기 위해 isPending을 사용할 수 있습니다.
00:01:22에러 경계(Error boundary)도 erud로 대체되었는데,
00:01:24대체로 내부적인 이름 변경 및 개편에 가깝고,
00:01:27suspense list 역시 reveal로 변경된 것도 마찬가지입니다.
00:01:30이러한 예시들만 보면 비동기 작업 관련 변경이 단순한 이름 변경처럼 보일 수 있지만,
00:01:34내부적으로는 프레임워크에서 비동기를 다루는 완전히 새로운 접근 방식입니다.
00:01:37Ryan이 레딧(Reddit)에 이를 설명하기 위한 다이어그램을 게시했으니,
00:01:40완벽한 심층 분석을 위해 해당 글을 읽어보시는 것을 추천합니다.
00:01:42하지만 요약하자면, 대부분의 프레임워크는 프로미스를 소비하는 것과 동시에 서스펜스 경계로 UI를 차단합니다.
00:01:47React의 use()나 Svelte의 await처럼 말이죠. 하지만 Solid 2는 생성 시점에 프로미스를 그래프로 소비하고
00:01:52실제로 값이 읽히는 곳에서 차단(blocking)을 수행합니다.
00:01:54React에서 이를 확인할 수 있습니다. 부모 컴포넌트에 모든 프로미스가 있고 리플레이를 누르면,
00:01:59요청이 UI를 차단하고 있기 때문에 첫 번째 서스펜스 경계 폴백만 계속 보게 되며,
00:02:03모든 요청이 끝날 때까지 기다리게 됩니다.
00:02:05프로미스를 전달하거나 컴포넌트를 함께 배치하는 등의 다른 방법으로 이를 해결할 수 있지만,
00:02:09항상 개발자 경험(DX)과 사용자 경험(UX) 사이의 타협이 필요했습니다.
00:02:12Solid 1도 이를 부분적으로 해결하긴 했습니다. 여기서 create resource로 모든 프로미스가 소비되고 있으며,
00:02:16리플레이를 누르면 데이터가 읽힐 때 사용자 프로필이 표시되고,
00:02:20데이터가 준비될 때까지 팀 스켈레톤이 표시됩니다. 팀 컴포넌트도 마찬가지입니다.
00:02:24따라서 데이터가 준비되면 UI가 즉시 업데이트되므로 사용자 경험 문제는 해결되었습니다.
00:02:28하지만 Solid 1의 문제는 리소스로부터 얻은 값을 다룰 때 널(null) 및 언디파인드(undefined) 체크를
00:02:32곳곳에 흩뿌려야 했다는 점입니다. Solid 2는 이 모든 것을 해결합니다.
00:02:36create memo로 프로미스를 소비하면 프로미스가 즉시 그래프에 들어가고,
00:02:40그 시점부터는 프로미스가 아닌 순수 값만 다루게 됩니다. 따라서 이 모든 중첩된 컴포넌트들은
00:02:44순수하게 프리젠테이셔널(Presentational)해질 수 있으며, 값에 더 이상 undefined 상태가 존재하지 않습니다.
00:02:49따라서 코드에서 그러한 체크들을 모두 제거할 수 있고, 동시에 loading 경계를 사용하여
00:02:52Solid가 값이 준비되었는지 여부를 처리하도록 할 수 있습니다. 이를 통해 최고의 사용자 경험을 얻을 수 있으며,
00:02:56UI가 준비될 때 표시되면서도 코드가 더 깔끔해지므로 개발자 경험도 훨씬 좋아집니다.
00:03:00구독을 하시면 이와 같은 AI 및 개발 소식을 최신으로 받아볼 수 있어 개발자 경험이 훨씬 좋아집니다.
00:03:04지금까지 비동기에 대해 언급한 내용은 모두 '읽기'에 관한 것이었지만, '쓰기'는 어떨까요?
00:03:08낙관적 업데이트(Optimistic updates)를 수행하는 방식에도 일부 변경 사항이 있기 때문입니다.
00:03:13Solid 1에서는 낙관적 업데이트에 리소스 mutate 함수를 사용했지만, 이는 실제로 제거되었으며
00:03:18action, create optimistic, create optimistic store를 이용한 훨씬 멋진 흐름으로 대체되었습니다.
00:03:23할 일(to-do) 앱에 낙관적 업데이트를 적용하고 싶다면, 먼저 서버 페치인 진실의 원천(source of truth)으로
00:03:27낙관적 스토어를 생성한 다음, 할 일 추가 액션을 만들고,
00:03:31로컬 스토어에 할 일을 즉시 추가하고 저장 API를 실행한 뒤, 완료되면 서버에서 새로고침을 호출합니다.
00:03:35Action은 뮤테이션에 라이프사이클을 부여하므로, 낙관적 스토어에 만드는 로컬 변경 사항은
00:03:40이 액션의 수명 동안에만 존재합니다. 즉, 이 API 호출에서 에러가 발생하면
00:03:44낙관적 오버라이드가 사라지고 UI가 신뢰할 수 있는 원래 값으로 돌아간다는 뜻입니다.
00:03:49따라서 이제 자동 롤백 기능이 제공되는데, 이는 Solid 1에서 수동으로 처리하던 것에 비해 꽤 멋진 변화입니다.
00:03:52Solid 개발자분들이라면 낙관적 스토어에 대한 특별한 점을 눈치채셨을지도 모릅니다.
00:03:56여기서 직접 변형(mutated)할 수 있는 초안(draft)을 제공했다는 점이죠.
00:04:01이러한 변경 사항은 모든 스토어에 걸쳐 적용되었으므로,
00:04:04더 이상 produce 함수가 필요 없습니다. create mutable과 함께 제거되었으며, 이제 기본 동작이 되었기 때문입니다.
00:04:08하지만 예전 방식을 원한다면 여전히 store path 헬퍼를 사용할 수 있습니다.
00:04:12이펙트로 넘어가보면, 이 부분에서도 큰 변화가 있었습니다. Solid 1에서는 이펙트가
00:04:17읽는 모든 것을 추적하는 것과 사이드 이펙트를 동시에 수행하는 하나의 함수였습니다.
00:04:21Solid 2는 이를 둘로 나누어 의존성 추적과 사이드 이펙트를 분리합니다.
00:04:26첫 번째 함수는 값을 계산하고 추적되며, 두 번째 함수는 추적되지 않고(untracked) 값을 받아.
00:04:30실제 작업을 수행합니다. 이를 통해 무엇에 의존하는지와 그에 대해 무엇을 할지 사이의 분리가 이루어지며.
00:04:34이는 계산 함수에서 처리되기 때문에 on 함수의 필요성을 대체합니다.
00:04:39그리고 on 함수가 가지고 있던 defer 옵션을 원한다면, 이제 이펙트의 옵션으로 간단히 지정할 수 있습니다.
00:04:43이와 함께 create computed도 제거되었습니다. 파생된 값이 필요하면 메모를 사용하고.
00:04:47사이드 이펙트가 필요하면 분할된 이펙트(split effect)를 사용하면 되기 때문입니다. 이펙트 정리(cleanup)와 관련해서도.
00:04:52변화가 생겼습니다. 함수 본문 내부에서 on cleanup을 호출하는 대신,
00:04:56apply 함수가 단순히 정리 함수를 반환하는 방식(React의 접근 방식과 유사함)으로 바뀝니다.
00:05:01on mount 함수에도 동일한 변경이 적용되어 이제는 on settled가 되었습니다. 콜백에서 정리 함수를 반환하면 됩니다.
00:05:05on settled는 단순히 컴포넌트가 마운트될 때가 아니라 그 하위의 모든 비동기 작업이 해결되었을 때 실행됩니다.
00:05:10시그널(Signals)의 경우 사용하는 방식 자체는 크게 달라지지 않았지만, 내부적인 차이가 있습니다.
00:05:14Solid 2는 쓰기 작업을 스테이징하고 다음 마이크로 태스크에서 커밋하므로,
00:05:18시그널을 설정한 바로 다음 줄에서 읽으면 이전 값을 얻게 됩니다.
00:05:22하지만 당장 값이 필요하다면 flush 함수를 사용하여 강제로 값을 밀어 넣을 수 있습니다.
00:05:26이러한 변경으로 인해 연속된 쓰기 작업은 기본적으로 이미 하나의 배치(batch)를 공유하므로,
00:05:30더 이상 감쌀 필요가 없어 batch가 제거되었습니다. 다루고자 했던 비동기 및 반응성 변경 사항은.
00:05:34대략 이 정도면 된 것 같으니, HTML에 더 가까운 DOM 모델을 목표로 개편된 JSX를 살펴보겠습니다.
00:05:39클래스부터 시작하면, class list는 이제 사라졌습니다.
00:05:44대신 이제 class 속성 자체가 문자열, 객체, 배열을 모두 허용합니다. 조건부 스타일의 경우.
00:05:48간단히 객체를 사용할 수 있으므로 더 이상 문자열 결합, filter, join 트릭이 필요 없습니다.
00:05:52속성(Attributes)도 동일한 처리를 받아 attribute 및 bool 접두사가 사라졌으며.
00:05:56표준 속성을 그대로 작성하고 불리언은 일반 HTML 존재 및 부재 규칙을 따르므로,
00:06:00값이 truthy일 때만 속성이 나타납니다. on 및 on capture도 사라졌으며.
00:06:04이제 카멜 케이스 이벤트 프로필을 사용하고, 네이티브 리스너 옵션이 필요하면 ref 콜백과 addEventListener를 사용하세요.
00:06:08디렉티브의 경우 유저 네임스페이스가 사라졌고, ref 콜백과 디렉티브 팩토리로 대체되었습니다.
00:06:13그리고 ref는 이제 배열을 받으므로 래퍼 함수 없이도 동일한 요소에 여러 디렉티브를 스택할 수 있습니다.
00:06:17JSX에 머물러서, 리스트도 단순화되었습니다. Solid 1에서는.
00:06:23배열을 렌더링하기 위해 for와 index라는 두 가지 컴포넌트가 있었습니다. for는 키가 지정되어 각 항목이 아이덴티티로 매칭되었고.
00:06:28index는 그 반대로 위치(position)로 매핑되었습니다. 하지만 Solid 2에서는 index가 제거되어.
00:06:32이제 for만 남았지만, keyed prop을 false로 설정하면 해당 index 동작을 다시 구현할 수 있습니다.
00:06:37그리고 JSX 변경 사항의 마지막으로 repeat이라는 새로운 컴포넌트도 생겼습니다. 배열을 받는 대신.
00:06:42이 컴포넌트는 개수로 렌더링하며, 시작 인덱스와 개수를 주면 각 행이 스토어에서 자신의 슬롯을 읽으므로.
00:06:47하나의 행을 업데이트해도 다른 것은 전혀 건드리지 않습니다. 프레임워크 관점에서의 주목할 만한 변경 사항은 드디어 이게 전부인 것 같으니,
00:06:52이제 도구(Tooling)에 집중해 보겠습니다. Vite 플러그인에 두 가지 큰 변경 사항이 생겼고,
00:06:57그중 두 번째 변경 사항 덕분에 solid start가 더 이상 존재할 필요가 없어졌습니다. 먼저 컴파일러입니다.
00:07:01Solid 2는 Oxy 기반으로 러스트로 작성된 완전히 새로운 컴파일러 도구 체인을 탑재했으며 Vite 플러그인이 이를 기본값으로 사용하므로.
00:07:06사용자가 별도의 변경을 할 필요는 없습니다. 벤치마크에 따르면,
00:07:10테스트 프로젝트의 컴파일 시간이 약 440밀리초에서 불과 19밀리초로 단축되었고, 더 큰 1메가바이트
00:07:16단일 모듈에서는 25초에서 단 70밀리초로 단축되어 무려 355배 빨라졌습니다. 두 번째 변경 사항은 더 큰 변화입니다.
00:07:24플러그인에 이제 자체 start 모드가 생겼습니다. 이를 통해 인덱스 HTML 스크립트나 엔트리 파일 없이
00:07:28순수 Vite에서 완전한 앱 빌드를 수행할 수 있습니다. 기본적으로 이는 클라이언트 전용 모드로 작동하여
00:07:33빌드 시 순수 정적 파일만 출력되지만, 서버 번들을 함께 빌드하여 서버 사이드 렌더링을 원할 경우 SSR을 활성화할 수도 있습니다.
00:07:38참고로 서버 함수를 좋아하신다면 use server가 이제 핵심 기능입니다. 그뿐만 아니라,
00:07:42라우터 중립적인 패키지를 통해 파일 시스템 라우팅을 사용할 수 있으며, solid start의 검증된 규칙들, HMR, 코드 분할 등을 제공합니다.
00:07:47라우터 중립적인 패키지를 통해 파일 시스템 라우팅을 사용할 수 있으며, solid start의 검증된 규칙들, HMR, 코드 분할 등을 제공합니다.
00:07:51이 세팅이 정말 마음에 드는 이유는 배포가 정적 파일이거나, 혹은 웹 표준 fetch 핸들러를 내보내는 서버 모듈이기 때문입니다.
00:07:56Cloudflare Workers, Netlify, Nitro, Bun, Deno 등이 이미 지원하는 방식이므로
00:08:01중간에 Solid 전용 어댑터 없이 플랫폼 자체 도구로 배포할 수 있습니다.
00:08:06그렇다면 이제 solid start는 더 이상 필요 없다는 뜻이 됩니다. 블로그 글에서 말하듯.
00:08:10solid start는 자신의 역할을 다했습니다. Solid의 공백을 채우기 위한 메타 프레임워크였지만, 이제 2 버전이 그 모든 기능을 집으로 가져왔습니다.
00:08:14현재 solid start를 사용 중이시라면 오늘 당장 바뀌는 것은 없습니다. 유지보수 업데이트는 계속 제공될 것이며,
00:08:18전환하고 싶다면 해당 마이그레이션 가이드를 확인하시면 됩니다.
00:08:22하나의 영상에 담을 수 있는 업데이트는 대략 이 정도입니다. 이번 업데이트가 엄청난 규모의 변경 사항과.
00:08:26API 제거를 담은 대단한 업데이트라는 것을 알 수 있으며, 제가 다루지 않은 부분도 몇 가지 있을 겁니다.
00:08:30start transition이나 use transition이 제거된 것 같은 말이죠. 따라서 전체 목록을 원하신다면
00:08:34solid 1에서 solid 2로의 마이그레이션 가이드를 확인해보시는 것을 추천하며, 이는 AI에게 마이그레이션을 부탁하기에도.
00:08:39아주 훌륭한 리소스입니다. 저도 solid 1과 solid 2를 오가며 작업을 해보았는데,
00:08:43Claude Code가 이 문서를 바탕으로 모든 변경 사항을 잘 이해하고 파악하는 것 같았습니다.
00:08:47이번 업데이트를 깊이 있게 파고들어 정말 즐거웠고 솔직히 말씀드리면.
00:08:51Solid를 안 쓴 지 좀 되었는데, Solid 2 덕분에 아주 쉽게 다시 시작할 수 있었고 사용하기도 꽤 즐거웠습니다.
00:08:55그래서 앞으로는 조금 더 자주 쓰게 될 것 같습니다. 여러분은 어떻게 생각하시나요? 예전에 Solid를 써보신 적이 있으신가요,
00:08:59그리고 이번 업데이트가 마음에 드시나요? 아래 댓글로 남겨주시고
00:09:02구독도 부탁드리며, 늘 그렇듯 다음 영상에서 뵙겠습니다.

핵심 요약

Solid 2는 러스트 기반 컴파일러 도입과 비동기 처리 및 메타프레임워크 기능의 코어 통합을 통해 개발자 경험과 빌드 성능을 대폭 혁신했다.

하이라이트

  • Solid 2는 러스트로 작성된 새로운 Oxy 기반 컴파일러 도구 체인을 도입하여 컴파일 시간을 최대 355배 단축시켰다.

  • Solid 2에서는 비동기 처리가 반응형 그래프의 일등 시민으로 편입되면서 create resource 프리미티브가 완전히 제거되었다.

  • Solid 2 Vite 플러그인에 내장된 start 모드를 통해 별도의 Solid Start 프레임워크 없이 정적 파일 빌드 및 SSR 서버 모듈을 지원한다.

  • 시그널 쓰기 작업이 다음 마이크로 태스크로 스테이징 및 커밋되도록 변경되면서 기존 batch 함수가 제거되었다.

  • 새로운 반복 렌더링 컴포넌트인 repeat은 시작 인덱스와 개수를 받아 각 행이 스토어의 슬롯을 직접 읽도록 처리한다.

타임라인

비동기 처리 개편과 프리미티브 변경

  • 비동기 작업이 반응형 그래프의 일부가 되어 연산이 프로미스를 직접 반환할 수 있게 되었다.
  • 기존의 create resource 프리미티브와 suspense 경계가 각각 제거되고 새로운 loading 경계로 대체되었다.
  • 프로미스가 생성 시점에 그래프로 소비되므로 하위 컴포넌트에서 언디파인드 체크 없이 순수 값으로 다룰 수 있다.

Solid 2는 프레임워크 전반의 비동기 처리 방식을 근본적으로 개편하여 개발자 경험을 향상시켰다. 연산 내부에서 프로미스를 직접 다룰 수 있게 되면서 데이터 패칭과 관련된 복잡한 예외 처리 코드가 대폭 줄어들었다. 또한 기존 suspense 대신 도입된 loading 경계는 데이터 준비 상태를 효율적으로 추적하며 사용자 경험을 최적화한다.

낙관적 업데이트 및 이펙트 시스템 변경

  • 낙관적 업데이트는 action, create optimistic, create optimistic store를 통해 자동 롤백 기능을 제공한다.
  • 이펙트는 의존성 추적과 사이드 이펙트 함수로 분할되어 on 함수의 필요성을 대체했다.
  • 시그널 쓰기 작업이 마이크로 태스크로 연기되면서 연속 쓰기 시 자동 배치 처리로 인해 batch 함수가 제거되었다.

쓰기 작업과 사이드 이펙트 관리 방식이 대대적으로 정비되었다. 낙관적 업데이트 과정에서 에러가 발생하면 로컬 변경 사항이 자동으로 사라지고 원래 값으로 돌아오는 자동 롤백 기능이 탑재되었다. 또한 의존성 추적과 실제 사이드 이펙트를 수행하는 로직이 분리되어 코드가 더욱 명확해졌으며, 시그널 변경 사항이 자동으로 묶이면서 불필요한 배칭 도구가 사라졌다.

JSX 간소화 및 도구 체인 혁신

  • class 리스트와 attribute/bool 접두사가 사라지고 표준 속성 및 유연한 객체 구문이 도입되었다.
  • 러스트 기반 Oxy 컴파일러가 도입되어 테스트 프로젝트의 컴파일 시간이 최대 355배 빨라졌다.
  • Vite 플러그인에 start 모드가 기본 포함되면서 별도의 Solid Start 없이 순수 Vite 기반 빌드 및 SSR이 가능해졌다.

DOM 모델에 더 가까워진 JSX 문법 개편을 통해 조건부 클래스 적용과 리스트 렌더링이 대폭 간소화되었다. 특히 러스트로 작성된 새로운 컴파일러 도구 체인은 대형 모듈의 컴파일 속도를 극적으로 단축시켰다. 아울러 Solid Start 메타프레임워크의 기능이 코어 플러그인 내부에 통합됨으로써 별도의 어댑터 없이 웹 표준 fetch 핸들러 기반 배포를 직접 지원하게 되었다.

커뮤니티 글

모든 글 보기