[TIL] 211206

Lee Syong·2021년 12ė›” 6ėž
0

TIL

ëŠĐ록 ëģīęļ°
110/204
post-thumbnail

📝 ė˜Ī늘 한 ęēƒ

  1. user profile ëģĩėŠĩ

  2. webpack - babel-loader / SCSS loader / MiniCssExtractPlugin


📚 ë°°ėšī ęēƒ

1. user profile ëģĩėŠĩ

ėē˜ėŒëķ€í„° ë‹Īė‹œ ęĩŽí˜„í•īëģļ 후 í—·ę°ˆë ļ거나 ë‹Īė‹œ ëģīęģ  ė‹ķė€ ëķ€ëķ„ ė •ëĶŽ

1) DB ė—…데ėīíŠļ / session ė—…데ėīíŠļ

model.findByIdAndUpdate()는 ė—…데ėīíŠļ ė „ė˜ 데ėī터ëĨž return 한ë‹Ī.
ė—…데ėīíŠļ 후ė˜ 데ėī터ëĨž 받ęļ° ėœ„í•īė„œëŠ” { new: true } ė˜ĩė…˜ė„ ėĪ˜ė•ž 한ë‹Ī.

2) multer ė‚ŽėšĐ

파ėžė„ ė—…ëĄœë“œ 하ęļ° ėœ„í•īė„œëŠ” express가 파ėž ęē―로ëĨž ė•Œ ėˆ˜ ėžˆë„록 ėķ”ę°€í•˜ęģ , express.static("ëļŒëžėš°ė €ė— ë…ļėķœė‹œí‚Ž íī더 ėīëĶ„")ė„ ė‚ŽėšĐí•īė•ž 한ë‹Ī.

app.use("/uploads", express.static("uploads"));

3) video owner profile

videoëĨž ė—…ëĄœë“œí•œ userė˜ profileė€ 누ęĩŽë‚˜ ëģž ėˆ˜ ėžˆë„록 req.session.user._id가 ė•„니띞 req.params.idëĨž ė‚ŽėšĐí•īė•ž 한ë‹Ī.

4) loggedInUser is undefined

// watch.pug

// ėƒëžĩ
  if String(video.owner._id) === loggedInUser._id
    a(href=`${video.id}/edit`) Edit Video →
    a(href=`${video.id}/delete`) Delete Video →

ėœ„ ė―”ë“œė˜ ęē°ęģž, 로ę·ļėļ 하ė§€ ė•Šė€ user가 homeė—ė„œ video.titleė„ íīëĶ­í•ī watch 페ėīė§€ė— ë“Īė–ī가ë Īęģ  하ëĐī, loggedInUser가 undefined띞ė„œ ė—ëŸŽę°€ ëœĻ는 ëŽļė œę°€ 발ėƒí•œë‹Ī.

// middlewares.js
export const localsMiddleware = (req, res, next) => {
  res.locals.siteName = "Wetube";
  res.locals.loggedIn = true;
  res.locals.loggedInUser = req.session.user || {}; // ėī ëķ€ëķ„ė— || {} ëĨž ėķ”ę°€í–ˆë‹Ī ❗
};

localsMiddlewareė—ė„œ user가 로ę·ļėļ하ė§€ ė•Šė•„도 loggedInUser가 true 값ė„ 가ė§ˆ ėˆ˜ ėžˆë„록 ėˆ˜ė •í•īė•ž 한ë‹Ī.

5) req.session.loggedInęģž res.locals.loggedInUser ëđ„ęĩ

// middlewares.js
export const localsMiddleware = (req, res, next) => {
  res.locals.siteName = "Wetube";
  res.locals.loggedIn = Boolean(req.session.loggedIn);
  res.locals.loggedInUser = req.session.user || {};
  next();
};

export const protectorMiddleware = (req, res, next) => {
  if (res.locals.loggedInUser) { // req.session.loggedInėœžëĄœ ëģ€ęē― ❗
    next();
  } else {
    return res.redirect("/login");
  }
};

