Skip to content

Commit 71db4a6

Browse files
committed
feat: live-editor에 새로운 이미지 추가, 내용 추가.
1 parent 1ea6832 commit 71db4a6

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed
-4.35 KB
Loading
256 KB
Loading

src/app/ko/article/2025-10/live-editor/page.mdx

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import i0 from "./i0.png";
99
import i1 from "./i1.jpg";
1010
import i2 from "./i2.png";
1111
import i3 from "./i3.png";
12+
import i4 from "./i4.png";
1213
import i99 from "./i99.png";
1314

1415
export const metadata = getArticleMetadata(item);
@@ -19,7 +20,7 @@ export const metadata = getArticleMetadata(item);
1920

2021
<ArticleImage img={i1} alt="포스트잇 사진" caption={<>
2122

22-
어떻게 생겼는지도 예측하기 힘든 고객의 사이트에서 뭔가가 잘 동작하게끔 하기란, 마치 어디에나 잘 붙는 포스트잇을 개발하는 것과 다를 바가 없다. 사진: <a href="https://unsplash.com/ko/%EC%82%AC%EC%A7%84/%EC%9D%B8%EC%87%84%EB%90%9C-%EC%8A%A4%ED%8B%B0%EC%BB%A4-%EB%A9%94%EB%AA%A8%EA%B0%80-%EB%B3%B4%EB%93%9C%EC%97%90-%EC%A0%91%EC%B0%A9%EB%90%98%EC%96%B4-%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4-zoCDWPuiRuA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a> by <a href="https://unsplash.com/ko/@epicantus?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Daria Nepriakhina 🇺🇦</a>
23+
어떻게 생겼는지도 예측하기 힘든 고객의 사이트에서 뭔가가 잘 동작하게끔 하기란, 마치 어디에나 잘 붙는 포스트잇을 개발하는 것과 같다. 사진: <a href="https://unsplash.com/ko/%EC%82%AC%EC%A7%84/%EC%9D%B8%EC%87%84%EB%90%9C-%EC%8A%A4%ED%8B%B0%EC%BB%A4-%EB%A9%94%EB%AA%A8%EA%B0%80-%EB%B3%B4%EB%93%9C%EC%97%90-%EC%A0%91%EC%B0%A9%EB%90%98%EC%96%B4-%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4-zoCDWPuiRuA?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a> by <a href="https://unsplash.com/ko/@epicantus?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Daria Nepriakhina 🇺🇦</a>
2324

2425
</>} />
2526

@@ -51,9 +52,9 @@ export const metadata = getArticleMetadata(item);
5152

5253
우리는 이 글에서, **너희(You)**, 즉 고객의 사이트에서 동작하는 Front 앱을 만들 겁니다. 무슨 말이죠? 그게 왜 필요할까요? 아래와 같은 제품을 개발한다고 가정합시다.
5354

54-
## 요구사항
55+
## 요구사항 (가정)
5556

56-
우리가 파는 물건은 **웹사이트 광고 배너 렌더링 시스템**이며 우리의 주 고객은 **사이트 운영자**입니다. 고객이 해줄 것은 `main` 스크립트를 자신의 사이트에 삽입해놓는 것입니다. 아마 아래와 같을 것입니다.
57+
우리가 파는 물건은 **웹사이트 광고 배너 렌더링 시스템**이며 우리의 주 고객은 **사이트 운영자**입니다. 고객이 해줄 것은 `main` 스크립트를 자신의 사이트에 삽입해놓는 것입니다. 아래와 같을 것입니다.
5758

5859
```html
5960
<script
@@ -62,7 +63,7 @@ export const metadata = getArticleMetadata(item);
6263
></script>
6364
```
6465

65-
동시에 `live-locator` 라는 기능도 제공합니다. 이는 광고 배너를 어느 위치에 삽입할 건지를 지정해주는 도구입니다. 고객 사이트와 상호작용하면서도 복잡한 UI가 고객 사이트에 Floating 되어 동작합니다. `main` 스크립트와 `live-locator` 스크립트는 분리되어 있고, 상황에 따라 **동적으로 로딩**되어 사이트 성능을 해치지 않으면서도 운영자만 에디터를 사용할 수 있도록 설계합니다.
66+
또한, **광고 배너를 어느 위치에 삽입할 건지를 실시간으로 지정할 수 있는 도구**`live-locator` 라는 기능도 제공합니다. 고객 사이트와 상호작용하면서도 복잡한 UI가 고객 사이트에 Floating 되어 동작합니다. `main` 스크립트와 `live-locator` 스크립트는 분리되어 있고, 상황에 따라 **동적으로 로딩**되어 사이트 성능을 해치지 않으면서도 운영자만 에디터를 사용할 수 있도록 설계합니다.
6667

6768
모든 빌드는 Vite 기반으로 합니다. 결과물은 S3(+CloudFront) 에 업로드하는 것을 전제로 합니다.
6869

@@ -72,13 +73,13 @@ export const metadata = getArticleMetadata(item);
7273

