안녕하세요


React 시작 전 준비 단계 3번째 입니다.  JSX  , 그리고 ReactDOM.render 및 제가 사용하면서 궁금했던 것들에 대해


그리고 이제까지 1,2단계에서 봤던 것들 정리 차원입니다.



리액트 시작 전 리스트 체크 


1. 준비물 챙겼는지?


IDE - vscode (관련 플러그인, ESLint, Guides)


Node.js 설치 

CRA(create-react-app) 설치 


create-react-app 설치 후 

> 1. create-react-app basic-react

> 2. cd basic-react 

> 3. npm start

> 짜잔. Hello React


github(깃허브)


JS,HTML5,CSS3

> ES6 


이외 사용 도구들 (시작하고 알아보기)

> webpack,babel ... 

2. 리액트는 왜하는건지?

노마드 코더의 말을 빌리자면 매우 멋진 UI 라이브러리이며 그냥 js만 잘하면 다 할수 있다. 모든 화면들을

컴포넌트화 하여서 쪼개서 사용이 가능하다 vue. angular는 그에 따른 문법을 배워야 하지만 리액트 는 그렇지 않다.

또한 리액트는 View만을 위한 라이브러리 이기 때문에 다른 프레임워크와 같이 사용이 가능 하다.



3. 리액트 (create-react-app)


3-1 모든 컴포넌트는 Component를 상속 받아야 한다.

class tempComponent extends Component

      3-2 모든 컴포넌트는 render () 함수가 있다.

render() {}

3-3 import React, { Component,Fragment } from 'react'; 는 필수

상속도 받고 render 부모로 Fragmnet 사용   <Fragment>


4. JSX

리액트에서 사용 되는 문법으로 마치 HTML 을 쓰는 것과 같지만 다른점이 하나있다.

기존 HTML에서는  여러 줄 입력시

'<button></button>'+

'<input></input>' 식을 거치지만 JSX에서는


<button></button>

<input></input> 와 같은 직접 HTML을 쓰는것 처럼 보이는 형태를 띄기 때문이다.


4-1    주석

주석은 단순하게 /* */ 가 아니라 { /* */ } 와 같이 작성한다.


4-2   위젯 생성

- 단순 버튼 생성

render() {

return(

<Fragment>

<button type="button" value="test"/>

</Fragment>

);

}

- js를 통한 생성 

const btnArr=["첫번째","두번째","세번째"];
const listinputTag = btnArr.map(item =>
<input type="button" style={btnStyle} value={item+1} key={item+1}></input>
);

render(){

return(

<Fragment>

{listinputTag}

</Fragment>

);

}

- CSS 속성 입히기 (외부 스타일)

App.js


<div className="react-CSS">
여기는 div입니다.
</div>

App.css


.react-CSS{
width:550px;
height:200px;
color:white;
background-color:black;

}


- CSS 속성 입히기 (인라인 스타일)

App.js


const btnStyle = {
backgroundColor:"#fafafa",
border : '1px solid #d3dbdf',
padding: '8px 13px 9px 15px',
margin:'0px 2px 0px 0px',
whiteSpace:'nowrap',
fontWeight:'600',
cursor:'pointer',
height: '50px',
width:'100px',
borderRadius:'3px',
WebkitTransition:'all',
MozTransition:'all',
msTransition:'all'
};


<button style={btnStyle} type="button" value="test"/>



index.js  (ReactDOM.render)


ReactDOM.render : 리액트 돔 말그대로 React코드를 DOM (Document Object Model) 에 붙이는 역할을 합니다.


다른 의미로 IOS나 AOS같은 모바일에 붙이는 경우는 ReactNative.render(?) 가 있었던것처럼


화면구성은 React + Component 로 구성하고 붙이는 지점은 브라우저냐 모바일이냐 에 따라서


ReactDOM 이냐 ReactNative로 갈리는 것 같습니다. 완전한 분리 좋네요


import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();



ReactDOM.render(만든컴포넌트, document.getElementById('root'))로 되어있는데


root는 어디있을까 했더니 public 폴더에 index.html 에 있는 <div id="root"> 에 붙는 것으로 보입니다.




결과 App.js






import React, { Component, Fragment} from 'react';

import './App.css';
// [React] 시작 전 준비 3단계( JSX && 스타일)
class App extends Component {