export const publicOnlyMiddleware = (req, res, next) => {
  if (!res.locals.loggedInUser) { // req.session.loggedInėœžëĄœ ëģ€ęē― ❗
    next();
  } else {
    return res.redirect("/");
  }
};

ė›đ ė‚ŽėīíŠļė˜ ė–īë–Ī 페ėīė§€ė— ë“Īė–ī갈 때도 localsMiddleware가 ė‹Ī행되ęļ° 때ëŽļė— req.session.userė˜ 값ė— 따띾 loggedInUserė˜ 값ėī 닮띾ė§ˆ ėˆ˜ë„ ėžˆė§€ë§Œ

ė•žė„œ localsMiddlewareė—ė„œ loggedInUserė˜ 값ė„ ëŽīėĄ°ęąī true가 되도록 || {}ė„ ėķ”ę°€í–ˆęļ° 때ëŽļė—
ėœ„ė™€ 같ėī protectorMiddlewareė™€ publicOnlyMiddlewareė—ė„œ res.locals.loggedInUserëĨž ė‚ŽėšĐ하ëĐī ę·ļ 값ėī ëŽīėĄ°ęąī true가 되ė–ī ė—ëŸŽę°€ 발ėƒí•œë‹Ī.

따띾ė„œ, res.locals.loggedInUser 대ė‹ ė— req.session.loggedInė„ ė‚ŽėšĐí•īė•ž 한ë‹Ī.


2. Webpack

1) Webpackėī란?

Webpackėī란 ėžë°”ėŠĪ큎ëĶ―íŠļ나 CSS, ėīëŊļė§€ 등ė˜ ëĶŽė†ŒėŠĪë“Īė„ ëģ€í™˜í•˜ęģ  ëŽķė–īėĢžëŠ” ëŠĻ듈 ëēˆë“Ī럮ëĨž 말한ë‹Ī.

ë‹Ī만, react.js, vue.js 등 대ëķ€ëķ„ė˜ 큰 프레ėž„ė›ŒíŽė—ëŠ” webpackėī ėīëŊļ ë‚īėžĨ되ė–ī ėžˆęļ° 때ëŽļė— ė‹Īė œëĄœ webpackė„ ė§ė ‘ ėž‘ė„ąí•īëģž ėžė€ ęą°ė˜ ė—†ë‹Ī.

ę·ļ럮나, ėī는 ė—…ęģ„ 표ėĪ€ėœžëĄœėĻ ėĩœė†Œí•œ ė–īë–ŧęēŒ ėž‘동하는ė§€ëŠ” ė•Œė•„ė•ž 하ęļ° 때ëŽļė— ėīí•īëĨž ėœ„í•ī webpack configuration 파ėžė„ ėž‘ė„ąí•īëģīë Īęģ  한ë‹Ī.

2) webpack ė„Īėđ˜ 및 ė‚ŽėšĐëē•

(1) ė„Īėđ˜

npmė„ ėīėšĐí•ī webpackęģž webpack cliëĨž devDependenciesė— ė„Īėđ˜í•œë‹Ī.
webpack cliëĨž ėīėšĐí•ī ė―˜ė†”ė—ė„œ webpackė„ ëķˆëŸŽë‚ž ėˆ˜ ėžˆë‹Ī.

$ npm i webpack webpack-cli --save-dev

(2) entry / output

프로ė íŠļ íī더ė— webpack.config.js 파ėžė„ 만든ë‹Ī.
ėī 파ėžė—ëŠ” ėĩœė‹  ė―”ë“œëĨž ė‚ŽėšĐí•īė„œëŠ” ė•ˆëœë‹Ī.

export default, import (x)
module.exports = {}, const ~ require() (o)

webpackė„ ė‚ŽėšĐ하ęļ° ėœ„í•īė„œëŠ” entryė™€ outputė„ 반드ė‹œ ė§€ė •í•īėĪ˜ė•ž 한ë‹Ī.
entry란 webpackė„ ęą°ėģ ëģ€í˜•ė‹œí‚Īęģ ėž 하는 파ėžė˜ ęē―로ëĨž 말한ë‹Ī.
outputėī란 webpackė„ ęą°ėģ ëģ€í˜•ëœ ęē°ęģžëŽžė„ ė €ėžĨ할 파ėžëŠ…ęģž ę·ļ 파ėžėī ė €ėžĨ될 ęē―로ëĨž 말한ë‹Ī.

