00. 설치
This content is not available in your language yet.
대상 독자: Roblox Studio 또는 Luau CLI 툴체인(Rojo, pesde 등) 환경에서 Quad를 프로젝트에 붙이려는 개발자 목표: 패키지를 내려받아 게임 트리에 올리고, 타입 검사 플래그를 켜기
이 장은 까는 것만 다룹니다. 실제로 화면에 무언가를 띄우는 건 다음 장인 01. 프레임워크 설정하기입니다.
1. 배포 방식 한눈에 보기
섹션 제목: “1. 배포 방식 한눈에 보기”Quad는 아래 세 가지 경로로 배포합니다. [2026-11-04 기준] 제공되는 건 pesde 경로 하나입니다(pesde 레지스트리에 4.0.0이 게시됨) — Wally 게시와 릴리스 페이지는 아직 없습니다.
| 배포 방식 | 추천 대상 | 필요한 도구 | 상태 |
|---|---|---|---|
| 1. pesde + Rojo | Luau 패키지 매니저를 쓰는 프로젝트 | pesde, rojo |
제공 중 (4.0.0) |
| 2. Wally + Rojo | 이미 Wally를 쓰고 있는 프로젝트 | wally, rojo |
미제공 |
3. Standalone .rbxm |
CLI 도구 없이 Studio만 쓰는 경우 | 없음 | 미제공 |
Wally나 .rbxm으로는 못 쓰나요?
아직 그 경로가 없습니다. Wally 레지스트리 게시도, 배포용 .rbxm을 올릴 릴리스 페이지도 준비되지 않았습니다 — 생기면 이 절에 패키지 이름·버전과 링크를 채워 넣습니다.
Wally로 오게 되더라도 받을 것은 셋입니다. 01장의 설정 모듈이 quad_types를 require해 타입을 다시 내보내기 때문에, quad_base·quad_roblox만으로는 그 require가 풀리지 않습니다.
2. pesde + Rojo
섹션 제목: “2. pesde + Rojo”pesde는 의존성을 내려받아 배치하는 도구일 뿐, Studio 안의 ModuleScript로 싱크해 주지는 않습니다. 따라서 Rojo가 반드시 함께 필요합니다 — pesde가 디스크에 놓은 폴더를 게임 트리로 투영하는 건 Rojo의 몫입니다.
1단계: 패키지 셋 추가
섹션 제목: “1단계: 패키지 셋 추가”[dependencies]quad_base = { name = "qwreey/quad_base", version = "^4.0.0" }quad_roblox = { name = "qwreey/quad_roblox", version = "^4.0.0" }quad_types = { name = "qwreey/quad_types", version = "^4.0.0" }셋을 직접 적는 데는 각각 이유가 있습니다.
quad_roblox— Roblox 백엔드. 여러분이 실제로 쓰는q.Elem·q.Modifier등이 여기서 옵니다.quad_base—quad_roblox는 이걸 개발 의존성으로만 잡습니다(런타임에는 모듈 인스턴스를 인자로 받으므로 require하지 않습니다). 개발 의존성은 소비자에게 전파되지 않으니 직접 적어야 합니다.quad_types— 타입만 든 패키지입니다. 01장의 설정 모듈이 이걸 require해 타입을 다시 내보내는데, 직접 의존성으로 적어야 최상위에 링커가 생겨 그 require가 풀립니다.
quad_error / type_version_check는 위 셋의 의존성으로 따라 들어오므로 적을 필요가 없습니다(이 둘은 quad에 묶이지 않은 범용 패키지라 4.0.0부터는 각자의 번호로 올라갑니다). ^4.0.0은 4.x 안의 갱신을 모두 받겠다는 뜻입니다 — 4.0.0부터 호환이 깨지는 변경은 메이저 버전에만 실립니다(안정성). 정확한 버전으로 고정하려면 version = "4.0.0"처럼 쓰되, 적은 패키지를 모두 같은 버전으로 고정하세요 — 일부만 고정하면 나머지가 새 버전으로 풀려 서로 맞지 않을 수 있습니다. 이 문서의 예제는 4.0.0 기준입니다. 3.x에서 올 때는 CHANGELOG의 4.0.0 항목을 보세요 — 3.x는 안정화 구간이라 마이너 릴리즈에서도 호환이 깨질 수 있었고, 3.3.0 이하에는 q.Elem·q.Spread·q.Raw·q.NewModule이 없습니다(옮기는 법은 CHANGELOG의 3.4.0 항목과 scripts/migrate-3.4.py).
이름을 적을 때 주의할 것이 하나 있습니다. 저장소상 패키지 이름은 언더스코어만 씁니다 — qwreey/quad_base, qwreey/quad_roblox처럼요(폴더 이름은 quad-base/quad-roblox로 하이픈이고, 매니페스트의 name만 언더스코어입니다). 직접 적는 세 패키지가 같은 버전으로 게시되며 현재 버전은 4.0.0입니다. 저장소 루트의 qwreey/quad는 워크스페이스 루트일 뿐 게시 대상이 아니라(private = true) 이 이름으로는 설치할 수 없습니다.
2단계: Rojo 프로젝트 맵 연결
섹션 제목: “2단계: Rojo 프로젝트 맵 연결”pesde는 설치 디렉터리를 “의존 대상 패키지 자신의 target” 이름으로 나눕니다. 다섯 패키지 중 quad_roblox만 roblox 타깃이고, 나머지 넷은 luau·roblox 두 타깃으로 게시됩니다. 그래서 여러분의 매니페스트 [target] environment가 roblox이면 다섯 개가 전부 roblox_packages/ 하나에 들어옵니다. 이 경우 luau_packages/는 생기지 않습니다.
타깃이 roblox가 아니면 어떻게 되나요?
environment가 roblox가 아니면(예: luau) 넷의 luau 사본이 luau_packages/로 들어가므로 그 디렉터리도 트리에 올려야 합니다.
pesde는 설치 디렉터리 안에 얇은 링커를 놓고 실체는 .pesde/ 아래에 둡니다 — 직접 적은 셋만 최상위에 링커가 생기지만, 따라 들어오는 둘도 그 아래로 링크되므로 트리에 올릴 건 roblox_packages/ 하나입니다(그 폴더를 통째로 매핑해야 하는 이유는 아래 매핑 지시에 있습니다).
roblox_sync_config_generator스크립트 — pesde는 roblox 타깃 프로젝트의 매니페스트에[scripts] roblox_sync_config_generator가 없으면 설치 때not having a roblox_sync_config_generator script in the manifest might cause issues with linking경고를 냅니다. pesde 공식 Roblox 가이드가 안내하는 scripts 패키지를 매니페스트에 넣어 두는 걸 권장합니다.
이 문서의 예제들은 아래 모양을 씁니다. 디스크의 src/client/UI/가 게임 트리의 ReplicatedStorage.Client.UI가 되고, 진입점 하나가 StarterPlayerScripts로 갑니다.
src/client/UI/Quad.luau → ReplicatedStorage/Client/UI/Quad (설정 모듈, 01장)src/client/UI/Counter.luau → ReplicatedStorage/Client/UI/Counter (컴포넌트, 12장)src/client/Main.client.luau → StarterPlayerScripts/Main (진입점, 01장)roblox_packages/ → ReplicatedStorage/roblox_packages{ "name": "MyQuadApp", "tree": { "$className": "DataModel", "ReplicatedStorage": { "$className": "ReplicatedStorage", "roblox_packages": { "$path": "roblox_packages" }, "Client": { "$className": "Folder", "UI": { "$path": "src/client/UI" } } }, "StarterPlayer": { "$className": "StarterPlayer", "StarterPlayerScripts": { "$className": "StarterPlayerScripts", "Main": { "$path": "src/client/Main.client.luau" } } } }}이 매핑에서 중요한 건 이름이 아니라 모양입니다. Quad 소스는 require("./roblox_packages/…")처럼 자기 폴더의 형제를 상대 경로로 가리키므로, 디스크에서 형제였던 것이 Instance 공간에서도 형제여야 합니다. 그리고 패키지 디렉터리는 통째로 매핑하세요 — pesde가 놓는 roblox_packages/quad_roblox.luau는 그 아래 .pesde/… 실체를 가리키는 얇은 링커라, 점으로 시작하는 그 하위 트리까지 같이 올라가야 require가 풀립니다(Rojo는 .pesde를 정상적으로 따라갑니다).
위 경로들은 프로젝트 구성에 따라 달라지는 자리입니다. 실제 이름은 여러분의 default.project.json에 맞춰 바꾸세요.
3단계: 타입 검사 플래그
섹션 제목: “3단계: 타입 검사 플래그”Quad의 타입은 Luau의 새 솔버로만 검사됩니다. 그 플래그 하나는 필수이고, 한도 플래그 셋은 권장입니다.
| 플래그 | 값 | 없으면 |
|---|---|---|
LuauSolverV2 |
true |
필수. quad 소스의 타입 검사가 실패합니다 — TypeError: read keyword is illegal here |
LuauTarjanChildLimit |
160000 |
권장. 아래 한 가지 자리가 Code is too complex to typecheck!로 무너집니다 |
LuauSubtypingIterationLimit |
100000 |
권장(위와 같이 넣습니다) |
LuauTypeInferIterationLimit |
1000000 |
권장(위와 같이 넣습니다) |
[2026-10-20 실측] 3.4.0부터 생성자와 Modifier의 타입은 여러분의 검사기가 가진 Roblox 클래스 타입에서 타입 함수가 계산합니다. 그래서 한도 플래그가 없어도 대부분의 코드가 검사됩니다(이 저장소의 킷 둘, 330파일이 깨끗했습니다). 기본 한도에서 무너지는 것으로 확인된 자리는 하나입니다 — 조상 클래스 Modifier의 타입을 주석에 적고 값을 그 자리로 넘길 때(local m: Modifier<GuiObject> = q.Modifier "GuiObject" (), 파라미터 m: Modifier<GuiButton>)입니다. 구체 클래스(Modifier<Frame>)·입력 자리 마커(ModifierInto<C>)·주석 없는 추론은 기본 한도에서도 됩니다. 한도 플래그 셋을 넣으면 그 자리도 검사됩니다.
Studio의 스크립트 분석은 플래그를 바꿀 수 없으니, Studio에서도 검사받아야 하는 코드라면 그 자리를 피하세요 — 입력 자리는 ModifierInto<C>로 받고, 지역 변수는 주석 없이 둡니다. 편집기와 CI에는 같은 값을 넣으세요.
VS Code — Luau Language Server 확장
섹션 제목: “VS Code — Luau Language Server 확장”대부분은 VS Code에서 JohnnyMorganz의 Luau Language Server 확장(johnnymorganz.luau-lsp)을 쓸 것입니다. 확장을 설치한 뒤, 프로젝트 루트의 .vscode/settings.json에 아래를 넣습니다.
{ "luau-lsp.platform.type": "roblox", "luau-lsp.fflags.enableNewSolver": true, "luau-lsp.fflags.override": { "LuauTarjanChildLimit": "160000", "LuauSubtypingIterationLimit": "100000", "LuauTypeInferIterationLimit": "1000000" }}enableNewSolver가 첫 플래그(LuauSolverV2)를 켭니다. 나머지 셋은override에 넣습니다.override에"LuauSolverV2": "true"를 같이 적어도 결과는 같습니다.override의 값은 문자열입니다 —"160000"처럼 따옴표로 감싸세요. 스키마가 문자열만 받습니다.- 사용자 설정이 아니라 워크스페이스 설정(
.vscode/settings.json)에 두는 걸 권합니다. 저장소에 같이 커밋하면 팀원 모두 같은 값으로 검사하고, Quad를 안 쓰는 다른 프로젝트의 검사는 바뀌지 않습니다. --definitions에 해당하는 설정은 따로 필요 없습니다. 확장이 Roblox 타입 정의를 알아서 내려받습니다(luau-lsp.types.roblox, 기본 켜짐). Rojo가PATH에 있으면default.project.json으로 sourcemap도 자동 생성하므로(luau-lsp.sourcemap.autogenerate, 기본 켜짐) 2단계에서 만든 매핑을 그대로 따라 require를 풉니다.- 확장은 기본으로 Roblox가 공개한 Luau 플래그를 받아와 적용합니다(
luau-lsp.fflags.sync).override가 그 뒤에 적용되므로 위 값이 이깁니다. - 설정을 바꾸면 확장이 언어 서버를 다시 띄우라는 알림을 냅니다. 알림에서 다시 띄우거나 VS Code 창을 다시 로드하세요(명령 팔레트 →
Developer: Reload Window).
적용됐는지는 q.Elem "Frame" { Name = 5 } 한 줄로 확인할 수 있습니다 — Name에 숫자를 넣은 자리가 타입 에러로 잡히면 새 솔버가 켜진 것입니다. 편집기에서는 한도에 걸린 자리가 눈에 띄는 에러 없이 조용히 무너지는 경우가 많습니다 — props 안에서 자동완성이 안 나오거나, 마우스를 올린 타입이 *error-type*으로 보이면 그 자리가 한도에 걸린 것입니다. CLI에서는 같은 상황이 “too complex to typecheck” 에러로 드러납니다.
CI와 터미널 — luau-lsp analyze
섹션 제목: “CI와 터미널 — luau-lsp analyze”CI에서는 같은 확장의 CLI인 luau-lsp로 검사합니다. 편집기와 달리 Roblox 타입 정의를 자동으로 받지 않으므로 --definitions로 직접 넘깁니다.
luau-lsp analyze \ --flag:LuauSolverV2=true \ --flag:LuauTarjanChildLimit=160000 \ --flag:LuauSubtypingIterationLimit=100000 \ --flag:LuauTypeInferIterationLimit=1000000 \ --definitions=<Roblox 타입 정의 파일> \ <검사할 파일들>Neovim 같은 다른 편집기는요?
같은 luau-lsp 언어 서버를 쓰므로 넣을 값은 똑같습니다. 서버를 띄우는 인자에 위와 같은 --flag:이름=값 넷을 붙이거나, 쓰는 플러그인이 FFlag 설정을 따로 받으면 그 자리에 넣으세요.
이해 점검
섹션 제목: “이해 점검”세 패키지를 직접 적는 이유
quad_base·quad_roblox·quad_types 셋을 의존성에 직접 적어야 하는 이유는 무엇인가요?
- 셋 중 하나라도 빠지면 나머지가 내려받아지지 않도록 레지스트리가 막아 두었기 때문입니다
-
quad_base는 개발 의존성이라 전파되지 않고,quad_types는 직접 의존성이어야 최상위에 링커가 생기기 때문입니다 - 따라 들어오는
quad_error·type_version_check까지 다섯을 전부 적어야 하기 때문입니다
quad_roblox는 quad_base를 개발 의존성으로만 잡는데 개발 의존성은 소비자에게 전파되지 않고, quad_types는 직접 의존성으로 적어야 최상위에 링커가 생겨 설정 모듈의 require가 풀립니다. quad_error와 type_version_check는 위 셋의 의존성으로 따라 들어오므로 적을 필요가 없습니다.
타입 검사 플래그
local m: Modifier<GuiObject> = q.Modifier "GuiObject" () 한 줄에서 CLI 검사가 Code is too complex to typecheck!로 죽고, 같은 파일의 q.Elem "Frame" { … }들은 멀쩡합니다. 무엇을 바꾸면 되나요?
-
LuauSolverV2=true를 넣습니다 — 새 솔버가 꺼져 있을 때 나는 증상입니다 - 한도 플래그 셋을 넣거나, 그 자리의 주석을 빼고 추론에 맡깁니다(입력 자리라면
ModifierInto<C>로 받습니다) -
q.Modifier "GuiObject"를q.Modifier "Frame"으로 바꿔야 합니다 — 조상 클래스의 Modifier는 만들 수 없습니다
조상 클래스 Modifier의 타입을 주석으로 비교하는 자리가 기본 한도를 넘는 것으로 확인된 유일한 자리입니다. 한도 플래그 셋을 넣으면 검사되고, 플래그를 바꿀 수 없는 Studio에서는 주석을 빼거나 입력 자리를 마커로 받아 피합니다. 조상 클래스의 Modifier 자체는 만들 수 있고 쓸모 있습니다 — “GuiObject라면 무엇에든 붙는 스타일”이 그것입니다. LuauSolverV2=true가 빠졌을 때 나는 것은 read keyword is illegal here입니다.
더 알고 싶다면
섹션 제목: “더 알고 싶다면”- 레퍼런스: 설치와 프로바이더 —
quad-roblox가 설치하는 것 전부 - 08. quad v1에서 v2로 옮기기 — v1 프로젝트의 툴체인을 바꿀 때
Quiz Progress
0 / 0 questions answered (0%)
0 correct
Your score
0%
0 / 0 correct
Answered: 0 / 0 (0%)