7374
스크립트란 무엇이고, 어떤 스크립트가 필요한지 봅시다.
7475

75-
우리는 우리의 도메인 주소가 온전히 있는 우리만의 서비스에서 개발하는 게 아닙니다. **다른 이의 사이트에서 잘 동작하는 기능**을 만들어야 합니다. 그렇다면 고객 회사로 파견을 나가서 그 쪽의 코드를 수정해야 할까요? 그런 방법만 있는 건 아닙니다. **스크립트**라는 최소한의 연결점만 만들면, 우리가 작성한 코드를 그 쪽의 사이트에서 동작시키게 할 수 있습니다. 스크립트는 말 그대로 `<script src="...">`를 뜻합니다.
76+
우리는 우리의 도메인 주소가 온전히 있는 우리만의 서비스에서 개발하는 게 아닙니다. **다른 이의 사이트에서 잘 동작하는 기능**을 만들어야 합니다. 그렇다면 고객 회사로 파견을 나가서 그 쪽의 코드를 수정해야 할까요? 제일 확실한 방법이긴 하겠지만, 모든 회사에 우리가 일일히 방문을 할 수는 없으니 대안을 생각해봅시다. 네. **스크립트**라는 최소한의 연결점만 만들면, 우리가 작성한 코드를 그 쪽의 사이트에서 동작시키게 할 수 있습니다. 스크립트는 말 그대로 `<script src="...">`를 뜻합니다.
7677