  render() {
    const isButton = true;
    const btnArr=["첫번째","두번째","세번째"];
    const btnStyle = {
        backgroundColor:"#fafafa",
        border : '1px solid #d3dbdf',
        padding: '8px 13px 9px 15px',
        margin:'0px 2px 0px 0px',
        whiteSpace:'nowrap',
        fontWeight:'600',
        cursor:'pointer',
        height: '50px',
        width:'100px',
        borderRadius:'3px',
        WebkitTransition:'all',
        MozTransition:'all',
        msTransition:'all'
    };
    const listinputTag =  btnArr.map(item =>
      <input type="button" style={btnStyle} value={item+1} key={item+1}></input>
    );
    const listbuttonTag = btnArr.map(item=>
        <button type="button" style={btnStyle} key={item+1} >  {item+1} </button>
    );
    // [...new Array(10)].map(x => 0);
    const btnCnt = 3;
    const countBtn = Array(btnCnt).fill(null).map( (i,idx) =>{
         let btnKey = "Count_"+idx;
         return <button style={btnStyle} type="button" key={btnKey}>Cnt_{idx}</button>
      }
    );
    return (
      <Fragment>
        <h2>
            { isButton ? '버튼이 있다': '버튼이없다'}
        </h2>
        <h2>
            { isButton && '버튼이 있다'}
        </h2>
            {/* 버튼이 있기 때문에 해당 버튼을 생성 btnCnt만큼 */}
            <button style={btnStyle} type="button" value="test"/>
        <h3> 'map 을 통하여 버튼 렌더링 input 태그 btnArr=[1,2,3];'</h3>
         {listinputTag}
        <h3> 'map 을 통하여 버튼 렌더링 button 태그 btnArr=[1,2,3];'</h3>
        {listbuttonTag}
        <h3> count 변수를 통하여 버튼 렌더링 button 태그  현재 cnt : {btnCnt}</h3>

        {countBtn}
        <div className="react-CSS">
                여기는 div입니다.
        </div>
      </Fragment>
    );
  }
}

export default App;

안녕하세요 언제까지 리액트 시작전인지 모르겠지만...


매번 느끼는 건데 기본기가 탄탄하지않으면 어느 순간 막히는 구간이 다시 오더라구요


하나하나 따져보면서 시작을 하려고해요


저번엔 class App extends Component 였었죠 기본앱을 만들수 있는 


Component 를 상속받기 위해서 import {Component} from 'react' 도 배웠고 이제 index.js 에서 


만들어진 App 을 어떻게 렌더링을 시키는지 확인하고자 index.js 을 보았습니다.


필요없는것들을 지우고 렌더링 에 초점을 맞추기 위해서 



코드를 수정하고 리액트 컴포넌트 쪼개기는 아직 부족한 상태라  기존의 샘플로 작성중인 코드들 을 옮기기 위해 여러 줄 태그를 써보았습니다만