ėī때 ę·ļ 파ėžėī ė €ėžĨ될 ęē―로는 ė ˆëŒ€ ęē―로로 ėž‘ė„ąí•īė•ž 한ë‹Ī.
ėīëĨž ėœ„í•ī path.resolve(__dirname, "")ëĨž ėīėšĐ한ë‹Ī.
path.resolve()는 ėž…ë Ĩ한 ëŠĻ든 파íŠļë“Īė„ ëŠĻė•„ ęē―로로 만ë“Īė–īėĪ€ë‹Ī.
dirnameėī란 rootëķ€í„° íī더ęđŒė§€ė˜ ęē―로 ė „ėēīëĨž ė˜ëŊļ한ë‹Ī.

ė‹ĪėŠĩė„ ėœ„í•ī ė•„래ė™€ 같ėī ė„Īė •í•œ 후, src/client/js íī더 ė•ˆė— main.js 파ėžė„ 만ë“Īė–ī ėĩœė‹  ė―”ë“œëĨž ėž‘ė„ąí–ˆë‹Ī.

// webpack.config.js
const path = require("path");

module.exports = {
  entry: "./src/client/js/main.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "assets", "js"),
  },
};

package.json 파ėžė—ė„œ assets scriptëĨž 만든 후 ė―˜ė†”ė—ė„œ ė‹Ī행한ë‹Ī.

// package.json
"scripts": {
  "assets": "webpack --config webpack.config.js"
},
$ npm run assets

ėžë™ėœžëĄœ assets/js íī더ė™€ í•Ļęŧ˜ ę·ļ ė•ˆė— ëģ€í˜•ëœ ė―”ë“œę°€ ë‹īęļī main.js 파ėžėī 만ë“Īė–īė§„ ęēƒė„ 확ėļ할 ėˆ˜ ėžˆë‹Ī.
( + assets íī더ëĨž .gitignore 파ėžė— ėķ”ę°€í•˜ė—Ž githubė— ė—…ëĄœë“œí•˜ė§€ ė•Šë„록 한ë‹Ī.)

ėī ė―”드는 ė œëŒ€ëĄœ ėž‘동하ęģ  ėžˆė§€ë§Œ, ėžëķ€ ė―”드는 ëļŒëžėš°ė €ę°€ ėīí•ī하ė§€ ëŠŧ할 ėˆ˜ë„ ėžˆęļ° 때ëŽļė— í˜ļ환ė„ąė„ 확ëģīí•īė•ž 한ë‹Ī.

따띾ė„œ, ė•žė„œ ë°ąė—”ë“œ ė―”ë“œ ėē˜ëĶŽëĨž ėœ„í•ī package.json 파ėžė—ė„œ babelė„ ė‚ŽėšĐ했ë“Ŋėī, 프론íŠļė—”ë“œ ė―”ë“œ ėē˜ëĶŽëĨž ėœ„í•ī webpack.config.js 파ėžė—ė„œ babelė„ ė‚ŽėšĐí•īė•ž 한ë‹Ī.

(3) rules (ëŠĻ든 js 파ėžė— babel-loader ė ėšĐ)

íŠđė • ėĒ…ëĨ˜ė˜ 파ėžė— íŠđė • ëģ€í˜•ė„ ė ėšĐ하ęļ° ėœ„í•ī rulesëĨž ė‚ŽėšĐí•īė•ž 한ë‹Ī.
webpackė€ loaderëĨž í†ĩí•ī 파ėžė„ ė „환ė‹œí‚Ļë‹Ī.
ėī ęē―ėš°ė—ëŠ” JavaScript ė―”ë“œ(test)ëĨž babel-loader(use, loader)ëĨž ėīėšĐí•ī ëģ€í™˜í•īė•ž 한ë‹Ī.

