FrontEnd/프론트엔드 개발환경의 이해와 실습 (webpack, babel, esli

바벨(Babel) , 린트(Lint)

Tony Lim 2024. 8. 30. 09:35
728x90

크로스 브라우징

브라우져 마다 사용하는 언어가 달라서 프론트엔드 코드는 일관적이지 못할 때가 많다.

바벨은 ECMAScript2015+ 로 작성한 코드를 모든 브라우져에서 동작하도록 호환성을 지켜준다.

 

바벨은 3단계로 빌드를 진행한다. 

파싱 -> 변환 -> 출력

module.exports = function myBabelPlugin() {
  return {
    visitor: {
      Identifier(path) {
        const name = path.node.name;

        // 바벨이 만든 AST 노드를 출력한다
        console.log("Identifier() name:", name)

        // 변환작업: 코드 문자열을 역순으로 변환한다.
        path.node.name = name
          .split("")
          .reverse()
          .join("");
      }
    }
  }
}

바벨에서도 플러그인을 사용할 수 있다. 이는 webpack plugin과는 다른 것이다.

$ npx babel app.js --plugins "./my-babel-plugin.js"

Identifier() name: alert
Identifier() name: msg
Identifier() name: window
Identifier() name: alert
Identifier() name: msg
const trela = gsm => wodniw.trela(gsm);

babel에서 path 를 주입해준다.

module.exports = function myBabelPlugin() {
  return {
    visitor: {
      VariableDeclaration(path) {
        console.log("VariableDeclaration() kind:", path.node.kind);

        // const => var 변환
        if (path.node.kind === "const") {
          path.node.kind = "var";
        }
      },
    },
  };
};
~/workspace/frontend/sample on  main! ⌚ 11:32:50
$ npx babel app.js --plugins "./my-babel-plugin.js"

VariableDeclaration() kind: const
var alert = msg => window.alert(msg);
~/workspace/frontend/sample on  main! ⌚ 11:39:01
$ npx babel app.js --plugins @babel/plugin-transform-block-scoping
var alert = msg => window.alert(msg);

위와 똑같은기능을 하는 plugin이 별도로 npm에 존재한다. 이런것처럼 미리 만들어진 babel plugin들이 많이 존재한다.

module.exports = {
  plugins: [
    "@babel/plugin-transform-block-scoping",
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-strict-mode",
  ]
}

이런식으로 babel.config.js에 export 해주고나면 npx babel app.js 하면 3가지 plugins들이 적용이 된다.

 

preset으로 적용하는 방법도 존재한다

module.exports = function myBabelPreset() {
  return {
    plugins: [
    "@babel/plugin-transform-block-scoping",
    "@babel/plugin-transform-arrow-functions",
    "@babel/plugin-transform-strict-mode",
    ]
  }
}

my-babel-preset.js 에서 plugins들을 돌려주는 함수들을 정의한다.

module.exports = {
  presets: [
    "./my-babel-preset.js"
  ]
}

npx babel app.js 를 통해 동일하게 실행시킬 수 있다.


바벨 사용법과 웹팩 통합

preset-env, preset-flow, preset-react, preset typescript 처럼 많이 쓰이는 프리셋들이 있다.

module.exports = {
  presets: [
    ["@babel/preset-env",{
        targets: {
          chrome: "79"
        }
    }]
  ]
}
~/workspace/frontend/sample on  main! ⌚ 14:31:01
$ npx babel app.js                                                
"use strict";

const alert = msg => window.alert(msg);

chrome 79version에서는 arrow, const를 지원해서 딱히 변환이 되어있지 않다. target 브라우저에 따라 알맞게 변환된다.

Promise 클래스의 경우 IE에서 지원하지 않는데 이때 "폴리필" 이라는 코드조각을 추가해서 해결할 수 있다.

module.exports = {
  presets: [
    ["@babel/preset-env",{
        targets: {
          chrome: "79",
          ie: "11",
        },
        useBuiltIns: "usage", 
        corejs: {
          version: 2 , 
        }
    }]
  ]
}
~/workspace/frontend/sample on  main! ⌚ 14:37:19
$ npx babel app.js
"use strict";

require("core-js/modules/es6.object.to-string.js");
require("core-js/modules/es6.promise.js");
new Promise();

core-js라는 node 모듈에서 필요한 js를 로딩한후에 IE에서도 new Promise가 정상동작할 수 있게 변경되었다.

실무에서는 보통 이렇게 직접 babel으로 빌드하지않고 babel-loader를 통해서 webpack과 통합해서 사용한다.

module.exports = {
  mode: "development",
  entry: {
    main: "./app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          process.env.NODE_ENV === "production"
            ? MiniCssExtractPlugin.loader
            : "style-loader",
          "css-loader",
        ],
      },
      {
        test: /\.(png|jpg|gif|svg)$/,
        loader: "url-loader",
        options: {
          publicPath: "./dist/",
          name: "[name].[ext]?[hash]",
          limit: 2000, //2kb
        },
      },
      {
        test:/\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/
      },
    ],
  },
  plugins: [
    new MyWebpackPlugin(),
    new webpack.BannerPlugin({
      banner: `
        Build Date: ${new Date().toLocaleDateString()}
        Commit Version: ${childProcess.execSync("git rev-parse --short HEAD")}
        Author : ${childProcess.execSync("git config user.name")}
      `,
    }),
    new webpack.DefinePlugin({
      TWO: "1+1",
      "api.domain": JSON.stringify("http://dev/api.domain.com"),
    }),
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      templateParameters: {
        env: process.env.NODE_ENV === "development" ? "(개발용)" : "",
      },
      minify:
        process.env.NODE_ENV === "production"
          ? {
              collapseWhitespace: true,
              removeComments: true,
            }
          : false,
    }),
    new CleanWebpackPlugin({}),
    ...(process.env.NODE_ENV === "production"
      ? [new MiniCssExtractPlugin({ filename: "[name].css" })]
      : []),
  ],
};