render() { return 에서 사용되는 jsx 문법에는 덮는 부모가 꼭 있어야 한다고 에러가 납니다.


해당 이유는 virtual DOM 에서 컴포넌트 변화를 감지 하기 위해 컴포넌트 내부는 DOM 트리구조 하나로 되어야 한다는 규칙이기 때문이라고 하네요 


그래서 예전에는 해당 을 고치기 위해서


<div >

<tag>

<taG>

</div>


로 썻다고 하는데 


요즘{ React v16버전이후 부터는) Fragment 컴포넌트가 도입되어서 div로 감싸지 않고 Fragment를 사용한다고 합니다.



무슨 차이인지 궁금해서 한번 테스트 해보았습니다.


div로 감쌋을때


return (
<div className="onlyDiv">
<h1>리액트 한줄</h1>
<h2>리액트 두줄</h2>
</div>
);


렌더링 결과는


이와 같이 렌더링되네요  (create-react-app) 에서 App.js만 수정한거기 때문에 다른 변화들은 잘 모르지만 그 기준으로 봐주시길 바랍니다.


div가 아닌 Fragment 로 감쌌을 때

import React, { Component } from 'react';

class App extends Component {
render() {
return (
<Fragment>
<h1>리액트 한줄</h1>
<h2>리액트 두줄</h2>
</Fragment>
);
}
}

export default App;

앗.. 그냥 그대로 수정했더니 모른다고 에러가 나오네요 ;; ㅜ 


'Fragment' is not defined react/jsx-no-undef


import 에 비구조화 할당으로 Component가 아닌 Fragment도 가져와야 되는 걸 몰랐네요


import React, { Component ,Fragment } from 'react';


실행 결과 -

Fragment 로 감싸는 경우는 뭔가 렌더링 후에는 없던것 처럼 나오네요


위에 있던 불필요한 div의 렌더링을 없앨수 있어서 확실히 좋은것 같습니다.


Fragment를 생활화!!



그리고 JSX에서는


기존에 있던 JSP 템플릿 <%  여기에 자바 코드를 넣었었죠 


과같이 자바스크립트 코드를 넣을수도 있다고 하네요


render() {
const AppTitle = "앱 타이틀입니다";
return (
<Fragment>
<h1>리액트 한줄</h1>
<h2>리액트 두줄 {AppTitle}</h2>
</Fragment>
);
}


렌더를 이와같이 수정시에는 


{AppTitle} 부분이 동적으로 들어갈수 있네요 ㅜㅜ 이런거 너무좋아합니다.


여기 까지 해보니 JSX 렌더링에 대해서 한번 더 작성해야 할것 같아서  다시 한번 작성 하겠습니다.


JSX좋은것 같습니다.

안녕하세요 저번 에는 


React를 시작하기전에 create-react-app basic-react를 통해서 만들어진 basic-react 폴더에서 보면


기본적인 리액트 화면과 같이 리액트가 어떤식으로 이루어져있는지 코드 확인이 됩니다. 



import 구문이 있는데


저는 import 하면 자바에서 패키지 가져올떄 import java.lang.nullException~~.. 뭐 이런식으로


가져온것만 기억이 나서 js에도 있는것이 매우 신기 합니다.


프론트에서는 <script 태그를 통해서 가져오는데 그렇지 않은 경우에 대해서는 잘 몰랐었습니다.


import React, { Component } from 'react';


->

 

const React = require('react');

const Component = React.Component; 


와 같다고 볼수 있습니다.


위에서 보면  import React from 'react 랑 const React = require('react'); 는 알겠는데


import {Component} from 'react'는 잘모르겠네요


이부분에 대해서 알아 보니


비 구조화 할당 이라고 ES6 스펙에 있는 기능인데


비 구조화 할당에 대해서는 나중에 다시 한번 포스팅 하도록 하고


해당 비 구조화 할당 중 신기 한것이 있어 하나 가져와 봤습니다.



function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

반환 값 무시인데요  return 으로 1,2,3 배열을 반환 했지만 


반환 을 위와같이 비 구조화 할당을 진행시 중간 반환값인 2 를 무시 할수 있다고 하네요 ㅋㅋ 매우 신기 ;


react라는 것을 임포트하여서 가져오는데 그중 {Component}로 받게 되면


react.Component로 받아서 할당 한다고 보면되겠네요 



정리를 하자면 


리액트 코드의 첫줄은 


import React, { Component } from 'react';는


해석하자면


react를 가져와서 React에 넣었고 Component는 비구조화 할당으로 react안에 있는 react.Component를 가져와서 할당했다고 봐도 되겠습니다.


그리고 리액트를 시작하기전에  번들링 도구에 대한 지식이 있어야 합니다. 


번들링 도구는 가장 유명한 웹팩 (webpack)을 알아야 할 것 같고 


여러 가지 파일들을 불러오는 것은 webpack 에서는 loader가 이 역할을 수행해냅니다.


css-loader는 CSS 파일을 


file-loader는 웹 폰트, 이미지, 미디어 파일 등 


babel-loader는  js 파일들을 불러오면서 ES6 -> ES5로 바꿔주는 역할


원래는 이 로더들을 통해서 설정해야 하는데  create-react-app 에서 이 작업들을 전부 로컬에서 해주는 것 같네요


(로컬 테스트용으로) 이후에는 직접 다 해야 하는것으로 보입니다.



import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';


이 구분에 대한 해석이 어느정도 끝난 것 같습니다.


react를 가져와서 React와 Component 에 할당 했고 


svg와 css의 경우는 css-loaderfile-loader등 로더로 설정을 해야 할것으로 보이네요


그다음


class App extends Component {


이 부분입니다.


js에서도 클래스를 만들었고 상속으로 Component를 받았습니다.


위의 비 구조화 할당으로 Component를 가져왔으니 가능하겠죠?


리액트의 컴포넌트를 만들어지는 기본방법으로 보입니다.


class frontButton extends Component로 하면 화면 버튼으로 제가 만들어서 쓸수 있을 것 같네요


벌써부터 재미..


그다음 render함수를 보겠습니다.


import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit 오오미 <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}

export default App;


바로 render() { 

// do thing;;

}}으로 되어있는데


내부함수에 function render(){}    도 아니고


var render = function() 도 아니네요;; 이게 뭘까 했습니다.


이 점도 찾아 보니 ES6에  생긴 


간결 메서드

Concise Method()


라고 하네요


ES 5에서


var beforeObj = {
        name : "beforeObj",

  objShow : function(){

   }

 };


였다면 ES6에서는


var beforeObj = {

name :"newObj",

objShow(){


}

}


와같이 사용이 가능하다는 점입니다. 그렇기 때문에 render 도 사실은


var render = function(){} 또는 render : function(){} 이어야 할것 같지만 ES6문법 에 의해서


render(){


}가 될수 있습니다. 




그리고 render() 함수에 대해서 보자면 리액트에서는 render라는 함수를 통해서 UI 렌더링 기능을 진행한다고 합니다


렌더링은 JSX라는 문법을 통해서 html 과 매우 유사한 형태로 반환되지만 실제적으로는 그렇진 않습니다.


' ' + ' 형식으로 추가하는것도 아니고 그냥 생 html처럼 보이거든요


js문법도 물론 아니고  리액트 문법이라 보는것이 좀더 맞겠네요 렌더링 시( render 함수 호출 시 ) 에는