babel-loaderė„ ėīėšĐ하ęļ° ėœ„í•īė„œëŠ” ë‹ĪėŒ ëŠĻ듈ë“Īė„ ė„Īėđ˜í•īė•ž 한ë‹Ī.
나ëĻļė§€ëŠ” ëŠĻ두 ė„Īėđ˜ë˜ė–ī ėžˆėœžëŊ€ëĄœ babel-loader만 따로 ė„Īėđ˜í•īėĢžė—ˆë‹Ī.

npm install -D babel-loader @babel/core @babel/preset-env webpack

babel-loader ė‚ŽėšĐëē•ė€ ė•„래ė™€ 같ë‹Ī.
babel-loaderëĨž ė°ļęģ í•ī webpack.config.js 파ėžė„ ėˆ˜ė •í–ˆë‹Ī.

// webpack.config.js
const path = require("path");

module.exports = {
  // ėƒëžĩ
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [["@babel/preset-env", { targets: "defaults" }]],
          },
        },
      },
    ],
  },
};

ėīė œ webpackė€ babel-loaderė— 멇 가ė§€ ė˜ĩė…˜ė„ ė „í•īėĢžëĐīė„œ ėīëĨž ėīėšĐí•ī ëŠĻ든 js 파ėžė„ ëģ€í˜•í•˜ë„록 한ë‹Ī.

ë‹Īė‹œ assets/jsė—ė„œ main.js 파ėžė„ 확ėļí•īëģīëĐī, babel-loaderė— ė˜í•ī JavaScript ė―”ë“œę°€ 한ëēˆ 더 ëģ€í™˜ëœ ęēƒė„ 확ėļ할 ėˆ˜ ėžˆë‹Ī.

(4) mode ė˜ĩė…˜

npm run assetsė„ ė‹Ī행하ė—Ž assets íī더ëĨž 만ë“Īė—ˆė„ 때ëķ€í„° ė―˜ė†” ė°―ė— mode optionėī ė„Īė •ë˜ė§€ ė•Šė•˜ë‹Ī는 ęē―ęģ  ëŽļęĩŽę°€ 떠 ėžˆë‹Ī.

ėīëĨž í•īęē°í•˜ęļ° ėœ„í•ī webpackė—ęēŒ ėī ė―”ë“œę°€ ė§€ęļˆ 개발 ėĪ‘ėļė§€ ė•„ë‹Œė§€ëĨž ė•Œë ĪėĪ˜ė•ž 한ë‹Ī.
modeëĨž ė„Īė •í•˜ė§€ ė•ŠėœžëĐī webpackė€ ęļ°ëģļė ėœžëĄœ production mode로 ė„Īė •ë˜ė–ī ëŠĻ든 ė―”ë“œë“Īė„ ė••ėķ•í•ĻėœžëĄœėĻ ė—ëŸŽëĨž ė°ūęļ° 힘ë“Īęļ° 때ëŽļėīë‹Ī.

따띾ė„œ, 현ėžŽëŠ” development mode로 ė„Īė •í•œ 후, 나ėĪ‘ė— ė„œëē„ė— ë°ąė—”ë“œëĨž ė§ė ‘ ė˜ŽëĶī 때 ėīëĨž 바ęŋ”ëģž ęēƒėīë‹Ī.

const path = require("path");

module.exports = {
  entry: "./src/client/js/main.js",
  mode: "development", // ėķ”ę°€ ❗
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "assets", "js"),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [["@babel/preset-env", { targets: "defaults" }]],
          },
        },
      },
    ],
  },
};

(5) ëļŒëžėš°ė €ė— assets íī더 ęģĩ개

ė•„ė§ express는 assets띾는 íī더ė˜ ėĄīėžŽëĨž ëŠĻëĨīęģ , ëļŒëžėš°ė €ë„ í•īë‹đ íī더ė— ė ‘ę·ží•  ėˆ˜ ė—†ë‹Ī.
server.js 파ėžė—ė„œ express.static()ė„ ėīėšĐí•ī ëļŒëžėš°ė €ę°€ assets íī더ė— ė ‘ę·ží•  ėˆ˜ ėžˆë„록 한ë‹Ī.