ESLint

console.log()
(function() {})()

console.log()(function() {})()

브라우져가 코드에 세미콜론을 자동으로 넣는 과정에서 잘못해석하는 경우가 있다.

위 과정은 console.log 따로 즉시실행함수 따로 로 실행해야하는데 console.log의 return 값인 undefined에 대해 함수 호출을 시도한것으로 착각한 케이스이다.

주로 포맷팅, 코드품질 을 유지하기 위해서 쓰게 된다.

module.exports = {
  rules: {
    "no-unexpected-multiline": "error"
  }
}

eslint.config.js 에 위와 같이 설정하고 npx eslint app.js를 실행하면

$ npx eslint app.js

/home/tony/workspace/frontend/sample/app.js
  2:1  error  Unexpected newline between function and ( of function call  no-unexpected-multiline

✖ 1 problem (1 error, 0 warnings)

이런식으로 설정된 rule중에 지키지 않은것이 뭔지 알려준다.

여러 rule들이 존재하는데 렌치 표시가 있는것들은 자동으로 수정까지 해주는 rule이다.

 

Extensible Config

eslint:recommanded는 미리 설정된 규칙 세트를 활용한다.

eslint-plugin-prettier 를 통해 eslint만 돌려도 prettier도 함께 돌려주는 기능이 존재한다.


husky

git commit 이 되기전에 eslint같은것을 통과하지 못했으면 commit을 방지하게 되는 git hook을 좀 더 쉽게 작성할 수 있게 도와주는 역할이다.

console.log()
(function(){})()

app.js

module.exports = {
  rules: {
    "no-unexpected-multiline": "error",
  },
};

eslint.config.js

  "lint-staged": {
    "*.js": "eslint --fix"
  }

package.json에서 lint-staged 선언

echo "bullshit"
npx lint-staged

.husky/pre-commit 

$ git commit --allow-empty -m "message"
bullshit
✔ Preparing lint-staged...
⚠ Running tasks for staged files...
  ❯ package.json — 1 file
    ❯ *.js — 1 file
      ✖ eslint --fix [FAILED]
↓ Skipped because of errors from tasks.
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...

✖ eslint --fix:

/home/tony/workspace/frontend/sample/src/app.js
  2:1  error  Unexpected newline between function and ( of function call  no-unexpected-multiline

✖ 1 problem (1 error, 0 warnings)

husky - pre-commit script failed (code 1)

git commit을 실행하면 stage 된 file들을 대상으로 eslint를 수행하게 된다. 

728x90

'FrontEnd > 프론트엔드 개발환경의 이해와 실습 (webpack, babel, esli' 카테고리의 다른 글

Webpack 심화  (4) 2024.09.04
NPM , Webpack  (0) 2024.08.26