render 에 있는 JSX들을 계속 반복하며서 HTML을 만들기 위한 오브젝트를 생성합니다.


오브젝트가 전부 생성되면 해당 정보를 통하여 HTML 을 마크업 그리고 실제 DOM 에 붙여서 화면에 나타나게 합니다.


render ()호출 - HTML를 그리기위한 정보 객체 생성 (내부에 다른 Component가 있을 경우다시 돌면서 생성)

-> 해당 정보로 HTML 맠업 생성 -> 실제 DOM 에 붙임













1. 리액트를 다루는 기술  (책) - 김민준 저자


2. VSCode(에디터)

     -> 관련 플러그인

> ESLint // 문법 정리 *

> Relative Path // 상대 경로 작성 도구 

> Guides   // 들여쓰기 가이드 라인 

> Reactjs code snippets(Karypidis) // 리액트 관련 스니펫 모음 제작자 Charalampos Karypidis *

> React-beautify // 리액트 코드 정리 




3. Node.js with NPM (노드는 10버전)

> create-react-app 설치   -g 로 


4. git 





* 코드 스니펫이 뭔가 해서 찾아봤습니다.


js에서 


arr에는 forEach 로 가져올수 있는 것처럼


arr.forEach(function(item,index,arr){


}); 를 입력해야되는데


arr.f 엔터 치면 저 위에부분들이 조각처럼 가지고있다가 한번에 나오는 기능을 말합니다.





global 옵션으로 create-react-app 설치 


npm i -g create-react-app

터미널에 create-react-app basic-react


** basicReact 라고 했더니 



Could not create a project called  ''  because of npm naming restrictions 

** name can no longer contain capital letters

네;; 대문자를 사용 못한답니다.


그래서 소문자로 만 하셔야 됩니다.


basic-react로 변경 



입력 후 


cd basic-react


npm start 시


리액트 화면 확인



신나네요 리액트 할 생각에 




안녕하세요 노드에서 파일 작업을 하여야 하는 경우가 생겼는데 예전에 한번 썻었지만 기억도 나지않고


예전에 사용했던 경우는 그냥 단순 파일 쓰는 작업만 해서 이번에는 폴더가 있는지 체크해서 없으면


해당 폴더를 만든후에 -> 폴더를 만들고 해당 폴더 안에 파일을 작성하는 것을 포스팅 하려고합니다.


노드버전은 LTS버전인 10.6 기준입니다.


우선 기본적으로 알아야 할 것이 있습니다.


__dirname;


개인변수명 작성시에 preFix로 __로 지양 해야 겠네요 

File System 에 대한 내용은 전부 docs 에 너무 잘되어있기 때문에 다른점은 참고 하셔도 될것 같습니다.


/* Node.js docs 10.6.0 Documentation - File System */

https://nodejs.org/dist/latest-v10.x/docs/api/fs.html



const fs = require('fs');

const _path = __dirname;

console.log(_path);


결과는 현재 폴더 트리의 위치가 나타나게 됩니다. __dirname을 알고 있어야 어느 폴더로 이동하여서


노드가 실행 되어도 문제가 되지 않을것 같습니다.




const fs = require('fs');

const currPath = __dirname+"/_test_/";
let version =currPath+'Fixed/';


let arr = ['linearlayout','button','datepicker'];

let contents_ =['content','tea','test','b','e','t','set','s','hg'];

let writeFile = (filename,contents)=> {
            
    fs.open(filename,'w',(err,fd)=>{
            if(err) throw err;
            console.log('file Open - :',filename.split('/')[filename.split('/').length-1]);
           fs.writeFile(fd,contents.join(','),(err)=>{
                        if(err) throw err;
                    console.log(filename + ' - write\n');
                });
    });
};
try{

       if(!fs.existsSync(version)){
                console.log(version.split('/')[version.split('/').length-1]+" 폴더가 없습니다.생성합니다.");
              fs.mkdir(version,0700,function(err){
                        if(err) throw err;
                    for(let i=0;i<3;i++){
                            writeFile(version+arr[i]+'.txt',contents_);
                    }
            });
        }
       else{
                console.log(version.split('/')[version.split('/').length-2]+" 폴더가 존재합니다.");
                    for(let i=0;i<3;i++){
                            writeFile(version+arr[i]+'.txt',contents_);
                    }
        }

}
catch(err){console.error(err);}

finally{
        console.log('File System Working Clean');
}
       






공간 데이터 (Spatial Data) : 지구상에 있는 집, 도로 등을 점이나 선 등의 형태로 나타낸 위치 데이터를 말함


1차원 데이터를 위해 만든 B-Tree 인덱싱 방법으로 2차원 데이터를 저장하면 속도가 떨어지기 때문에 


위도,경도와 같은 공간 데이터 , 즉 2차원 데이터의 좌표 값을 데이터베이스에 저장할 때는 공간 인덱싱 방법 사용


