크로스 브라우징
브라우져 마다 사용하는 언어가 달라서 프론트엔드 코드는 일관적이지 못할 때가 많다.
바벨은 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를 수행하게 된다.
'FrontEnd > 프론트엔드 개발환경의 이해와 실습 (webpack, babel, esli' 카테고리의 다른 글
Webpack 심화 (4) | 2024.09.04 |
---|---|
NPM , Webpack (0) | 2024.08.26 |