Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/danpacho/vanilla-vercel-clone

๐Ÿ“ฆ vanilla js๋กœ vercel ํŽ˜์ด์ง€ ์ผ๋ถ€๋ฅผ ํด๋†ˆ์ฝ”๋”ฉ ํ•ด๋ด…๋‹ˆ๋‹ค!
https://github.com/danpacho/vanilla-vercel-clone

component-based vanilla-javascript vercel-clone

Last synced: 2 days ago
JSON representation

๐Ÿ“ฆ vanilla js๋กœ vercel ํŽ˜์ด์ง€ ์ผ๋ถ€๋ฅผ ํด๋†ˆ์ฝ”๋”ฉ ํ•ด๋ด…๋‹ˆ๋‹ค!

Awesome Lists containing this project

README

        

# Vercel Clone / 7์ผ

## ์ค‘์ ์ ์ธ ๊ณ ๋ฏผ ์‚ฌํ•ญ ๐Ÿง

> vanilla `js` & `CSS`๋งŒ์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋Š๊ปด์ง€๋Š” ๋ถˆํŽธํ•จ ๊ฐœ์„ ํ•ด๋ณด๊ธฐ

1. ์ค‘๋ณต๋˜๋Š” `html` ๋งˆํฌ์—…์˜ ๋ฌธ์ œ์ 
2. ์ ˆ์ฐจ์  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋ฌธ์ œ์ 
3. ์ „์—ญ์  ์Šคํƒ€์ผ๋ง๊ณผ ์ค‘๋ณต `class` naming์˜ ๋ฌธ์ œ์ 
4. ๋ชจ๋“ ๊ฒƒ์„ ํ—ˆ์šฉํ•ด์ฃผ๋Š” ์ง€๋‚˜์น˜๊ฒŒ ์นœ์ ˆํ•œ `js`

## ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ๐ŸŽ

> ์ค‘๋ณต๊ณผ ์ ˆ์ฐจํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ โžก๏ธ ์„ ์–ธํ˜• ์ปดํฌ๋„ŒํŠธ

1. `Component` class

**์„ ์–ธํ˜•** ์ปดํฌ๋„ŒํŠธ

```js
const Container = (children) =>
new Component({
template: `


${children}
`,
}).html()
```

์ปดํฌ๋„ŒํŠธ **ํ™œ์šฉ** ๋ฐ **์žฌ์‚ฌ์šฉ**

```js
import { Container } from "์–ด๋””์„ ๊ฐ€"

const Section = () =>
new Component({
template: `


${Container(`
์•ˆ๋…•?
`)}

`,
}).html()
```

2. `EventListener` class

์ปดํฌ๋„ŒํŠธ์— **๋ช…์‹œ์ ์œผ๋กœ** ์ด๋ฒคํŠธ ๋ถ€์ฐฉ ๋ฐ ์ œ๊ฑฐ

```js
const Container = (children) => {
const clickHandler = (e) => {
console.log(e.clientX)
}

return new Component({
template: `


${children}
`,
})
.addEvent((target) => ({
type: "click",
handler: clickHandler,
}))
.removeEvent((target) => ({
type: "click",
handler: clickHandler,
}))
}
```

3. `atom` state management

๋ช…์‹œ์ ์ธ ๋ณ€์ˆ˜๊ด€๋ฆฌ์˜ ์žฅ์ 

```js
const Counter = () => {
const [count, setCount] = atom(0)
const increase = () => {
setCount(count() + 1)
}

return new Component({
template: `

Counter is ${count()}
`,
})
.addEvent(() => ({
type: "click",
handler: increase,
}))
.render()
}
```

> ์Šคํƒ€์ผ๋ง โžก๏ธ `CSS module`์„ ํ™œ์šฉํ•œ scoped `CSS`

์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์„ ์ปดํฌ๋„ŒํŠธ ๋ฐ ์Šคํƒ€์ผ๋กœ ๊ตฌ๋ถ„ํ•˜๊ธฐ

```
๐Ÿ“ฆmy-component
โ”ฃ ๐Ÿ“œindex.js
โ”— ๐Ÿ’„index.module.css
```

> ์ง€๋‚˜์นœ ์ž์œ  โžก๏ธ `jsdoc`๊ณผ `jsconfig.json`์œผ๋กœ ํƒ„์••

๋“ ๋“ ํ•œ ๋ฌด๊ธฐ ์ค€๋น„ `jsconfig.json`

```json
{
"compilerOptions": {
"strict": true,
"allowJs": true,
"checkJs": true,
"noEmit": true,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"typeRoots": ["./node_modules/@types"],
"forceConsistentCasingInFileNames": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
```

๊ธฐ๋งฅํžŒ `jsdoc`๊ณผ ์ž ์ž ํ•ด์ง„ `js`