ėī때 ęē―로ė˜ ėīëĶ„ė€ ė–īë–Ī ėīëĶ„ėœžëĄœë“  ėž‘ė„ąí•  ėˆ˜ ėžˆė§€ë§Œ, íī더 ėīëĶ„ė€ ėœ„ė—ė„œ 만든 íī더 ėīëĶ„ ę·ļ대로 ėž‘ė„ąí•īė•ž 한ë‹Ī.
ė˜ˆëĨž ë“Īė–ī, ė•„래ė™€ 같ėī ėž‘ė„ąí–ˆë‹ĪëĐī assets íī더ė˜ ë‚īėšĐė„ /static ėĢžė†ŒëĨž í†ĩí•ī ęģĩ개하도록 하는 ęēƒėīë‹Ī.

// server.js
app.use("/static", express.static("assets"));

base.pug 파ėžėī main.js 파ėžė„ ëķˆëŸŽė˜Ž ėˆ˜ ėžˆë„록 assets/js/main.jsëĨž base.pugė™€ ė—°ęē°í•œë‹Ī.
ëļŒëžėš°ė €ëŠ” /static ~ ęē―로ė—ė„œ assets íī더 ë‚īėšĐė„ ëģž ėˆ˜ ėžˆë‹Ī.

//- base.pug

// ėƒëžĩ
include partials/footer
script(src="/static/js/main.js")

ėīė œ ė›đ ė‚ŽėīíŠļė˜ ė–īë–Ī 페ėīė§€ė— ë“Īė–ī가든 main.js 파ėžė˜ ë‚īėšĐėī ė‹Ī행된ë‹Ī.
â€ŧ /static/js/main.js는 node.js ė―”ë“œę°€ ė•„니띞 'ëļŒëžėš°ė €ė—ė„œ ėž‘동하는 js ė―”ë“œ'ėīë‹Ī.

ðŸ’Ą ė •ëĶŽí•˜ëĐī

📌 src/client/js/main.jsė— ėĩœė‹  js ė―”ë“œëĨž ėž‘ė„ąí•˜ëĐī
📌 webpack.config.jsė— 따띾 ę·ļęēƒė˜ ëģ€í˜•ëœ ęē°ęģžëŽžėī assets/js/main.jsė— ë‹īęļ°ęēŒ 된ë‹Ī.
📌 pug 파ėžė€ assets íī더로ëķ€í„° ę·ļ ęē°ęģžëŽž(js ė―”ë“œ)ė„ ëķˆëŸŽė˜Ļë‹Ī.

3) SCSS loader

(1) scss 파ėž 만ë“Īęļ°

client íī더 ė•ˆė— scss íī더ëĨž 만든 후 ę·ļ ė•ˆė— styles.scss 파ėžęģž _variables.scss 파ėžė„ 만든ë‹Ī.

// _variables.scss
$red: red;
// style.scss
@import "./_variables";

body {
  background-color: $red;
}

client íī더 ė•ˆė˜ js íī더 ė•ˆė˜ main.js 파ėžė—ė„œ, client íī더 ė•ˆė˜ scss íī더 ė•ˆė˜ styles.scss 파ėžė„ import 한ë‹Ī.

// main.js
import "../scss/styles.scss";

console.log("hi");

(2) rules

loaderëĨž ė§€ė •í•  때는 ėœ„ė—ė„œ ėž‘ė„ąí•œ ęēƒėē˜ëŸž 할 ėˆ˜ë„ ėžˆė§€ë§Œ, ė—ŽëŸŽ 개ė˜ loaderëĨž ëŠĻė•„ė„œ ė§€ė •í•  ėˆ˜ë„ ėžˆë‹Ī.

ė˜ˆëĨž ë“Īė–ī, scss 파ėžė„ ėē˜ëĶŽí•˜ęļ° ėœ„í•īė„œëŠ” ë‹ĪėŒęģž 같ė€ ė„ļ 개ė˜ loader가 필ėš”하ë‹Ī.

  • sass-loader: scss 파ėžė„ ėžë°˜ css 파ėžëĄœ ëģ€í™˜
