λ―Έλλͺ¨λ λͺ¨λ°μΌ μ΄λμ₯, νμ¬ ν¬μ€ν° λ±μ λλκ·Έ μ€ λλ‘μΌλ‘ μ½κ² μ μν μ μλ λ―Έλ μΉ λΉλμ λλ€.
π λ°νμμ - 3λΆ λ΄μΈμ κ°λ¨ν κΈ°λ₯μκ° λΆλΆμ λλ€. μ 체μ μΈ κΈ°λ₯μ λ³΄μ€ μ μμ΅λλ€.
π λ°°ν¬λ§ν¬: https://www.minimo.life
π frontend: https://github.com/minimo-editor/minimo-client
π backend: https://github.com/minimo-editor/minimo-server
-
Frontend
- React
- ContextAPI
- ES6
- Styled-components
- Google-Maps-API
- Immer
- AWS-S3
- Jest
- React-testing-library
-
Backend
- Node.js
- Express.js
- MongoDB
- Mongoose
- πββοΈ νλ‘μ νΈ κ°μ
- π μμ κΈ°κ°
- πΉ κΈ°λ₯
- π§βπ» TECH STACK WHY?
- β TEST
- π‘ νΉμ§
- π νλ‘μ νΈ μ¬μ© λ°©λ²
- π§βπ» νλ‘μ νΈλ₯Ό λ§μΉλ©°
λ―Έλλͺ¨ μΉ λΉλλ λͺ¨λ°μΌ μ²μ²©μ₯μμ μμλ μμ΄λμ΄μ λλ€.
κ²°νΌμ ν λ μ¬λλ€μ μ¨λ©ν, λλ μ€, λ°μ§ λ± λͺ¨λ κ²μ μ΅κ³ λ‘ νλ €νκ² ν©λλ€. νμ§λ§ λͺ¨λ°μΌ μ²μ²©μ₯μ λ³΄ν΅ μ μ μ΄λ©° μ΅κ³ λ μλλΌκ³ μκ°νμ΅λλ€. νΉν μ½λ‘λλ‘μΈν΄ κ²°νΌμ λΆμ°Έμ΄ λ§μ μν©μμ, λͺ¨λ°μΌ μ²μ²©μ₯μ λ νΉλ³νκ² λ§λ€λ©΄ μ’κ² λ€κ³ μκ°νμ΅λλ€.
νλμ μΉμ 3D, μ€μκ° μΈν°λ μ , parallax scrolling λ± μ¬λ°λ μμλ λ§μ΄ μΆκ°ν μ μμ΅λλ€. μ΄λ¬ν κ²λ€μ λ°μκ² κ²°νΌ μ€λΉνμλ λΆλ€μ΄ μ½κ³ λΉ λ₯΄κ² λ§λ€ μ μλ μΉ λΉλλ₯Ό λ§λ€κ³ μΆμμ΅λλ€.
κ°λ° κΈ°κ°μ΄ 2μ£Όλ‘ μ§§κΈ° λλ¬Έμ, μ΄λ² κ°λ° κΈ°κ°λμμλ μλμ κ°μ λͺ©νλ₯Ό κ°κ³ μ§ννμμ΅λλ€.
- μΆνμ νΈνκ² λΈλ‘(μλν° κΈ°λ₯)μ μΆκ°ν μ μκ² νμ₯μ± μκ² λ§λ€κΈ°
- μ μ κ²½νμ ν΅μ¬μ μΈ λλκ·Έ μ€ λλ‘μ λΌμ΄λΈλ¬λ¦¬ μμ΄ μ§μ λ§λ€κΈ°
- κΈ°λ³Έμ μΈ λΈλ‘ μμλ€(ν μ€νΈ, λμμ, μ¬μ§ λ±)μ΄ ν¬ν¨λ μλν°λ₯Ό μ λ§λ€κΈ°
- μ»΄ν¬λνΈλ€μ μ¬μ¬μ©μ± μκ² νμ¬ μΆνμ λΈλ‘μ μΆκ°ν μ μκ² λ§λ€κΈ°
λ°λΌμ μ²μ²©μ₯ 보λ€λ νμ₯μ± μλ μΉ λΉλ νμμΌλ‘ νκ² λμκ³ , μ΄λ² νλ‘μ νΈ κΈ°κ°λμ κΈ°λ³Έ ν΄μ λ§λ€κΈ°λ‘ νμ΅λλ€.
-
κΈ°ν : 2021/05/03 ~ 2021/05/07 (1μ£Ό)
- μμ΄λμ΄ λΈλ μΈμ€ν λ°, κΈ°ν, κΈ°μ κ²μ¦
- minimo wireframe μμ±
-
κ°λ° : 2021/05/10 ~ 2021/05/21 (2μ£Ό)
- 2μ£Όμ°¨
μλν°λ°λλκ·Έ μ€ λλ‘λ± ν΅μ¬ κΈ°λ₯ ꡬνμ¬μ©μ μΈμ¦,μ μ μνκ΄λ¦¬λ±
- 3μ£Όμ°¨
μ»΄ν¬λνΈλ°μ»€μ€ν νμ¬μ¬μ©μ± μκ² λ¦¬ν©ν λ§- λλκ·Έ λλ‘
μ λλ©μ΄μ ,μΆκ° λΈλ‘, κΈ°λ₯ λ± μ λ ν μ€νΈλ°λ°°ν¬
- 2μ£Όμ°¨
π λ°νμμ - 3λΆ λ΄μΈμ κ°λ¨ν κΈ°λ₯μκ° λΆλΆμ λλ€. μ 체μ μΈ νλ‘μ°λ₯Ό λ³΄μ€ μ μμ΅λλ€.
- κΈ°λ³Έ ν νλ¦Ώμ μ νν μ μμ΅λλ€.
- λλκ·Έ λλ‘μ ν΅ν΄ μ½κ² λΈλ‘λ€μ μΆκ°ν μ μμ΅λλ€.
- μ΄λ―Έμ§, λμμ, μ νλΈ μμ λ±μ μΆκ°ν μ μμ΅λλ€.
- μμ λ―Έλμ΄ λ²νΌμ κ°μΈ λ§ν¬λ₯Ό μ°κ²°ν μ μμ΅λλ€.
- νΉμ μμΉλ₯Ό μ§λμ λ§ν¬νμ¬ μ£Όμμ ν¨κ» νμν μ μμ΅λλ€.
- λͺ¨λ°μΌ νλ©΄μ λ§κ² λ―Έλ¦¬λ³΄κΈ°κ° κ°λ₯ν©λλ€.
- μνλ μ£Όμλ₯Ό μ€μ ν μ μμ΅λλ€.
-
μ΄κΈ° μ€κ³λ¨κ³μμλ μ μ μνλ λ¨μν
prop-drillingμ λ§κΈ° μν μ λμκΈ° λλ¬ΈμContext APIλ₯Ό μ ννμ΅λλ€. -
ꡬνμ νλ©΄μ
Editor(project)μ μνκ΄λ¦¬ λ‘μ§μ΄ μ»€μ ΈμReduxλ₯Ό μ¬μ©ν μ§Context API + useReducerλ₯Ό μ¬μ©ν μ§ κ³ λ―Όνλλ°, μ νλ‘μ νΈλReduxκ° μ 곡νλ μ¬λ¬ κΈ°λ₯λ νμκ° μμκ³ , μνμ λ³νκ° κ·Έλ κ² λΉλ²νμ§ μκΈ° λλ¬Έμ κ΅³μ΄Reduxλ₯Ό λ°μ λ²λ€λ§ μ¬μ΄μ¦λ₯Ό ν€μ°κΈ° 보λ¨Context API + useReducerλ₯Ό μ ννκ² λμμ΅λλ€.
React Testing LibraryμJestλ₯Ό μ¬μ©νμ¬Custom Hook,util,reducerλ±μ μ€μ λ‘μ§μ μ°μ μ μΌλ‘ μ λ ν μ€νΈλ₯Ό μμ±νμ΅λλ€.
-
WYSIWYG (What You See Is What You Get)
νλ‘μ νΈλ₯Ό μ μ/νΈμ§ νλ κ³Όμ μμμ λͺ¨μ΅ κ·Έλλ‘ κ²°κ³Όλ¬Όμ΄ λμ€λλ‘ κ΅¬ννμμ΅λλ€.
-
Block λ¨μ μλν°
λ―Έλλͺ¨λ μ ν΅μ μΈ WYSIWYG μλν°μ λ€λ₯΄κ² block λ¨μλ‘ κ΅¬ννμμ΅λλ€.
μ ν΅μ μΈ WYSIWYGλ νλμ
contenteditableμμ μμ μλ‘λ€λ₯Έhtml markupμ μμ±νλ λ°©μμΈλ°, μ΄λ νΈμ§νλ κ°κ°μ μμκ° μλ‘μκ² μν₯μ μ£Όλ μμ λ²κ·Έκ° μ‘΄μ¬ν©λλ€. μ λ μ΄λ¬ν λΆνΈν¨μ κ²ͺμ΄λ³Έ μ μ΄ μκΈ° λλ¬Έμ, λ―Έλλͺ¨λparagraph,title,imageλ±μ κ°κ° λ 립μ μΈcontenteditableμμλ‘μ νΈμ§νλλ‘ κ΅¬ννμ΅λλ€. -
Clean output data
νλ‘μ νΈμ κ²°κ³Όλ¬Όμ
html markupμ΄ μλjsonνμμ λ°μ΄ν°λ‘ μ μ₯νμμ΅λλ€.λͺλͺ μλν°, λΈλ‘κ·Έ μλΉμ€ λ±μμ
html markupννοΏ½οΏ½οΏ½ λ°μ΄ν°λ₯Ό μ μ₯νμ¬ λ§μ κ³ λ―Όμ νμ§λ§,jsonνμμ μ₯μ μ΄ λ λ§λ€κ³ μκ°νμ¬jsonνμμΌλ‘ μ μ₯νμμ΅λλ€.html markupνμ<section name="0ed1" class="section section--body section--first"> <div class="section-divider"> <hr class="section-divider"> </div> <div class="section-content"> <div class="section-inner sectionLayout--insetColumn"> <h3 name="f8e8" class="graf graf--h3 graf--leading graf--title"> <br> </h3> <p name="83d3" class="graf graf--p graf-after--h3"> So what do we have? </p> </div> </div> </section> <section name="d1d2" class="section section--body"> ... </section>
minimoμ
jsonνμ{ "_id": "60a8ac7ec767550586e16766", "address" : "freeboard", "concept": "basic", "blocks" : [ { "type" : "paragraph", "data" : { "contents" : { "texts": "<p>this is free<p>" }, "styles": { "color": "black" } } }, { "type" : "title", "data" : { "contents" : { "texts": "give away alert" }, "styles": { "color": "red" } } }, { "type" : "image", "data" : { "contents" : { "src": "https://minimo.s3.amazonaws.com/project-image/any.png" } } } ], "createdAt": "2021-05-22T07:02:22.401Z" }
μμκ°μ
jsonννλ‘ λ°μ΄ν°λ₯Ό μ μ₯ ν¨μΌλ‘μ¨, νμ¬ μ¬μ©νλ minimo μΉ λΏλ§ μλλΌ, native, desktop app, μ€λμ€ λ¦¬λ, μ±λ΄ λ±μκ²λ μ½κ² μ μ©ν μ μμκ±°λΌ μκ°λμμ΅λλ€.λν λ°±μλμμμ validationλ λ μ©μ΄νκ³ , νΉμ λΆλΆμ λ°μ΄ν°λ§ μΆμΆνλ λ°μλ μμν κ²μ΄λΌκ³ μκ°νμ΅λλ€.
-
λλ ν 리 μ΄λ
// client cd minimo-client // server cd minimo-server -
package.jsonμ μ μλ ν¨ν€μ§ μ€μΉ
npm install -
Firebase Realtime Database μ¬μ©μ νμν
dotenvμ€μ λλ ν 리 μ΅μλ¨μ
.env.exampleμ.envλ‘ λ³κ²½ ν μλμ κ°λ€μ λ³κ²½// client REACT_APP_API_KEY=[FIREBASE_CONFIG_API_KEY] REACT_APP_AUTH_DOMAIN=[FIREBASE_CONFIG_AUTH_DOMAIN] REACT_APP_SERVER_URL=[SERVER_URL] REACT_APP_AWS_ACCESS_KEY=[AWS_S3_ACCESS_KE] REACT_APP_AWS_SECRET_KEY=[AWS_S3_SECRET_KEY] REACT_APP_GOOGLE_API_KEY=[GOOGLE_API_KEY] // server PORT=[PORT_NUMBER] MONGO_URL=[MONGO_DB_URL]
- μ€ν
// client npm start // server npm run dev
-
νλ‘μ νΈλ₯Ό λλ΄κ³ μ€μ€λ‘ μνλ€κ³ μκ°ν μ μ ν΅μ¬ κΈ°λ₯ κ΄λ ¨ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ§ μμλ€λ κ² μ λλ€.
μ΄μ νλ‘μ νΈμμ 'react-three-fiber'λΌλ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νλλ°, λ΄λΆμμ λμκ°λ three.js, canvas, webGLμ μ λͺ¨λ₯Έ μ± μ¬μ©νμ¬ λ¬Έμ λ€μ ν΄κ²°νκΈ° μ΄λ €μ κ³ μνλ λλ‘ κ΅¬ννμ§ λͺ»ν λΆλΆλ μμμ΅λλ€.
λ°λΌμ μ΄λ²μλ ν΅μ¬ κΈ°λ₯ κ΄λ ¨ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ§ μκ³ κΈ°λ³Έ web apiλ₯Ό μ΄μ©νμ¬ κ΅¬ννλ € νμ΅λλ€. λλΆμ μ΄λ €μ΄ μν©μ λ§λ¬μ λ, MDNκ³Ό stackoverflow λ±μ ν΅ν΄ κΈ°λ³Έ apiμ νΉμ±μ νμ΅νλ©° λ¬Έμ λ₯Ό ν΄κ²°ν μ μμμ΅λλ€. λν, μ΄νμ κ΄λ ¨ λΌμ΄λΈλ¬λ¦¬ μ¬μ© μμλ λ κΉκ² μ΄ν΄νκ³ μ¬μ©ν μ μμ κ±°λΌ κΈ°λν©λλ€.
-
λν νμ¬μμ λμμ΄λλκ³Ό μμ μ νλ€κ³ κ°μ νκ³ , κΈ°μ μ νΈμλ₯Ό μν΄ μ΄κΈ° wireframeμ λμμΈμ λ°κΎΈμ§ μκΈ°λ‘ λ§μλ¨Ήμλλ°, μ΄λ₯Ό μ μ§μΌμ μ΄κΈ° λμμΈκ³Ό κ°μ κ²°κ³Όλ¬Όμ λ§λ μ λ μ νλ€κ³ μκ°ν©λλ€.
-
νμ μμ°μ±μ΄ λμ μΉμ±μ κ΄μ¬μ΄ λ§μλλ°, μ§μ λ§λ€μ΄ λ³Ό μ μμ΄μ λ무 μ¬λ°μμ΅λλ€. μΆνμ parallax scroll μ λλ©μ΄μ , μ 물리μ€νΈ λ± μ¬λ°κ³ μΈν°λ ν°λΈν μμλ€μ ν¬ν¨ν λΈλ½λ€μ λ μΆκ°ν μμ μΈλ° λ무 μ¬λ°μ κ² κ°λ€μ. π