공간 인덱싱은 데이터 베이스에서 2차원 공간 데이터를 빠르게 조회하기 위해 만든 2차원 인덱싱 방법으로


2차원 인덱싱 방법에는 R-Tree, R*Tree 등이 있음



Node.js를 알아가기 전에 동기 방식 과 비동기 방식 에 대한 정~~~말 간단한 예시를 보고 들어 가는게 좋을것 같아


가져왔습니다.



동기 입출력 (블로킹, Blocking IO) 방식 


파일 기능(읽기요청) -> 파일준비 -> 파일 처리 -> 데이터 처리 -> 다른작업 진행

var contents = file.read('a.txt');

******************대기*****************

doShow(contents);

var result = doAdd(10,10);



비동기 입출력(논블록깅 입출력, Non-Blocking IO) 방식

파일 기능(읽기요청) -> 파일준비 > 파일 처리 > 데이터 처리 

-> 다른작업 진행

file.read('a.txt',function(contents){

doShow(contents);

}

var result = doAdd(10,10);


|       Node Program                 |

|JavaScript C/C++                           |

| 노드 표준 라이브러리 |

| Node Standard library |

| 노드바인딩 |

| (Socket,http,etc) |

|스레드 풀 이벤트 루프  DNS crypto |

|libeio  libev    |

| V8 엔진 |

프로그램 실행시 V8엔진 위에서 실행됩니다. V8엔진 에서는 필요한 기능을 병렬로 실행하는 '스레드 풀'과

이벤트를 받아 처리하는 '이벤트 루프' 등의 기본 기능이 있으며 그 위에 네트워킹 기능을 담당하는 소켓(Socket)

,http 라이브러리 들이 있고 그 위에 표준 라이브러리가 구현되어있습니다.


결론 

특정 예시 [ 깍돌이의 오늘 저녁은 짜파게티위에 계란 후라이를 올려 먹을 생각입니다. ]

1. 짜파게티를 끓여야 함. [ 냄비에 물 올리고 끓으면 면넣고 섞어서 물 버리고 스프 로 섞기 ]

2. 계란후라이도 해야 함. [ 후라이팬에 불 달구고 기름 넣고 날계란 까서 뒤집어 주기 ]


이 두개의 작업이 있다고 하였을 때


동기 방식 


 후라이를 하든지 짜파게티를 끓이던지 하나를 정해야 합니다. 전자의 작업을 먼저 한다고 하였을 때 


1. 후라이팬을 꺼내 불 온도를 올립니다.

2. 온도가 올랐을때 기름을 붓고 날계란을 올립니다.

3. 익으면 뒤집어 줍니다.

[후라이 완료] - 예상 시간 60초


1. 냄비를 꺼내서 물을 넣고 끓입니다.

2. 끓었을때 짜파게티 사리를 넣습니다.

3. 익었을 경우 면을 섞고 물을 버립니다.

4. 스프를 넣고 섞습니다.

[짜파게티 완료] 예상 시간 150초


짜파게티 위에 계란을 올려 먹습니다.


-> 결과적으로 최소한 210초가 걸리게 되는 현상이 발생합니다.  하나씩 하나씩 스텝을 진행하여야 되기 때문입니다.


말로만 이렇게 하긴 했지만 프로그램적으로 봤을때는 짜파게티가 되기전 계란 후라이 작업에서는 펜딩되어있다고 보실


수 있기 때문에 매우 비효율적으로 보입니다. 


그러면 비동기가 짱짱일거 같지만 비동기가 매우 편리하고 좋지만 처리해야 할 작업도 많고


동기로 처리해야 하는경우가 있긴 합니다. 




비동기 방식  Node.js 의 논블로킹방식

(비동기는 실행순서가 늦는점을 이야기한거고 아래와 같은 예시는 논블로킹방식이 맞습니다.)


1. 후라이를 시작함과 동시에 냄비도 올리고 짜파게티도 시작합니다.

2. [후라이 완료] 60초 

3. [짜파게티 완료] 150초


짜파게티 위에 계란을 올려 먹습니다.


-> 결과적으로 동시에 따로 시작했고 후라이가 먼저 되었기 때문에 그걸 알려주게되며 전체 시간은 150초가 걸렸습니다.


위의 동기 방식을 더 쉽게 이야기하면 가스렌지가 1개 밖에 없어서 순차적으로 음식을만들어야 되는 점 


비동기 방식은 가스렌지가 2개라서 같이 진행 할수 있습니다.


어느정도 이해가 된 상태에서 비동기에 대한 포스팅은 다시 한번 자세하게 하겠습니다.








기존에 작성은 한적 있지만

 

새 서버로 옮기는 바람에 Node를 다시 설치 하여야 할 일이 생겼습니다.


노드 프로젝트를 통채로 가져왔기 때문에 


package.json 이랑 package-lock.json 은 그대로 있는 상태에서


Node를 재설치 후에 동작을 확인해보겠습니다.


우선 node.js 공식 홈페이지 접속 


https://nodejs.org/en/



메인 메뉴에서  DOWNLOADS 후  하단 


을 선택 합니다. 


저는 CentOS7 이기 때문에 엔터프라이즈 리눅스 메뉴를 선택


그리고 가이드대로 설치 합니다.


On RHEL, CentOS or Fedora, for Node.js v8 LTS:

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -

Alternatively for Node.js 10:

curl --silent --location https://rpm.nodesource.com/setup_10.x | sudo bash -

Then install:

sudo yum -y install nodejs


현재 LTS버전인 8 (stable)  은 위에 LTS버전인 current 버전은 아래의 setup_10.x로 설치합니다.


설치 후  아래의 명령 yum -y install nodejs로 node를 설치합니다. node -v 로 버전 확인



설치가 잘됐습니다.


npm init으로 package.json 에 맞게 세팅 해주고


nodemon pm2같은 모듈은 제가 -g로 설정하여서 pakcage.json 에 없다보니


다시 재설치를 하였습니다.







NPM(Node Package Manager) 에 대해서는 이제 어떤건지 대략적으로 알수 있을 것 같습니다.


이제부터는 NPM 에서 사용하였던 모듈들에 대해서 리스트를 작성 하도록 할려고 합니다.


이번에는 2번째 모듈인  cors (Cross Origin Resource Sharing)  모듈에 대해서 간단하게 보려고 합니다.


왜 두번째로 cors를 하였냐면 가장 맨 처음에 부딪치는 이슈이기 때문입니다. 


122.118.155.163:3000 으로 node서버를 진행시


122.118.155.163 에서 node 실행 인데 3000 port로 Listen 중 이며



122.118.155.163:8888 에서 웹서버가 디플로이 (Deploy) 된 상태 에서 클라이언트가 


122.118.155.163 으로 ajax 요청을 보내게되면 크로스 도메인 이슈가 나타나게 된다.


웹서버(웹프로젝트)는 8888에 떠있지만 실제로 요청을 받는 API 서버는 3000 포트에서 받고 있기 때문이다. 


해당 크로스 도메인에 대해서는 따로 찾아 보시길 바라고 해당 의 경우에는 


3000으로 Listen 중인 이 서버가 같은 IP를 사용하고 있지라도 CORS 문제로 인해서 restapi 를 사용할수가 없게 된다. - 보안 상의 이유로 안된다고 하는데 해당 사항에 대해서는 찾아서 이 글에 수정 하도록 하겠습니다.



XMLHttpRequest cannot load http://xx.xx.xx.xx/xxx. Request header field Content-Type is not allowed by Access-Control-Allow-Headers. 

출처: http://blog.opid.kr/430 [opid's document]

해당 에러 메시지 가 나타났을 경우에 CORS 이슈가 나타났다고 할수 있습니다.


** IE에서 간혹 cors를 설정 하였는데도 불구하고 SEC7118 XMLHttpRequest CORS 라는 에러를 내 뿜는


경우가 있는데 해당은 IE 11 버그입니다. (Windows 10 으로 가서 실행시는 나타나지 않는)


CORS이슈가있으면 response, request가 되지 않습니다. 



이에 대해서 여러가지 방법이 있는데 

1. ajax의 dataType을 jsonp 로 바꾸는 법 


2. 헤더의 크로스 도메인 을 허가하는 방법 

  -> PHP  header("Access-Control-Allow-Origin: *");

  -> JSP  <% response.addHeader("Access-Control-Allow-Origin","*"); %>



3.  Node에서는 cors 모듈을 설치 하는 법

현재는 NPM에 대한 이야기 이므로  cors 모듈을 설치하여서 해결하는 방법이 있습니다.

express-cors 도있고 cors도 있는데  express-cors는 npm 검색시에도 잘 나오지 않고 npm에서 cors로 검색시에 가장 인기가 많은 cors 모듈을 사용하였으니 해당 모듈에 대해서 간단하게 

소개하겠습니다.


cors 검색하게되면 가장 상단에 


Node.js CORS middleware 2.8.4 가 보일 겁니다. 해당 클릭 

설명에 보시면  Connect/Express middleware that can be used to enable CORS with various options.


cors를 활성화 해준다고 되어있습니다. 여러 기능도 포함하여서


설치

-> npm 모듈이기 때문에 npm 으로 설치 합니다. 해당 설명도 진행할수록 생략 하도록 하겠습니다.


npm install cors


사용

npm cors 페이지 참조 

1. 모든 도메인 요청 활성화(모든 작업 CORS 허용 테스트용)

// 익스프레스 모듈 require 및 app 설정 (해당 방식은 express 에서 사용하도록 한 규약? 같은 방식)

var express = require('express')

var app =express();

// install cors 로 설치 하였기 때문에 cors 모듈 require

var cors = require('cors')


// cors () 사용  // 모든 도메인에 대한 Request 활성화  -> 좋지 않은 방식 

app.use(cors());


사용

2. 싱글 라우트에 대한 도메인 활성화(특정 작업에 대해서만 CORS허용)

// 익스프레스 사용

var express = require('express');

var app = express();


// cors 사용

var cors = require('cors');


// ***********  products/:id 에 대한 url 라우팅시에만  cors 를 허용 

app.get('/products/:id', cors(), function(req,res,next) {

res.json({msg:'This is CORS-enabled for a single Route'});

})


사용

3. CORS Config settings(setting 값을 수정하여서 CORS 허용 IP지정)

var express = require('express');

var app = expresS();


var corsOptions = {

origin :'http://example.com',

optionsSuccessStatus:200; // IE 11이나 여러 스마트 TV들에 대한 확인 

};


app.get('/products/:id',cors(corsOptions),function(req,res,next){

res.json({msg:' This is CORS-enabled for only example.com.'});

});

사용

4. CORS w/ Dynamic Origin  동적으로 읽어서 사용 

whitelist 배열을 push 로 추가하여서 실시간으로 허용 및 제거 가능 


// 앞 부분 생략


var whitelist = ['http://example1.com','http://example2.com']

var corsOptions = {

origin: function(origin,callback)    {

if(whitelist.indexOf(origin) !==-1){

callback (null,true);

} else{

callback (new Error('Not allowed by CORS'))

}

}

}


app.get('/products/:id', cors(corsOptions),function(req,res,next){

res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})

});