$ npm install sass-loader sass webpack --save-dev
  • css-loader: scss 파ėžė˜ @importė™€ url()ė„ import/require()로 풀ė–īė„œ í•īė„
$ npm install --save-dev css-loader
  • style-loader: ëģ€í™˜ëœ cssëĨž ëļŒëžėš°ė €ė— ė ėšĐ (cssëĨž DOMė— ėĢžėž…)
$ npm install --save-dev style-loader

ėœ„ 3개ė˜ loaderëĨž ė•„래ė™€ 같ėī 한 ëēˆė— ëŠĻė•„ė„œ ė ė–īėĪ„ ėˆ˜ ėžˆë‹Ī.
ėī때 ėĢžė˜í•  ė ė€ ė‚ŽėšĐ ėˆœė„œė™€ 반대로 ė ė–īė•ž 한ë‹Ī는 ęēƒėīë‹Ī.
ėĶ‰, 가ėžĨ ėē˜ėŒ ė‚ŽėšĐ될 loaderëĨž 가ėžĨ 나ėĪ‘ė— ė ė–īė•ž 한ë‹Ī.

// webpack.config.js
const path = require("path");

module.exports = {
  entry: "./src/client/js/main.js",
  mode: "development",
  output: path.resolve(__dirname, "assets", "js"),
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [["@babel/preset-env", { targets: "defaults" }]],
          },
        },
      },
      {
        test: /\.scss$/,
        use: ["style-loader", "css-loader", "sass-loader"],
      },
    ],
  },
};

ėīė œ ė―˜ė†”ė— npm run assetsëĨž ėž…ë Ĩ하ëĐī

webpackė€ entry 파ėž(main.js)ė„ 가ė ļė˜Ļë‹Ī.
webpackė€ ę·ļ main.js 파ėžėī JavaScript 파ėžėž„ė„ ėļė‹í•œ 후, ėīëĨž babelė„ ėīėšĐí•ī ëģ€í™˜í•˜ëŠ”데
main.js 파ėžė—ė„œ import í•īėĪ€ 파ėžėī scss 파ėžėž„ė„ ėļė‹í•œ 후, scss 파ėžė„ scss, css, style loaderëĨž ėīėšĐí•ī css 파ėžëĄœ ëģ€í™˜í•˜ęģ  ėīëĨž ė›đ ė‚ŽėīíŠļė˜ head ė•ˆė— ėž…ë Ĩí•ī ëļŒëžėš°ė €ė— ė ėšĐė‹œí‚Ļë‹Ī.

(3) MiniCssExtractPlugin

CSSëĨž ėķ”ėķœí•īė„œ ë‹ĪëĨļ 파ėžëĄœ ëķ„ëĶŽí•˜ęļ° ėœ„í•ī MiniCssExtractPluginė„ ė„Īėđ˜í•œë‹Ī.

$ npm install --save-dev mini-css-extract-plugin

ėī는 style-loaderëĨž 대ė‹ í•˜ė—Ž ë‹ĪėŒęģž 같ėī ė‚ŽėšĐ할 ėˆ˜ ėžˆë‹Ī.
ė―”ë“œ ė–‘ė‹ėīęļ° 때ëŽļė— ė™ļėšļ 필ėš”는 ė—†ë‹Ī. ( MiniCssExtractPlugin ė°ļęģ  )

// webpack.config.js
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // ėķ”ę°€ ❗

module.exports = {
  entry: "./src/client/js/main.js",
  mode: "development",
  plugins: [new MiniCssExtractPlugin()], // ėķ”ę°€ ❗
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "assets", "js"),
  },
  module: {
    rules: [
      // ėƒëžĩ (babel-loader)
      {
        test: /\.scss$/, // ëŠĻ든 scss 파ėž
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], // ėˆ˜ė • ❗
      },
    ],
  },
};

ë‹Īė‹œ npm run assetsëĨž ė‹Ī행하ëĐī assets íī더 ė•ˆė˜ js íī더 ė•ˆė— main.js 파ėžęģž 더ëķˆė–ī main.css 파ėžėī ėƒęļīë‹Ī.

