๐Ÿ˜„ ์•ˆ๋…•ํ•˜์„ธ์š”, ์ง€์›์ž ์ •์„ํ˜ธ์ž…๋‹ˆ๋‹ค. โœจ

@CreatiCoding (Creative + Coding)

introduce [0]

  • ํŽซํ”„๋ Œ์ฆˆ ๊ฐ€์น˜๊ฐœ๋ฐœํŒ€
  • ํ”„๋ก ํŠธ์—”๋“œ front-end 3๋…„์ฐจ

ํŽซํ”„๋ Œ์ฆˆ์— ์‹ ์ž…์œผ๋กœ ์ž…์‚ฌํ•˜์—ฌ ํ˜„์žฌ๋Š” front-end ํŒŒํŠธ๋ฅผ ๋ฆฌ๋“œํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
ํŒ€ ๋‚ด ๊ฐœ๋ฐœ์ž์˜ ์—ญ๋Ÿ‰์„ ์ƒํ–ฅ ํ‰์ค€ํ™”ํ•˜๋Š” ๊ฑธ ๋ชฉํ‘œ๋กœ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ˜„์žฌ๋Š” front-end ์‚ฌ๋‚ด ๊ต์œก ๋ฐ ์ฝ”๋“œ ์Šคํƒ€์ผ ์ •๋ฆฝ์„ ์ง„ํ–‰ ์ค‘์— ์žˆ์Šต๋‹ˆ๋‹ค.
front-end ๊ฐœ๋ฐœ์ž๋„ DevOps๋ฅผ ์กฐ๊ธˆ๋งŒ ์•Œ๋ฉด back-end ๊ฐœ๋ฐœ์ž ๋ชป์ง€์•Š๊ฒŒ ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋„๋ฆฌ ์•Œ๋ฆฌ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

introduce [1]

์ €๋Š” ์•„๋ž˜๋ฅผ ์ƒ๊ฐํ•˜๊ณ  ๊ณ ๋ฏผํ•ฉ๋‹ˆ๋‹ค.

  • ์ตœ์†Œ์˜ ๋ฆฌ์†Œ์Šค๋กœ ์ตœ๋Œ€์˜ ํšจ๊ณผ

  • ์„ฑ๋Šฅ ์ข‹์€ ์ฝ”๋“œ < ์ฝ๊ธฐ ์ข‹์€ ์ฝ”๋“œ

  • ์ฃผ์„๋‹ฌ๋ฆฐ ์ฝ”๋“œ < ์ง๊ด€์ ์ธ ์ฝ”๋“œ

  • ๊ฐœ๋ฐœ์ž ๋ชจ๋‘์˜ ์ƒํ–ฅ ํ‰์ค€ํ™”

introduce [2]

์ €๋Š” ์ด๊ฒƒ์„ ์ถ”๊ตฌํ•˜๊ณ  ์—ด๋งํ•ฉ๋‹ˆ๋‹ค.

  • front-end๋ฅผ ์œ„ํ•œ DevOps(์ž๋™๋ฐฐํฌ ๋ฐ ์œ ๋‹›ํ…Œ์ŠคํŠธ)

  • ์„ฑ๋Šฅ ์ตœ์ ํ™” (์ฒซ ๋กœ๋”ฉ ์†๋„, ๋ฒˆ๋“ค๋ง ๋ถ„์„)

  • ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ… (๋ ˆ์ด์•„์›ƒ ์‰ฌํ”„ํŠธ, ํ”Œ๋ฆฌ์ปค ํ˜„์ƒ, ์ƒํƒœ ์ถ”์ )

์ €๋Š” ๋‹ค์Œ์˜ ์ˆœ์„œ๋Œ€๋กœ ์ง€ํ–ฅํ•ฉ๋‹ˆ๋‹ค.

  • ๊ธฐ์ˆ ์  ์•ˆ์ •์„ฑ >= ๊ธฐ์ˆ ์  ๋ถ€์ฑ„์˜ ์ตœ์†Œํ™” >= ์ผ์ •

project [0]
Next.js pm2 ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ

http server์˜ close ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉ
https://nodejs.org/api/http.html#http_server_close_callback

pm2์˜ reload๋ฅผ ํ™œ์šฉํ•˜์—ฌ graceful stop์œผ๋กœ ๊ตฌํ˜„
https://pm2.keymetrics.io/docs/usage/signals-clean-restart/#graceful-stop

pm2 reload๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ค‘๋‹จ ์—†๋Š” ๋ฐฐํฌ

process.on("SIGINT", function () {
  server.close(function (err) {
    if (err) throw err;
    process.exit(0);
  });
});

project [1]
Vue.js SPA ์ž๋™ ๋ฐฐํฌ ๊ตฌ์„ฑ