5. ETC CORS pre-Flight  CORS 비동기 사용 , CORS 제거 등에 대한 내용은

www.npmjs.com 에 cors 검색 후 확인 하시면 될것 같습니다.












NPM (Node Package Manager) 노드에서 사용하는 패키지 


uglify-js : 경량화 도구로써 자바스크립트 코드에 대해 공백을 제거하거나 코드를 가볍게 만들어줌


우선 www.npmjs.com 에 접속 



find packages 에 uglify-js 검색 


검색 후 리스트 중 최상단에 uglify-js (alexlamsl) // JavaScript parser, mangler/compressor and beautifier toolkit 클릭


안에 설명에 따른 설치를 보면


npm install uglify-js -g


또는


npm install uglify-js 로 설치를 할수 있으며


**ps -g옵션은 글로벌이란 뜻으로 어느 위치에서나 해당 명령어를 사용할수 있게 해주는 옵션 


( centos 기준으로  bash_profile에 넣어서 처리를 해주는게 아닌가 싶음 *추측 -> 확인되는 대로 글 수정 예정 )



-g 가 없을 시에는 lcoal 로 되며 현재 프로젝트 안에서만 사용이 가능 하다 



설치 후에 사용은 uglifyjs [input files] [option] 으로 사용한다고 적혀있다.



