#Webpack, Babel
왜 변환, 컴파일을 해주는가?
1) JavaScript 문법은 꾸준히 진화, 업데이트가 되어왔다.
JavaScript문법이 업데이트되면, 런타임이 따라와줘야하기 때문.
Ex)
of라는 예약어가 생긴다면? 실행하기 위해서는 브라우저(런타임)도 프로그램으로 이루어진 것이기 때문에 코드를 변경해줘야함.
ES6 -> ES5
Let const -> var
2) JavaScript를 실행하는 방법이 여러가지이기 때문.
* 브라우저
- window : 브라우저 전역 객체
* NodeJS
- Global : 노드 전역 객체
- require
- module/ exports
JavaScript는 import와 require, 모듈을 불러오는 방법은 두가지가 존재한다.
각각 런타임에 따라 사용 유무가 다른데, 왜 2개냐.. 불편할 수 있음.
-> babel을 통해서 require로 썼다가 NodeJS에서 사용할때는 그대로, 브라우저에서 실행할때는 require로 변환하여 실행할 수 있도록 한다.
####예제1)
1. 기본 구성 설치하기
Babel은 기본적으로 JS로 구성되어있고, npm을 통해 쉽게 설치가 가능하다.
$ npm init -y
$ npm install @babel/core @babel/cli @babel/preset-env
npm과 npx 차이
npm, npx 둘다 다운과 실행을 할 수 있지만
npm은 다운로드 후 실행까지 직접 경로를 설정해야한다.
npx는 node_modules에 있는 모듈들을 실행하기위해 나왔따. 실행할 패키지가 존재하지 않다면 다운로드 후 실행해준다.
babel 환경 구성을 위해선
.babelrc라는 파일이 필요함. ( 생성 )
rc Run Commands Run Control
커맨드 명령어를 썼을 때 옵션 내용을 파일로 따로 빼서 관리하는 것.
const fn = (message) => {
const arr = [1,2,3,4,5]
const arr2 = [6,7,8,9,10]
const arr3 = [...arr, ...arr2]
console.log(...arr3, message)
}
fn("hello world!")
npx babel [바꿀파일] --out-file [보낼파일]
npx babel example.js --out-file dist/example.js
결과
"use strict";
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
var fn = function fn(message) {
var _console;
var arr = [1, 2, 3, 4, 5];
var arr2 = [6, 7, 8, 9, 10];
var arr3 = [].concat(arr, arr2);
(_console = console).log.apply(_console, _toConsumableArray(arr3).concat([message]));
};
fn("hello world!");
babel에 플러그와 프리셋이 있는데
플러그인들이 모여서 프리셋이 된다.
ex) Arrow함수를 function으로 바꿔는 플러그인이 있고, 그 외에 다른 여러개 플러그인들을 묶어서 프리셋이 된다.
####예제2)
1. 관련 패키지 설치
$ npm install @babel/core @babel/cli @babel/plugin-transform-modules-commonjs
{
"plugins":["@babel/plugin-transform-modules-commonjs"]
}
import express from'express'
const app = express()
app.listen(3000,()=>{
console.log('Server Start')
})
$ npx babel server
결과
"use strict";
var _express = _interopRequireDefault(require("express"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const app = (0, _express.default)();
app.listen(3000, () => {
console.log('Server Start');
});
JavaScript에서는 "<",">" 문법은 존재하지 않음.
$ npm init
$ npm install @babel/core @babel/cli @babel/preset-react
{
"presets":["@babel/preset-react"]
}
babel은 파일을 모듈화해서 가져올때는 문제가 생긴다. 이때 webpack을 사용한다
3. 예제 코드
```js
const react = require('react')
const reactDOM = require('react-dom')
class App{
render(){
return (
<div>
Hello World!
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'))
root.render(<App/>)
const react = require('react');
const reactDOM = require('react-dom');
class App {
render() {
return /*#__PURE__*/React.createElement("div", null, "Hello World!");
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render( /*#__PURE__*/React.createElement(App, null));
babel은 코드 자체를 변환할때, 단일 파일.
webpack은 모듈인 파일들을 하나에 다 불러 모아가지고 처리한다.
Webpack 모듈 번들러
웹 어플리케이션을 구성하는 다양한 자원들을 하나의 파일로 번들링하고, 이를 사용해서 웹 페이지 로딩하는데
필요한 최소한의 파일을 제공함.
이를 통해서 로딩 속도를 개선할 수 있다.
모듈
번들러
<script src='./1.js'></script>
<script src='./2.js'></script>
<script src='./3.js'></script>
<script src='./4.js'></script>
<script src='./5.js'></script>
위 코드를 webpack으로 번들링을 한다면
<script src='./bundle.js'></script>
위와 같은 형식으로 자원을 줄일 수 있다.
babel 같은 경우
presets
plugins
entry -> plugins -> output
$ npm install webpack webpack-cli
프로젝트 구성
src 안에 있는 파일을 번들링 진행하려고 한다.
webpack 설정 파일
const path = require('path')
module.exports = {
entry:'./src/index.js',
output:{
filename:'bundle.js',
path: path.join(__dirname, "dist"),
},
}
const home = require('./pages/home.js')
console.log(home.name)
pages/home.js
module.exports = {
name="web7722",
}
$ npx webpack --config webpack.config.js // config값을 수정했을 시.
$ npx webpack
css도 javascript로 bundeling이 가능하다
Webpack 설정파일에 있는 Loaders 설정 내용은
다양한 유형의 파일을 모듈화 할 수 있따.
아마 우리가 자주사용하는 것들은
CSS, Image일 확률이 높다.
CSS 모듈을 번들링 해보도록 하겠습니다.
npm init -y
npm install webpack webpack-cli css-loader style-loader
src/index.js
import "./index.css"
console.log('hello world')
src/index.css
* {
margin:0;
padding:0;
background:red;
}
const path = require('path')
module.exports = {
entry:'./src/index.js',
module:{
rules:[ // {}하나당 1개의 loader
{
test:/\.css$/,
use:['style-loader', 'css-loader']
}
]
},
output: {
filename:'bundle.js',
path: path.join(__dirname, "dist")
}
}
Webpack의 결과는
(()=>{"use strict";var e,t,n,r,o,a,i,c,s,u,l,p,d,f,v={424:(e,t,n)=>{n.d(t,{Z:()=>c});var r=n(81),o=n.n(r),a=n(645),i=n.n(a)()(o());i.push([e.id,"* {\n margin:0;\n padding:0;\n background:red;\n}",""]);const c=i},645:e=>{e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var n="",r=void 0!==t[5];return t[4]&&(n+="@supports (".concat(t[4],") {")),t[2]&&(n+="@media ".concat(t[2]," {")),r&&(n+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),n+=e(t),r&&(n+="}"),t[2]&&(n+="}"),t[4]&&(n+="}"),n})).join("")},t.i=function(e,n,r,o,a){"string"==typeof e&&(e=[[null,e,void 0]]);var i={};if(r)for(var c=0;c<this.length;c++){var s=this[c][0];null!=s&&(i[s]=!0)}for(var u=0;u<e.length;u++){var l=[].concat(e[u]);r&&i[l[0]]||(void 0!==a&&(void 0===l[5]||(l[1]="@layer".concat(l[5].length>0?" ".concat(l[5]):""," {").concat(l[1],"}")),l[5]=a),n&&(l[2]?(l[1]="@media ".concat(l[2]," {").concat(l[1],"}"),l[2]=n):l[2]=n),o&&(l[4]?(l[1]="@supports (".concat(l[4],") {").concat(l[1],"}"),l[4]=o):l[4]="".concat(o)),t.push(l))}},t}},81:e=>{e.exports=function(e){return e[1]}},379:e=>{var t=[];function n(e){for(var n=-1,r=0;r<t.length;r++)if(t[r].identifier===e){n=r;break}return n}function r(e,r){for(var a={},i=[],c=0;c<e.length;c++){var s=e[c],u=r.base?s[0]+r.base:s[0],l=a[u]||0,p="".concat(u," ").concat(l);a[u]=l+1;var d=n(p),f={css:s[1],media:s[2],sourceMap:s[3],supports:s[4],layer:s[5]};if(-1!==d)t[d].references++,t[d].updater(f);else{var v=o(f,r);r.byIndex=c,t.splice(c,0,{identifier:p,updater:v,references:1})}i.push(p)}return i}function o(e,t){var n=t.domAPI(t);return n.update(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap&&t.supports===e.supports&&t.layer===e.layer)return;n.update(e=t)}else n.remove()}}e.exports=function(e,o){var a=r(e=e||[],o=o||{});return function(e){e=e||[];for(var i=0;i<a.length;i++){var c=n(a[i]);t[c].references--}for(var s=r(e,o),u=0;u<a.length;u++){var l=n(a[u]);0===t[l].references&&(t[l].updater(),t.splice(l,1))}a=s}}},569:e=>{var t={};e.exports=function(e,n){var r=function(e){if(void 0===t[e]){var n=document.querySelector(e);if(window.HTMLIFrameElement&&n instanceof window.HTMLIFrameElement)try{n=n.contentDocument.head}catch(e){n=null}t[e]=n}return t[e]}(e);if(!r)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");r.appendChild(n)}},216:e=>{e.exports=function(e){var t=document.createElement("style");return e.setAttributes(t,e.attributes),e.insert(t,e.options),t}},565:(e,t,n)=>{e.exports=function(e){var t=n.nc;t&&e.setAttribute("nonce",t)}},795:e=>{e.exports=function(e){var t=e.insertStyleElement(e);return{update:function(n){!function(e,t,n){var r="";n.supports&&(r+="@supports (".concat(n.supports,") {")),n.media&&(r+="@media ".concat(n.media," {"));var o=void 0!==n.layer;o&&(r+="@layer".concat(n.layer.length>0?" ".concat(n.layer):""," {")),r+=n.css,o&&(r+="}"),n.media&&(r+="}"),n.supports&&(r+="}");var a=n.sourceMap;a&&"undefined"!=typeof btoa&&(r+="\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(a))))," */")),t.styleTagTransform(r,e,t.options)}(t,e,n)},remove:function(){!function(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e)}(t)}}}},589:e=>{e.exports=function(e,t){if(t.styleSheet)t.styleSheet.cssText=e;else{for(;t.firstChild;)t.removeChild(t.firstChild);t.appendChild(document.createTextNode(e))}}}},m={};function h(e){var t=m[e];if(void 0!==t)return t.exports;var n=m[e]={id:e,exports:{}};return v[e](n,n.exports,h),n.exports}h.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return h.d(t,{a:t}),t},h.d=(e,t)=>{for(var n in t)h.o(t,n)&&!h.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},h.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),h.nc=void 0,e=h(379),t=h.n(e),n=h(795),r=h.n(n),o=h(569),a=h.n(o),i=h(565),c=h.n(i),s=h(216),u=h.n(s),l=h(589),p=h.n(l),d=h(424),(f={}).styleTagTransform=p(),f.setAttributes=c(),f.insert=a().bind(null,"head"),f.domAPI=r(),f.insertStyleElement=u(),t()(d.Z,f),d.Z&&d.Z.locals&&d.Z.locals,console.log("hello world")})();
위와 같이 그냥 보기에는 알아보기가 힘들고 많은 코드들로 구성되어있다.
HTML template 만드는 것을 해보자.
$ npm init -y
$ npm install webpack webpack-cli html-webpack-plugin
src/index.js
webpack.config.js
실행
$ npx webpack
React 프로젝트 디렉토리를 구성
아주 간단한 내용. 실제로 사용하기에는 부족할 수 있음ㅇㅇ.
npm install react react-dom
babel
.babelrc
{
"presets" :["@babel/preset-env","@babel/preset-react"]
}
관련패키지 설치
npm install @babel/preset-env @babel/preset-react
npm install @babel/core babel-loader