width:700px
FE ๋ฐฐํฌ ํ”„๋กœ์„ธ์Šค (S3, CloudFront, Vuejs, Route53)

project [2]
Vue Router # ์ œ๊ฑฐ

  • ๋ฒ”์šฉ์ ์ธ ๋งˆ์ผ€ํŒ… ํˆด ์‚ฌ์šฉ์„ ์œ„ํ•ด hash ์ œ๊ฑฐ ์‹œ๋„
  • CloudFront ์˜ Custom Error Page๋กœ SPA redirect ๊ตฌํ˜„
  • ์ด๋ฏธ SPA์˜ ๋ฒˆ๋“ค๋ง ํŒŒ์ผ์ด ๋กœ๋“œ๋œ ๊ธฐ์กด ์œ ์ €๋“ค์˜ Hash๊ธฐ๋ฐ˜ Path ์ ‘๊ทผ์˜ ์˜ˆ์™ธ์ฒ˜๋ฆฌ

https://๋„๋ฉ”์ธ/๊ฒฝ๋กœ1?ํŒŒ๋ผ๋ฏธํ„ฐ1#/๊ฒฝ๋กœ2?ํŒŒ๋ผ๋ฏธํ„ฐ2

  • ๊ฒฝ๋กœ1์ด ์žˆ์œผ๋ฉด ๊ฒฝ๋กœ1๋กœ #์—†์ด ์ƒˆ๋กœ๊ณ ์นจ
  • ๊ฒฝ๋กœ1์ด '/'์ด๊ฑฐ๋‚˜ ๋นˆ ๋ฌธ์ž์—ด์ด๋ฉด ๊ฒฝ๋กœ2๋กœ #์—†์ด ์ƒˆ๋กœ๊ณ ์นจ
  • ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” merge๋กœ ํ•˜๋˜ ํŒŒ๋ผ๋ฏธํ„ฐ2๋กœ OverWrite

์˜ˆ์‹œ) https://๋„๋ฉ”์ธ/?utm_source=utm์ •๋ณด/#/์ƒํ’ˆ์ƒ์„ธ๊ฒฝ๋กœ?product_id=์ƒํ’ˆ๋ฒˆํ˜ธ > this.$router.push('/์ƒํ’ˆ์ƒ์„ธ๊ฒฝ๋กœ?utm_source=utm์ •๋ณด&product_id=์ƒํ’ˆ๋ฒˆํ˜ธ');

improvement [0]
๋ธŒ๋žœ์น˜ ๊ด€๋ฆฌ ์ „๋žต ์ž๋™ ๋ฐฐํฌ ๊ตฌ์„ฑ

width:900px

  • git branch protection rule์„ ํ™œ์šฉํ•˜์—ฌ unexcepted deploy๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค.

improvement [0]
๋ธŒ๋žœ์น˜ ๊ด€๋ฆฌ ์ „๋žต ์ž๋™ ๋ฐฐํฌ ๊ตฌ์„ฑ

  • ์žฅ์•  ๋Œ€์‘์„ ์œ„ํ•ด ๋ถˆ๊ฐ€ํ”ผํ•˜๊ฒŒ ์ƒˆ๋ฒฝ์— ๋ฐฐํฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ,
  • ๋ฆฌ๋ทฐํ•ด์ค„ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ˜„์žฅ์— ์—†๋Š” ๊ฒฝ์šฐ,

hmarr/auto-approve-action์„ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • ๋ธŒ๋žœ์น˜ ์ด๋ฆ„์˜ ๊ทœ์น™๋งŒ ์ž๋™ approve

name: Emergency-Approve
on:
  pull_request:
jobs:
  auto-approve:
    if: github.repository == '๊ณ„์ •/repo๋ช…' && contains(github.head_ref, 'ํŠน์ •๋ธŒ๋žœ์น˜๋ฌธ์ž์—ด')
    runs-on: ubuntu-latest
    steps:
      - uses: hmarr/auto-approve-action@v2.0.0
        with:
          github-token: "${{ secrets.GITHUB_TOKEN }}"

improvement [1]
SPA์˜ versioning ๊ด€๋ฆฌ

commit ๋ฒˆํ˜ธ๋กœ ๋ฒ„์ „์„ uniqueํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•œ๋‹ค.

echo "{ \"version\": \"$(git rev-parse HEAD)\" }" > public/web-version.json
echo "{ \"version\": \"$(git rev-parse HEAD)\" }" > src/web-version.json

์œ„ ๋‚ด์šฉ์€ GitHub Actions์˜ ๋ฐฐํฌ ํ”„๋กœ์„ธ์Šค์—์„œ prebuild๋กœ ๋™์ž‘์‹œํ‚จ๋‹ค.
build์‹œ public์˜ json์€ fetch์šฉ์œผ๋กœ ์ด์šฉ๋˜๋ฉฐ, src์˜ json์€ module์šฉ์œผ๋กœ ์ด์šฉ๋œ๋‹ค.