ę·ļ런데 jsė™€ css가 ëķ„ëĶŽë˜ęļ°ëŠ” 했ė§€ë§Œ, assets íī더 ė•ˆė˜ js íī더ė— í•Ļęŧ˜ ë“Īė–ī가 ėžˆë‹Ī.

css 파ėžė€ css íī더ė—, js 파ėžė€ js íī더ė— ë„Ģęļ° ėœ„í•ī
webpack.config.js 파ėžė˜ output ëķ€ëķ„ė—ė„œ filenameė„ ėˆ˜ė •í•˜ęģ 
MiniCssExtractPlugin ëķ€ëķ„ė— filename ė˜ĩė…˜ė„ ë„Ģė–īėĪ€ë‹Ī.

module.exports = {
  entry: "./src/client/js/main.js",
  mode: "development",
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/styles.css", // ėķ”ę°€ ❗
    }),
  ],
  output: { 
    filename: "js/main.js", // ėˆ˜ė • ❗
    path: path.resolve(__dirname, "assets"), // "js" ė‚­ė œ ❗
  },
  // ėƒëžĩ
};

(4) pug 파ėžęģž css 파ėž ė—°ęē°

base.pug 파ėžėī style.css 파ėžė„ ëķˆëŸŽė˜Ž ėˆ˜ ėžˆë„록 assets/css/style.cssëĨž base.pugė™€ ė—°ęē°í•œë‹Ī.

//- base.pug

doctype html
html(lange="ko")
  head
    title #{pageTitle} | #{siteName}
    link(rel="stylesheet" href="https://unpkg.com/mvp.css")
    link(rel="stylesheet" href="/static/css/styles.css")

// ėƒëžĩ
  include partials/footer
  script(src="/static/js/main.js")

ðŸ’Ą ë‹Īė‹œ 한ëēˆ 더 ė •ëĶŽí•˜ëĐī

📌 webpackė— ė˜í•īė„œ client íī더 ë‚īė˜ 파ėžë“Īėī 로ë”Đ된ë‹Ī.
📌 webpackė„ ęą°ėđœ 후ė˜ ęē°ęģžëŽžë“Īė€ assets íī더 ė•ˆė— 만ë“Īė–īė§„ë‹Ī.
📌 ę·ļ ęē°ęģžëŽžë“Īė€ base.pug 파ėžė—ė„œ 로ë”Đ되ė–ī ëļŒëžėš°ė €ė— ëģīėīęēŒ 된ë‹Ī.

4) 개발 환ęē― 개ė„ 

(1) ė €ėžĨ할 때마ë‹Ī ėžë™ ė—…데ėīíŠļ

ė§€ęļˆėœžëĄœėŽ scss나 프론íŠļė—”ë“œ ėŠ― js 파ėžė—ė„œ ė―”ë“œëĨž ëģ€ęē―할 때마ë‹Ī ė―˜ė†”ė— npm run devëĨž ėž…ë Ĩí•īė•žë§Œ ė—…데ėīíŠļ가 된ë‹Ī.
또한 멅ë đė–īëĨž ė‹Ī행하ęļ° ė „ė— í˜đė‹œ ëŠĻëĨž ė—ëŸŽëĨž ë°Đė§€í•˜ęļ° ėœ„í•ī 항ėƒ assets íī더ëĨž ė§€ė›ŒėĪ˜ė•žë§Œ 한ë‹Ī.

ė €ėžĨ할 때마ë‹Ī ėžë™ėœžëĄœ ė—…데ėīíŠļ가 되도록 watch functionė„ ė‚ŽėšĐ하도록 한ë‹Ī.
output íī더가 만ë“Īė–īė§€ęļ° ė „ė— ęļ°ėĄīė˜ output íī더가 ė‚­ė œë˜ë„록 clean ė˜ĩė…˜ė„ ė‚ŽėšĐ하도록 한ë‹Ī.