```js
/**@type string */
let ๋ฐ˜๋“œ์‹œ_์ŠคํŠธ๋ง = "์ด๊ฑฐ ๋ฐ˜๋“œ์‹œ ๊ธ€์ž์—์šฉ"

// โŒ ๊ฐ€๋Šฅ์€ ํ•˜์ง€๋งŒ, ์˜ค๋ฅ˜ ๋งค์„ธ์ง€๊ฐ€ ๋œจ๋Š” ๋งค์ง
๋ฐ˜๋“œ์‹œ_์ŠคํŠธ๋ง = 1
```

## ๊ตฌํ˜„์‚ฌํ•ญ โœ…

1. ๋งˆ์šฐ์Šค `hover`์‹œ ์ขŒํ‘œ์—๋”ฐ๋ผ ๋™์ ์œผ๋กœ ๋ฐ˜์‘ํ•˜๋Š” ์นด๋“œ
2. `radial gradient`์™€ `blur` api๋ฅผ ์‚ฌ์šฉํ•œ ํšจ๊ณผ
3. ๋ฒ„ํŠผ ring ํšŒ์ „
4. gradient ํ…์ŠคํŠธ ๋ณ€ํ˜• ๋ฐ ์ „ํ™˜

## ๊ตฌํ˜„๊ฒฐ๊ณผ ๐ŸŽ‰

![์ตœ์ดˆ ๋กœ๋”ฉ ํŽ˜์ด์ง€!](./assets/preview.png)

## ์ข‹์•˜๋˜ ์  โœ…

1. ์„ ์–ธ์ ์ด๋ฉฐ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋†’์€ ํ•จ์ˆ˜์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ ์ œ์ž‘ํ•ด ๋งŽ์€ ์ค‘๋ณต์„ ์ค„์ผ ์ˆ˜ ์žˆ์—ˆ์Œ
2. ๋ฐ”๋‹๋ผ js์˜ `DOM` api์™€ ํ™œ์šฉ๋ฒ•์— ๋Œ€ํ•ด ๊นŠ๊ฒŒ ํ•™์Šตํ•  ์ˆ˜ ์žˆ์—ˆ์Œ
3. **reactivness**๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์›นํ”„๋ ˆ์ž„์›Œํฌ๋“ค์˜ ์ „๋žต(`compile` / `reactiveness` / `v-dom & diff`)์˜ ํ•„์š”์„ฑ์„ ๋Š๋‚Œ

## ๊ฐœ์„ ํ•  ์  ๐Ÿ”ธ

1. **reactiveness**๊ฐ€ ์—†์Œ. state๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜๊ณ  ์žฌ๋ Œ๋”๋งํ•˜๋Š” ๋กœ์ง์ด ์—†๊ธฐ์— ์ง์ ‘ `DOM` api๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜ `CSS variable`๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Œ

> `Proxy`๋ฅผ ์ด์šฉํ•œ ๋ณ€์ˆ˜ ๊ตฌ๋…๊ณผ ๋ Œ๋”๋ง ๋“ฑ์˜ ๋ฐฉ๋ฒ•

2. `string`์„ `HTML`๋กœ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ `jsx`์™€ ๊ฐ™์€ ์ง๊ด€์„ฑ๊ณผ ๊ฐœ๋ฐœ ํŽธ์˜์„ฑ์ด ์—†์Œ.

3. `render()`ํ˜ธ์ถœ์‹œ `parent`๊ฐ€ ์กด์žฌํ•˜๋ฉฐ, `event`๋“ฑ์ด ๋ถ€์ฐฉ๋œ ๋ฐ˜์‘์„ฑ์ด ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์›ํ•˜๋Š” ์œ„์น˜์— ๋ Œ๋”๋งํ•˜๊ธฐ๊ฐ€ ๊นŒ๋‹ค๋กœ์›€

๋ Œ๋”๋ง ์œ„์น˜ ์ง€์ •ํ•˜๊ธฐ โœ…

```js
const StaticParent = () => new Component({
template: "

{...}
"
})

const ReactiveComponent = () => {...}

// โŒ DOM-tree์—์„œ id์š”์†Œ๋ฅผ ํƒ์ƒ‰ ๋ถˆ๊ฐ€๋Šฅ
ReactiveComponent.render("์—ฌ๊ธฐ์—-๋ Œ๋”๋ง")

StaticParent.render()

// โœ… DOM-tree์—์„œ id์š”์†Œ๋ฅผ ํƒ์ƒ‰ ๊ฐ€๋Šฅ
ReactiveComponent.render("์—ฌ๊ธฐ์—-๋ Œ๋”๋ง")
```

๋ Œ๋”๋ง ์ง์ ‘ ํ•˜๊ธฐ โŒ

```js
const ReactiveComponent = () => {...}

const StaticParent = () => new Component({
// โŒ html ๋ Œ๋”๋ง ๋ถˆ๊ฐ€
template: `${ReactiveComponent.render()}`
template: `${ReactiveComponent.html()}`
})
```