improvement [1]
SPA์˜ versioning ๊ด€๋ฆฌ

app.js์— ๋ฒˆ๋“ค๋ง๋˜๋Š” jsonํŒŒ์ผ๊ณผ s3๋กœ ์˜ฌ๋ผ๊ฐ€๋Š” static jsonํŒŒ์ผ์„ ์„œ๋กœ ๋น„๊ตํ•œ๋‹ค.

  • ๋ฒˆ๋“ค๋ง ๋˜๋Š” ํŒŒ์ผ
getCurrentVersion() {
    return require('src/web-version.json').version;
},
  • Fetchํ•œ S3์˜ static version ํŒŒ์ผ
const { data } = await axios.get("/web-version.json", params);
const { version } = data;

improvement [1]
SPA์˜ versioning ๊ด€๋ฆฌ

HTML์˜ ์บ์‹ฑ ๋น„ํ™œ์„ฑํ™”

  • ํ˜„์žฌ ๋ฒ„์ „๊ณผ ๋ฐฐํฌ๋œ ์ตœ์‹  ๋ฒ„์ „์„ ๋น„๊ตํ•œ ํ›„, ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜์—ฌ ์›น ํŽ˜์ด์ง€์˜ ๋ฒ„์ „์„ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

  • HTML ํŒŒ์ผ์ด ์บ์‹ฑ๋˜์–ด ์žˆ์œผ๋ฉด, ๊ฐ™์€ app.[hash].js๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋ฏ€๋กœ ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ๊ฐ€ ์‹คํŒจ๋œ๋‹ค.

  • ๋”ฐ๋ผ์„œ, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ HTML ํŒŒ์ผ์˜ ์บ์‹œ๋ฅผ ์“ฐ์ง€ ์•Š๋„๋ก ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

<meta
  http-equiv="Cache-Control"
  content="no-cache, no-store, must-revalidate"
/>
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Pragma" content="no-cache" />

improvement [2]
Sentey log Grouping

  • ํ”„๋ก ํŠธ์—”๋“œ ์˜ค๋ฅ˜ ๋กœ๊ทธ ์ˆ˜์ง‘๊ธฐ - Sentry ์‚ฌ์šฉ

  • ๋ฌด๋ถ„๋ณ„ํ•œ ๊ฐ™์€ ์˜ค๋ฅ˜, ๋ถˆํ•„์š”ํ•œ ์˜ค๋ฅ˜ ๋“ฑ๋“ฑ์„ Sentry์˜ fingerprint๋กœ Grouping ์ ์šฉ

  • beforeSend์—์„œ์˜ ๋ถ„๋ฆฌ

// ----------------------------------------------------------------------------------------------------
import checkIE from "check-ie";
beforeSend: (event, hint) => {
  // IE๋Š” ๋ฆฌํฌํŒ… ๋ฌด์‹œ
  const result = checkIE(window.navigator.userAgent);
  if (result && result.isIE) {
    event.fingerprint = ["IE-USAGE"];
    if (event.exception.values[0]) {
      event.exception.values[0].type = "IE์‚ฌ์šฉ๊ฐ์ง€";
    }
    return event;
  }
};

improvement [3]
Hot Reload ์†๋„ ๊ฐœ์„ 

  • 5000์—ฌ ๊ฐœ๊ฐ€ ๋„˜๋Š” ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ => vue-cli-service serve์˜ ์†๋„ ๊ฐœ์„  ํ•„์š”

  • ์ €์žฅ์‹œ Hot Reload ๋ฐ˜์˜ ์†๋„: ์•ฝ 7.46์ดˆ => ๋‚ฎ์€ ์ƒ์‚ฐ์„ฑ

  • Vue-CLI์˜ Custom WebPack ์„ค์ •์„ ํ†ตํ•ด ๊ฐœ์„  => ์•ฝ 4.26์ดˆ๋กœ ๊ฐœ์„  (๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ ์ฆ๋Œ€)

module.exports = {
  configureWebpack: {
    devtool:
      process.env.NODE_ENV === "production"
        ? "source-map"
        : "eval-cheap-source-map",
  },
};

toy project [0]
creco.today

์ปดํ“จํŒ… ๋ฆฌ์†Œ์Šค์—†์ด FrontEnd๋ฅผ ์œ„ํ•œ ๋ธ”๋กœ๊ทธ ๋ฐ ๋™์  ์›น ์‚ฌ์ดํŠธ๋ฅผ ๊ธฐํš

Static Resource(HTML, JavaScript, CSS)

  • GitHub Project Repo โ†’ GitHub Actions โ†’ S3 โ†’ CloudFront โ†’ Route53