npm install uglify-js -g 로 설치 한 후에


uglifyjs 로 명령으로 실행하기전에 text.js를 생성


ugly.js


function ugly(ugly)

{

console.log("ugly");

console.log(ugly);

}

ugly("text Ugly");



와같이 작성후  (ESC 누른후 :  wq 엔터 -> vi 저장 단축키)


node ugly.js 실행시 다음과 같은 화면이 나타남 




이제 uglifyjs ugly.js 실행



 해당  입력이 위와같이 변함을 확인 할 수 있다. 


-m 옵션을 써서 uglifyjs ugly.js -m 을 써 주게 되면


위의 Local 변수인 ugly -> l 로 변환됨을 할수 있다. 이러한 변수명 까지 수정해준다.


새로운 파일로 추출해내기 위해서는


uglifyjs ugly.js -o ugly.min.js  와 같이 입력시 


ugliy.min.js 로 나타남을 확인 


해당 옵션을 같이 써서


uglifyjs ugly.js -m -o ugly.min.js 로 하게 되면 Local 변수로 수정하면서 다른 파일로 추출이 됨을 확인할수 있다.


안녕하세요 Jenkins 를 재설치 하게 되서 다른 방법으로 소개 하려고합니다.


// 젠킨스 공식 홈페이지

https://jenkins.io/



1. 메인 홈페이지 이동 후 Download 클릭 



2.  하단으로 스크롤



최신 버전 선택 


3. 다운로드 

(보이는 메뉴얼 대로 wget 으로 받아도 되고 저는 jenkins-2.117-1.1noarch.rpm 을 받아서 FTP로 옮겼습니다.)




4. root 계정으로 접속

명령어 입력

 rpm -Uvh jenkins-2.117-1.1.noarch.rpm







5. Jenkins Port 설정(루트 계정)

Default 8080 을 쓰지만 예약 포트라 겹칠 일이 있어 변경해줍니다.



vi /etc/sysconfig/jenkins