// webpack.config.js
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: "./src/client/js/main.js",
  mode: "development",
  watch: true,
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/style.css",
    }),
  ],
  output: {
    filename: "js/main.js",
    path: path.resolve(__dirname, "assets"),
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.js$/, // ëŠĻ든 js 파ėž
        use: {
          loader: "babel-loader",
          options: {
            presets: [["@babel/preset-env", { targets: "defaults" }]],
          },
        },
      },
      {
        test: /\.scss$/, // ëŠĻ든 scss 파ėž
        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
      },
    ],
  },
};

ėīė œ 항ėƒ 두 개ė˜ ė―˜ė†”ė„ í•Ļęŧ˜ ęĩŽë™í•īė•ž 한ë‹Ī.

$ npm run dev
$ npm run assets

(2) webpackė— ė˜í•ī ė„œëē„ę°€ ėžŽė‹œėž‘하ė§€ ė•Šë„록

ę·ļ런데 ėī렇ęēŒ 하ëĐī 프론íŠļė—”ë“œ ėžë°”ėŠĪ큎ëĶ―íŠļ ė―”ë“œëĨž ëģ€ęē―한 후 ė €ėžĨė„ 할 때마ë‹Ī nodemonė— ė˜í•ī ë°ąė—”ë“œę°€ ėžŽė‹œėž‘된ë‹Ī.

ëŽļė œëĨž í•īęē°í•˜ęļ° ėœ„í•ī ėžëķ€ 파ėž 및 íī더는 ëģ€ęē―되더띾도 nodemonėī ėīëĨž ëŽīė‹œí•˜ęģ  ė„œëē„ëĨž ėžŽė‹œėž‘하ė§€ ė•Šë„록 í•īė•ž 한ë‹Ī.

ėīëĨž ėœ„í•ī 프로ė íŠļ íī더ė— nodemon.json 파ėžė„ ėƒė„ąí•œ 후 ė•„래ė™€ 같ėī ėž‘ė„ąí•œë‹Ī. (https://github.com/remy/nodemon ė°ļęģ )

// nodemon.json
{
  "ignore": ["webpack.package.js", "src/client/*", "assets/*"],
  "exec": "babel-node src/init.js"
}

ę·ļ 후, package.json 파ėžė—ė„œ dev script (nodemon -L --exec ...)ëĨž ėˆ˜ė •í•œë‹Ī.
( + assets script도 ėˆ˜ė •í•œë‹Ī. webpack.config.json 파ėžė€ webpackėī ė‹Ī행될 때 ęļ°ëģļė ėœžëĄœ ė°ū는 ė„Īė • 파ėžėīęļ° 때ëŽļė— ęĩģėī ë’Īė— ė ė–īėĢžė§€ ė•Šė•„도 된ë‹Ī. )

// ėˆ˜ė • ė „ package.json
"scripts": {
  "dev": "nodemon -L --exec babel-node src/init.js",
  "assets": "webpack --config webpack.config.json"
}
// ėˆ˜ė • 후 package.json
"scripts": {
  "dev:server": "nodemon -L",
  "dev:assets": "webpack"
}

script ėīëĶ„도 ė§ęī€ė ėœžëĄœ 바ęŋ”ėĢžė—ˆë‹Ī.
항ėƒ 각각 ë‹ĪëĨļ ė―˜ė†”ė—ė„œ 두 개ė˜ 멅ë đė–īëĨž ëŠĻ두 ė‹Ī행í•īė•ž 한ë‹Ī.
하나는 ė„œëē„ëĨž ė‹Ī행ė‹œí‚Īęģ  템플ëĶŋęģž urlė„ 확ėļ하ęļ° ėœ„í•ī 필ėš”하ęģ , ë‹ĪëĨļ 하나는 client 파ėžė„ 확ėļ하ęļ° ėœ„í•ī 필ėš”하ë‹Ī.


âœĻ ë‚īėž 할 ęēƒ

  1. 강ė˜ ęģ„ė† ë“Ģęļ°
profile
ëŠĨ동ė ėœžëĄœ ė‚īėž, 행ëģĩ하ęēŒðŸ˜

0개ė˜ 댓ęļ€