Dynamic Resource(JSON API)

  • GitHub Data Repo โ†’ GitHub Actions โ†’ S3 โ†’ CloudFront โ†’ Route53

toy project [1]
marp-slide

ํฌํŠธํด๋ฆฌ์˜ค์šฉ PPT๋ฅผ MarkDown์œผ๋กœ ์ž‘์„ฑํ•˜๊ณ  Slide๋กœ ๋ณด๊ธฐ ์œ„ํ•ด ๊ธฐํš

  • marp-core, tiny-slider

๊ธฐ์กด์˜ https://web.marp.app ์€ ๋ฐœํ‘œ๋ชจ๋“œ๊ฐ€ ์—†๋Š” ๋‹จ์ ์— ์ฐฉ์•ˆ

marp-core์™€ tiny-slider๋ฅผ ํ™œ์šฉํ•ด VanillaJS ์ปดํฌ๋„ŒํŠธ ์ž‘์„ฑ

ex) https://creco.today/portfolio

toy experience [0]
CI/CD NPM ์ž๋™ ๋ฐฐํฌ

GitHub Actions๋ฅผ ํ™œ์šฉํ•œ NPM ์ž๋™ publish

# ---------------------------------------------------------------------------------------------------------
on:
  push:
    branches:
      - master
jobs:
  publish-npm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: actions/setup-node@v1
        with:
          node-version: 12
          registry-url: https://registry.npmjs.org/
      - run: yarn install
      - run: yarn build
      - name: npm publish
        env:
          NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
        run: npm publish
# ---------------------------------------------------------------------------------------------------------

toy experience [1]
GitHub Actions scheduler

GitHub Actions๋ฅผ ํ™œ์šฉํ•œ ๋ฌด๋ฃŒ ์Šค์ผ€์ฅด๋ง ์ปดํ“จํŒ… ๋ฆฌ์†Œ์Šค

https://github.com/CreatiCoding/action-scheduler

on:
  schedule:
    - cron: "*/10 * * * *"
  • 5๋ถ„ ๋‹จ์œ„, ํŽซํ”„๋ Œ์ฆˆ SEO ๊ฒ€์ฆ โ†’ ํ…”๋ ˆ๊ทธ๋žจ ์›นํ›…
  • 5๋ถ„ ๋‹จ์œ„, ์‹ ํŒŒํŠธ๋„ˆ ํ”„๋ก ํŠธ ๋ชจ๋‹ˆํ„ฐ๋ง โ†’ ํ…”๋ ˆ๊ทธ๋žจ ์›นํ›…
  • 1์ผ ๋‹จ์œ„, ํŠน์ • ๊ณต์ง€์‚ฌํ•ญ ํฌ๋กค๋ง โ†’ ํ…”๋ ˆ๊ทธ๋žจ ์›นํ›…

toy experience [2]
AWS Lambda Image Upload

  • AWS Lambda๋ฅผ HTTP API GateWay๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ง€์ • ๋„๋ฉ”์ธ์œผ๋กœ ์ œ๊ณต(Route53)

  • ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค ์šด์˜

toy experience [3]
AWS JavaScript SDK

  • AWS JavaScript SDK๋กœ ์ œ๊ณต๋˜๋Š” ์ฝ”๋“œ๋กœ ์ง์ ‘ AWS ์ธํ”„๋ผ DevOps๋ฅผ ์ž๋™ํ™”
  • ์ถ”ํ›„ ๋™์ผํ•œ ์„ธํŒ…์— ๋Œ€ํ•ด์„œ ์ž๋™ํ™”๋œ ์Šคํฌ๋ฆฝํŠธ ์ด์šฉ ๊ฐ€๋Šฅ

OpenSource Contributes

marp-team/marpit README.md ๊ธฐ์—ฌ

webpack-korea/webpack.js.org ๋ฒˆ์—ญ ์ฐธ์—ฌ

https://github.com/orgs/webpack-korea/people

  • WebPack ํ•œ๊ธ€ํ™” ๋ฒˆ์—ญ ์ฐธ์—ฌ (ํ˜„์žฌ ์ง„ํ–‰ ์ค‘)

ko.javascript.info ๋ฒˆ์—ญ ํ”„๋กœ์ ํŠธ ์ฐธ์—ฌ

OpenSource Contributes

sequelize-auto help ๋ฌธ๊ตฌ ์ˆ˜์ •

vue-iamport ์˜ค๋ฅ˜ ์ˆ˜์ •

vue-barcode-reader ๋ฐ๋ชจ ์ถ”๊ฐ€

๐Ÿคฉ Thanks for review!

To see more Resume

Resume https://creco.today/about
WebSite https://creco.today
GitHub https://github.com/CreatiCoding
Twitter https://twitter.com/creaticoding
Email nodejsdeveloper@kakao.com
Mobile 010-5189-7852