6. /etc/init.d/jenkins start or /etc/init.d/jenkins restart


Starting jenkins (via systemctl):  Job for jenkins.service failed because the control process exited w                                                                ith error code. See "systemctl status jenkins.service" and "journalctl -xe" for details.


에러가 났습니다.


 jenkins.service - LSB: Jenkins Automation Server

   Loaded: loaded (/etc/rc.d/init.d/jenkins; bad; vendor preset: disabled)

   Active: failed (Result: exit-code) since 월 2018-04-16 19:19:38 KST; 2min 32s ago

     Docs: man:systemd-sysv-generator(8)

  Process: 24668 ExecStart=/etc/rc.d/init.d/jenkins start (code=exited, status=1/FAILURE)


 4월 16 19:19:38 localhost.localdomain systemd[1]: Starting LSB: Jenkins Automation Server...

 4월 16 19:19:38 localhost.localdomain runuser[24673]: pam_unix(runuser:session): session opened for user jenkins by (uid=0)

 4월 16 19:19:38 localhost.localdomain jenkins[24668]: Starting Jenkins bash: /usr/bin/java: 그런 파일이나 디렉터리가 없습니다

 4월 16 19:19:38 localhost.localdomain jenkins[24668]: [실패]

 4월 16 19:19:38 localhost.localdomain systemd[1]: jenkins.service: control process exited, code=exited status=1

 4월 16 19:19:38 localhost.localdomain systemd[1]: Failed to start LSB: Jenkins Automation Server.

 4월 16 19:19:38 localhost.localdomain systemd[1]: Unit jenkins.service entered failed state.

 4월 16 19:19:38 localhost.localdomain systemd[1]: jenkins.service failed.


에러메시지 대로 systemctl status jenkins.service는 확인해봅니다.


확인해보니 

 jenkins.service - LSB: Jenkins Automation Server

   Loaded: loaded (/etc/rc.d/init.d/jenkins; bad; vendor preset: disabled)

   Active: failed (Result: exit-code) since 월 2018-04-16 19:19:38 KST; 2min 32s ago

     Docs: man:systemd-sysv-generator(8)

  Process: 24668 ExecStart=/etc/rc.d/init.d/jenkins start (code=exited, status=1/FAILURE)


 4월 16 19:19:38 localhost.localdomain systemd[1]: Starting LSB: Jenkins Automation Server...

 4월 16 19:19:38 localhost.localdomain runuser[24673]: pam_unix(runuser:session): session opened for user jenkins by (uid=0)

 4월 16 19:19:38 localhost.localdomain jenkins[24668]: Starting Jenkins bash: /usr/bin/java: 그런 파일이나 디렉터리가 없습니다

 4월 16 19:19:38 localhost.localdomain jenkins[24668]: [실패]

 4월 16 19:19:38 localhost.localdomain systemd[1]: jenkins.service: control process exited, code=exited status=1

 4월 16 19:19:38 localhost.localdomain systemd[1]: Failed to start LSB: Jenkins Automation Server.

 4월 16 19:19:38 localhost.localdomain systemd[1]: Unit jenkins.service entered failed state.

 4월 16 19:19:38 localhost.localdomain systemd[1]: jenkins.service failed.



이부분이 눈에 들어옵니다. jenkins 스크립트가 제대로 실행이 되지 않는 것 같아서


jenkins 스크립트를 까봅니다. 




자바 홈이 잡혀 있지 않았습니다.

/usr/bin/java -> 나의 자바 홈으로 변경(/usr/java/jdk1.8.0_152/bin/java

// 자바 바이너리를 타겟으로 하셔야 합니다. 



** 성공 

7. 웹으로 접속 ip:8888

 Unlock Jenkins


같은 동일 PC에서 하신다면 localhost:8888 


// 위에 8888로 설정하였기 때문에 혹시 안된다면 8080으로 해보셔도 되고 재시작을 해보시고 8888로 하시면 됩니다. 위에서 설정만 하고 말았다면 적용이 안되어있을수 있음 

** 접속이 안되는 경우 방화벽 문제일 확률이 높으니 테스트용으로

systemctl stop firewalld  실행 후 접속 시 정상접속 확인 됩니다.

접속 후 해당 부분에 입력 하는 키는

cat /var/lib/jenkins/secrets/initialAdminPassword 에 있는 키를 입력 하면 됩니다.



** JENKINS_HOME ="var/lib/jenkins" // 5단계까지는 접속 해도 아무것도 없습니다.



8. Customize Jenkins

Install suggested plugins 설치 (기본 설치 이므로 원하지 않는다면 선택하지 않아도 됩니다.



[설치 중 화면]


9. Admin 계정 생성(Root)

// 해당 계정으로만 jenkins의 플러그인 설치 및 쉘 스크립트 작성이 가능하기 때문에 유의 바람





접속 화면




+ Recent posts