77-
전지현이 광고하는 [Andar](https://andar.co.kr/)라는 브랜드의 쇼핑몰 사이트에서 온갖 써드파티 스크립트가 동작하는 걸 확인할 수 있습니다.
78+
간단하게 예시를 한번 살펴봅시다. 전지현이 광고하는 [Andar](https://andar.co.kr/)라는 브랜드의 쇼핑몰 사이트를 까봤는데요, 온갖 써드파티 스크립트가 동작하는 걸 확인할 수 있었습니다.
7879

7980
<ArticleImage
8081
img={i0}
81-
alt=""
82+
alt="Andar 사이트의 devtools"
8283
border
8384
caption="Andar 사이트의 코드를 까보면 온갖 스크립트가 로드되고 있다."
8485
/>
@@ -89,25 +90,46 @@ export const metadata = getArticleMetadata(item);
8990
- [크리마(CREMA)](https://www.cre.ma/): 리뷰 데이터를 기반 마케팅 플랫폼
9091
- [Google Tag Manager](https://tagmanager.google.com/): 웹/앱 코드 수정 없이 다양한 마케팅·측정 태그를 한 대시보드에서 배포·관리하는 태그 관리 시스템.
9192

92-
그런 스크립트는 고객이 직접 설치까지는 해야 합니다. 그 이후에는 우리의 차례입니다.
93+
스크립트 설치(삽입)는 쇼핑몰 운영자가 해주기는 해야 합니다. 그 이후는 스크립트의 차례입니다.
94+
95+
### React란 무엇일까
96+
97+
React는 웹앱을 만들기 위한 프레임워크입니다. 전세계 프론트엔드 개발자들에게는 아주 익숙합니다. 이런 프레임워크의 장점은 다양한 프론트엔드 개발자가 같은 개념, 같은 이야기를 할 수 있도록 하여 생산성을 올려준다는 겁니다. 그래서 웹앱을 계속해서 잘 개발해야 한다면 이런 프레임워크를 쓰는 게 생산성 측면에서 좋을 때가 많습니다. 우리가 만들고자 하는 `live-locator`도 예외는 아닙니다.
98+
99+
단, `main` 스크립트는 React를 사용하지 맙시다. 두 가지 이유가 있습니다. 먼저 복잡한 UI를 만들 일이 없기 때문에 React가 사실상 필요가 없습니다. 둘째로는, `main` 스크립트는 로딩 속도가 중요하기 때문에 극한으로 용량을 줄여야 합니다. 사이트 관리자가 아니라 일반 방문자 입장에서는 React를 만나지 않게 될 겁니다.
100+
101+
위에서 언급한 써드파티 스크립트도 UI가 필요한 게 아니라 사용자 정보를 수집하는 기능으로 충분하기 때문에 React같은 무거운 프레임워크가 필요 없습니다.
102+
103+
React는 편리한 개발 환경을 제공합니다. 특히 Hot Module Replacing(이하 HMR)은 정말 좋습니다. 만약 없으면 매번 새로고침해야 할 겁니다. 우리의 `live-locator` 또한 이런 편리한 개발 환경을 누리게 해줘야겠습니다.
104+
105+
### 동적 로딩
106+
107+
`main` 스크립트는 조건에 맞을 때에만 (관리자가 명시적으로 `live-locator` 쓰겠다 할 때에만) 그 스크립트를 로딩해야 합니다. 무엇을 기준으로 삼을까요? 일단은 `?bannerLocator=1` 라는 searchParams가 있으면 로드되도록 간단히 합시다. 로드는 `<script>` Element를 만들어 넣어줍시다.
108+
109+
### 격리를 어떻게 시킬까
110+
111+
React와 같은 프레임워크는 ******내 서비스** 만들 때 쓰라고 만든 거지 **남의 서비스** 위에 **내 서비스**를 얹기 위해 나온 게 아닙니다. 그래서 당연히 남의 서비스에 영향을 주지 않는 기능 같은 건 고려된 게 없을 겁니다. `live-locator`를 React로 개발한다고 하면 다음과 같은 상황이 발생할 수 있습니다.
112+
113+
- `div.container` 에 스타일을 설정했는데, 고객 사이트 스타일에 영향이 간다!
114+
- 고객 사이트도 React 같은 걸 써서 뭔가 글로벌 변수가 충돌한다!
115+
116+
이 글은 전체적인 흐름을 잡는 데 집중할 거기 때문에, 스타일을 격리시키기 쉬운 **Shadow DOM + Custom Element** 방법만 쓰고, 그 외에는 고려하지 않겠습니다.
93117

94118
## 비슷한 사례
95119

96-
**Vercel Toolbar** 기능을 아시나요? Vercel은 Next.js 등의 웹앱을 편하게 배포해주는 서비스인데요, `main` 브랜치가 아니라 작업 중인 브랜치를 따고 PR을 만들고 하면은 해당 버전으로 테스트(Preview)할 수 있는 빌드가 생깁니다.
120+
**Vercel Toolbar** 기능을 아시나요? Vercel은 Next.js 등의 웹앱을 편하게 배포해주는 서비스인데요, `main` 브랜치가 아니라 작업 중인 브랜치를 따고 PR을 만들고 하면은 해당 브랜치의 최신 버전으로 테스트(Preview)할 수 있는 빌드가 생깁니다.
97121

98122
아래는 `test` 브랜치에서 작업한 내용이 `zip-up-git-…vercel.app`으로 배포되는 모습입니다.
99123

100-
<ArticleImage img={i2} border caption="" />
124+
<ArticleImage img={i2} border caption="" alt="" />
101125

102-
저 주소로 들어가면 우측에 조그마한 버튼이 떠있는 걸 볼 수 있고, 그걸 누르면 아주 복잡한 기능이 내 사이트에서 뜨는 걸 확인할 수 있습니다. 라는 기능입니다.
126+
저 주소로 들어가면 우측에 조그마한 버튼이 떠있는 걸 볼 수 있고, 그걸 누르면 아주 복잡한 기능이 내 사이트에서 뜨는 걸 확인할 수 있습니다. 요지는 **나의 사이트에 내가 만들지 않은 기능이 생겼다는 것**입니다! 우리가 `live-locator`를 잘 만들어야 하는 상황과 아주 유사합니다.
103127

104-
<ArticleImage img={i3} border caption="" />
128+
<ArticleImage img={i3} border caption="" alt="" />
105129

106-
이게 어디서 어떻게 렌더링되는 걸까요?
130+
이게 어디서 어떻게 동작하는 걸까요?
107131

108-
1. 먼저 Vercel에서 만든 ..
109-
110-
아래와 같은 코드 스니펫이 삽입되어 있음을 확인할 수 있습니다.
132+
Next.js 앱이 Vercel에서 빌드될 때 Vercel Toolbar를 로드하는 코드 스니펫이 자동으로 삽입됩니다. 가장 먼저 로드되는 자바스크립트인 `webpack-xxx.js` 의 최하단에서 아래와 같은 코드가 있다는 걸 확인해볼 수 있습니다.
111133

112134
```jsx
113135
(function () {
@@ -119,14 +141,23 @@ export const metadata = getArticleMetadata(item);
119141
})();
120142
```
121143

144+
이 코드는 특정한 자바스크립트를 로드하게 되고, 그 스크립트가 온갖 리소스를 로드하고 동작시킵니다. 결과적으로 아래와 같은 Element가 body 하단에 삽입됩니다.
145+
122146
```html
123147
<vercel-live-feedback
124148
style="position: absolute; top: 0px; left: 0px; z-index: 2147483647;"
125149
></vercel-live-feedback>
126150
```
127151

128-
번외: Add Extension 하는 데는 이유가 다 있다~
152+
shadowRoot를 까보면서 확인해보면 엄청나게 많은 style 태그가 있고, 각종 Element도 많고, React를 포함한 커다란 스크립트가 로드되는 것도 확인할 수 있습니다.
153+
154+
<ArticleImage
155+
img={i4}
156+
border
157+
caption="로드되는 다양한 Vercel Toolbar 관련 스크립트"
158+
alt="로드되는 다양한 Vercel Toolbar 관련 스크립트"
159+
/>
129160

130-
![image.png](attachment:70bcfb7c-99b1-43ab-b04a-d24e8f987048:image.png)
161+
이제 대충 얘네가 어떻게
131162

132-
bannerLocator
163+
## 구현 ㄱㄱ

0 commit comments

Comments
 (0)