안녕하세요 저번 포스팅에서 Jenkins를 Windows.Ver으로 설치 하였습니다.(Windows 7 64bit)


설치도 하였고 기본 적인 설정 및 Jenkins 서비스를 재시작 하는 부분 까지 포스팅 하였는데요


사실 빌드 자동화 및 배포 를 위한 Jenkins는 CentOS 7 에 설치 하여서 진행하고 


이게 더 관리도 좋고 편합니다. 


윈도우 젠킨스 설정 및 사용 (Windows .ver with Jenkins)

https://ipex.tistory.com/entry/Jenkins-%EC%9C%88%EB%8F%84%EC%9A%B0-%EC%A0%A0%ED%82%A8%EC%8A%A4-%EC%84%A4%EC%A0%95-%EB%B0%8F-%EC%82%AC%EC%9A%A9-Windows-ver-with-Jenkins?category=767972


하지만 이번에 하는 작업은 회사에서 사용하고 있는 private web-front-end framework 

(TOP.js - TmaxDay 에서 공개 했으니까 이름정돈 공개 해도 될것 같습니다.) 


에 대한 자동화가 필요하기 때문에 (Windows 7 64bit) 에서 하여야 합니다. (IE 때문!)  프론트 프레임워크를 QA를 혼자 하고 있다보니 (개발연구원 수십명인뎅..) 자동화가 급박해졌습니다. 


Jenkins 에서 Build Job을 실행하는 작업은 생략 하겠습니다.


대강 러프하게 그려본 도식도는 이렇습니다. (현재는 이대로 돌아가고있습니다.~~ v)


엄청 러프하게 그렸는데 사실은 처음에 혼자 이렇게 되기가 힘들거같았는데 막상 하다보니 이것도 뭐 복잡한건 아닌것 같습니다..(그리고 너저분하다는 생각도 들어서 계속 수정해 나가야 합니다.)


해당 도식도 중 카테고리가 CI이기 때문에 Jenkins 관련해서만 작성할 예정입니다.


1. General

기본적인 내용 및 옵션 입니다.   


추가적으로 저는 오래된 빌드를 삭제 하는걸 체크하였는데 20~30일정도로 설정하였습니다.


(테스트 결과는 testLink 에 저장도 되고 node 서버에 dbms로 도 저장합니다..)


2. 소스 코드 관리 

소스코드 관리 입니다. 빌드 시작전에 어떠한 코드로 자동화를 돌려야 할지 자동화 테스트 코드를 관리 하는 부분입니다.

전체적으로 자동화 관련된 프로젝트는 4가지가 있습니다.

*Node.js (express)

express 로 만들어진 서버이며 mysql 을 DBMS로 가지며 테스트 결과를 저장합니다.

또한 ajax 등 비동기 테스트를 위한 서버이기도 하며 그 외에 서버를 통해야 하는 작업들을 위한 테스트 서버입니다. (더미데이터 등등)


**Node.js 서버는 testLink 에 테스트결과를 Update 할때 필요한 Junit.xml을 xmlBuilder를 통해 제작하는등 여러 기능들이 있습니다.


*Top.js(private web-front-end framework )

Top.js의 많은 Component 와 Container 및 Layout등을 테스트를 위한 초점으로 만들어진 Client 페이지입니다.

해당 프로젝트는 자사의 JEUS 6,7,8 로 구성되어 Deploy 되어있습니다.


End Point

해당 페이지의 특정 버튼을 누르게되면 테스트결과를 가지고있다가(자체 제작 모듈)

testLink 를 연동하기 위한 테스트 결과를  Node 서버로 전송합니다.


*Selenium-WebDriver + (IE Driver or Chrome Driver or FireFox Driver)

Top.js로 만들어진 페이지를 자동으로 테스트하기 위한 Test Runner 입니다. 3가지의 브라우저가 동작하여야 하기 때문에 해당 프로젝트에서는 내부적으로 ie , chrome,firefox 등 여러 드라이버가 설치 되어있으며 파라미터를 통해서 원하는 드라이버를 require 하여   테스트를 시작합니다.


* React.js (redux,react-redux,sass,react-router,... )

React.js로 만들어진 페이지입니다. 내부 private 프레임워크만 하다보니 다른것도 흥미가 생겨서 하게 된것도 있지만 Top가 버전업이 되었을 때 무조건 동작이 잘되리라는 보장이 없기 때문에 View를 위한 (테스트결과 추이 등을보기 위한) 페이지가 필요합니다. 

(물론 안정화된 top버전을 통해서 간단한 페이지를 만들수도있지만  react.js도 해보고싶었습니다.)


해당 4개의 프로젝트가 존재 하는데 어디서 소스코드를 가져와야 하나  


글씨 크기를 보면 아시겠지만  Selenium-WebDriver  입니다. 테스트를 시작하기 위해서는 사람을 대신할 객체가 필요한데  셀레니엄이 브라우저도 열고Top.js 의 End Point 까지 테스트를 진행합니다. (마지막엔 결과를 서버로 전송)


소스 코드 관리를 말하기전에 서두가 너무 길었지만      git을 통해서 관리합니다.  


Repository URL 란에 git을 선택 해주시고 git clone 에 사용하는 주소(HTTP) 를 넣어 줍니다.


그리고 Credentials 을 입력하기 위해서 우측에 Add를 선택하고  아래의 provider에서 입력 합니다.



기본적으로 나와있는 것을 제외하고 사용자가 입력하여야 하는 부분에 대해서 말씀드리자면


Username : Gitlab ID

Password : GitLab Password 

ID : Credentials 을 눌렀을 때 표시될 이름 (ex: seleniumTestCode)

Description : 작성하는 중인 Credentials 에 대한 설명 


Add버튼을 눌러 생성하게 되면 Credentials 드랍 박스에서 위의 설정한 ID가 표시되게 됩니다.


선택합니다.


-Branch Specifier (blank for 'any') 에 가져올 위치인 */master 입력 


!!! 빌드 시작시 소스코드를 최신으로 땡겨오게 됩니다.


// node_modules 는 gitlab 에는 올리지 않지만 편의를 위해서  내려받은 package.json 에 대해

// npm update를 미리 한번 해주었습니다.



Build Job 은 현재 3가지가 있습니다. (포스팅할때는 이미 다 해놓은 상태에서 포스팅!)


IE Automation

Chrome Automation

FireFox Automation 


3개의 Build Job은 다 같은 형태로 돌아갑니다. (Node.js 드라이버 실행시 파라미터만 다릅니다.)

// _auto.js ie 

// _auto.js chrome

// _auto.js firefox

3. 빌드 유발 

3개의 Job(IE,Chrome,FireFox) 에 대한 빌드 유발을 어떻게 할것인가 인데 

(현재는 Selenium-webDriver의 testCode가 push 또는 merge request 발생시)

스크립트로 원격 유발같은거 있는데 이거 한번 해보려고합니다.


RND서버에 새로운 버전이 올라왔을 시에 대한 점검 로직은 없기 때문에 특정 위치를 바라보는 Watcher를 만든 후에 새로운 버전이 올라왔음이 감지되면 자동으로 내려받아서 빌드를 시작할수 있도록 ;; 


webhook 에 대한 기본 트러블 슈팅은 해당 링크

https://ipex.tistory.com/entry/gitlab-%EC%9B%B9%ED%9B%85webhook-Internal-Error-500


Jenkins 에 GitLab Plugin 이 설치 되어 있어야 합니다.


4. 빌드 환경

Delete workspace before build starts 라는 것이 있습니다. (빌드전 워크스페이스를 비우는 작업)


고급 탭을 누른 후에 ant style pattern 을 적용하여서 


현재 돌아가는 빌드의 workspace 


Windows의 경우는 (C:\Program Files (x86)\Jenkins\workspace\빌드이름)


에 있는 폴더를 빌드 시작전에 삭제 해주는 역할을 합니다.


이 작업을 해주는 이유는 testLink 가 해당 폴더에 있는 testCase를 보고  테스트 실행을 할건데


기존에 작업했던 것이 남아있어서 테스트가 꼬일까봐 매번 작업전에 지워줄수 있도록 세팅 합니다.


아래와 같이 작성시에는 workspace/chromeBuilding 폴더와 그 하위 파일들이 전부 지워진 후 Build로 넘어갑니다.



5. 빌드

빌드는 2가지로 나뉩니다. 

5.1 Selenium-WebDriver


5-2 TestLink 




빌드 작업에 대해서는 다음 포스팅에서 하겠습니다.


읽어 주셔서 감사합니다.







윈도우 7 에 젠킨스를 설치를 완료 하였습니다.

https://ipex.tistory.com/entry/Jenkins-CI-%EC%84%9C%EB%B2%84-%EC%84%A4%EC%B9%98-Windows-Ver-%EC%9C%88%EB%8F%84%EC%9A%B0-%EC%A0%A0%ED%82%A8%EC%8A%A4-%EC%84%A4%EC%B9%98-2141?category=767972



기존 포트가 8080 으로 되어있는데


저는 8888로 우선적으로 바꾸고 싶기 때문에



C:\Program Files (x86)\Jenkins 경로에 있는 jenkins.xml 을 열어서 8888로 수정합니다.




localhost:8888  접속 



음? 그렇습니다.  재 시작을 안했기 때문입니다.


일단 저장을 합니다. 저는 notepad++ 로 열었기 때문에 저장을 한후에


젠킨스 서비스를 재시작 하여야 합니다. 


CentOS같은 리눅스의 경우에서는 ps 명령어를 통해 확인도 할수 있었고 환경변수에 설정되었던 커맨드 라인을 통해서 실행할수 있었습니다.


Windows의 경우는 조금 다릅니다.


      와 R키를 누릅니다.


[Windows logo] + [R] 





services.msc 


를 실행하셔서 Jenkins 서비스를 다시 시작 (E) 해주시면 됩니다.



짜잔 8888 로 로그인 이 되었습니다.


추후에도 서비스를 종료 하거나 실행시킬때는


services.msc 로 직접 설정하시면 됩니다.


감사합니다





안녕하세요 오늘은 CI 서버인 Jenkins를 Windows 7 에 설치 하여서 사용을 해보려고합니다.


자동화 (셀레늄) + 자동화 페이지 는 만들어진 상황에서  IE11을 실행하기 위해서는


Jenkins가 Windows 에 설치가 되어야 하기 때문입니다.


// jenkins 사이트 

https://jenkins.io/



[Download] 버튼을 누릅니다.



아래의 두개의 설치 할수 있는 경로가 나옵니다.


1. LTS (안정적으로 계속 사용할수 있도록 지원 해주는 버전 ) 

2. Weekly ( 이번주에 추가된 기능이 있는 최신 버전 -> 안정성은 LTS보다 떨어집니다. ) 


저는 Weekly 에서 쭉 스크롤을 내리다 보면 Windows 라고 있습니다.





[Windows] 클릭 합니다.



[다운로드 됩니다.]






압축파일이 다운로드 되는데


압축을 풀고  있는 jenkins.msi 파일을 실행하여서 설치 합니다.



딱히 설정할건 없고 Next를 진행하다보면 설치가 완료 됩니다.


그리고 자동으로 브라우저에 의해 실행이됩니다. 



리눅스와 비슷합니다. 해당 키를 입력 해야 합니다.





해당 Password파일을 에디터로 열어서 입력 합니다.


(저는 notepad++ 로 읽었습니다.)


1. Install suggested plugins : 설정해주는대로 기본 설치 

2. Select plugins to install : 직접 골라서 설치 


저는 1번으로 했습니다.   (설치중 .... )




설치가 끝나게되면 admin User 에 대한 설정을 하는 창이 나옵니다.


입력 다 한후 Save and Continue 를 누릅시다.





기존 버전에서 (올해 초에 작성하였던 jenkins) 는 없었는데

https://ipex.tistory.com/entry/Jenkins-CI-%EC%84%9C%EB%B2%84-%EC%84%A4%EC%B9%98-415%EC%9D%BC-%EC%9E%90-%EB%B2%84%EC%A0%84?category=767972



기본 instance 설정 도 나타나게 되네요 






Save and finish 하게되면 해당화면이 나타나고 Start using Jenkins 로 설치를 완료 하고 실행합니다.



완료 됐습니다.



Windows. Ver Jenkins 사용은 따로 다시 작성하겠습니다.


감사합니다.









Node.js 웹 어플리케이션 프레임워크 - > Express !  뭔가 이름부터 짱짱 멋지네요


비슷한 프레임워크로 koa가 있다고는 하는데 뭔가 익숙한 Express에 대해서 작성 해놓으려고 합니다.


현재 사용중인 버전은 express 4.16.3 버전을 사용중에 있습니다. (2018-09-19)


이외에 같이 사용중인 npm Module은


cors 2.8.4

iconv-lite 0.4.24

morgan 1.9.1

multer 1.3.1

joi 13.6.0

faker 4.1.0 정도가 있겠네요


Node.js 가 설치 된 상태라고 가정 시에


express를 설치 하겠습니다.



      mkdir praticeExpress
      cd praticeExpress
      // npm 초기화 
      npm init 
      // express 설치 
      npm i express 
      // express 구조 파악을 위한 express-generator 설치  전역에서 사용하기 위한 -g 옵션 
      npm i express-generator -g 
      // 단순 구조파악을 위한 pug 프로젝트 생성
      express --view=pug testApp
      cd testApp
      npm install
      // LInux 기준 실행 
      npm start
  


구조 파악을 위한 generator 후에 구조 입니다.


.
├── app.js
├── bin
│   └── www
├── package.json
├── public
│   ├── images
│   ├── javascripts
│   └── stylesheets
│       └── style.css
├── routes
│   ├── index.js
│   └── users.js
└── views
    ├── error.pug
    ├── index.pug
    └── layout.pug

[공식 홈페이지 https://expressjs.com/ko/starter/generator.html ]



app.js 부터 보겠습니다.


1. app.js

불러 오는 모듈들이 엄청 많네요

http-errors,express,path,cookie-parser,morgan, ./routes/index , ./routes/users


이중에서 불러오는 모듈들에 대해서는 각각 모듈에 대해 검색? 으로 찾을수 있는 부분들이라고 생각되서 이를 제외한 것들에 대한 확인을 하였습니다.


var app = express; // 공식 홈페이지에 이와같이 쓸수 있도록 가이드 되었습니다. 따라갑시다


// views -> 사용하는 템플릿 엔진 이 있는 디렉토리 설정 

app.set('views ', path.join(__dirname,'views'));

// 뷰 엔진 설정 - express에서 사용할 템플릿 엔진을 설정합니다. pug로 생성했기 때문에 pug로 지정하네요

app.set('view engine','pug');


// * 만약에 뷰엔진을 지정하지 않았을시에는 index.pug 라고작성해 주어야 하지만

// * 뷰 엔진을 pug로 지정하였을 경우는 index라고만 써도 index.pug로 인식하여 동작합니다.

// * res.render('index')      < - > res.render('index.pug')


// ** 템플릿 엔진 사용시에는 관련 모듈도 설치 하셔야됩니다. npm i pug 



// app.use

공식 홈페이지에는 이와같이 나타나있습니다.


지정되는 경로에서 지정된 미들웨어 기능을 탑재


app.use([Path],callback[,callback ...])


path : 미들웨어 기능이 호출되는 경로  Default [ '/' ]

 - 경로를 나타내는 문자열

 - 경로와 패턴

 - 경로와 일치하는 정규식 패턴

 - 위의 조합의 배열


callback : 콜백 함수                         Default : None

 - 미들웨어 기능

 - 일련의 미들웨어 기능 , 로 구분 

 - 미들웨어 기능의 배열

 - 위의 조합의 배열

자세한 내용은 따로 포스팅 하겠습니다.  

아래의 코드들에 대해 설명을 달자면

// express.json 은 express 16 버전 부터 사용 가능 

// express 내장 미들웨어 로 JSON 을 구문 분석 및 Content-type 헤더가 type 옵션과 일치 하는 요청을 보고하는

// 미들웨어를 반환하여 use ( 현재 express에서 사용 합니다. )

// 만약에 Content-type이 맞지 않거나 등의 오류가 발생하면 request 는 req.body 에 채워지는데 {} 값으로 채워집니다.


app.use(express.json());


// urlencoded 역시 내장된 미들웨어로 body의 인코딩을 UTF-8 로 받아 처리해준다.

// extended: 옵션은 기본값은 true이며 true일 경우  

// URL-encoded data와 querystring library 또는 qs 라이브러리 사이의 파싱을 선택할수 있게 허용한다.

// false로 주게 되면 이 부분은 허용하지 않게 한다. ( express 자체적으로 처리 )

app.use(express.urlencoded({ extended: false }));


// express 내장 미들웨어로 루트 디렉토리에서 정적 데이터들 위치를 지정한다. 

// req.url 로 제공된 root디렉토리 와 결합하여 제공할 파일을 결정 

app.use(express.static(path.join(__dirname,'public')));


// 라우터를 사용  -> routes 에서 다시 

app.use('/',indexRouter);

app.use('/users',usersRouter);


// 이외 코드들은 express 에러 핸들링 코드로 되어있는데 이부분은 따로 다뤄야 할것 같습니다.!


2. bin

실행 파일을 놓은 폴더 입니다.  (현재는 어떤 느낌인지 정도만 보고 넘어갑니다.)

3. package.json

현재 사용하는 npm 프로젝트의 의존성 파일입니다.

4. public

정적 파일로 사용할 폴더입니다. 대부분 리소스 파일들을 놓습니다.

해당 폴더를 사용하기 위해서 app.js에서는

express.static이라는 메서들를 사용합니다.

app.use(express.static(path.join(__dirname,'public')));


5. routes

express에서 use로 사용하기로 되어있던 라우터들이 있는 폴더 입니다.

app.use('/',indexRouter);

app.use('/users',usersRouter);

// 로사용 


var express = require('express');


// **** express.Router는 새로운 Router 오브젝트를 반환 해주는 express API 입니다.

var router = express.Router();



/* GET users listing. */

// / 로 작성하였지만 실제 app.js에서는 app.use('/users'/로 경로를 지정하기 때문에

// / 로 작성하여도 실제 동작은 /users 가 됩니다. 


// get으로 /totalUser 라고 작성시에는 실제로는

// /users/totalUser에 대한 라우팅을 실행합니다. ** app.use('/users', ... ) 로 호출하였을 시에


router.get('/',function(req,res,next) {

res.send('respond with a resource');

});


// 위의 만들어진 router를  module.exports를 통하여 exports 합니다. 


// app.js 에서는 var userRouter = require('./routes/users'); 로 사용 

module.exports = router; 


6. views

express에서 사용할 뷰 (views) 템플릿 엔진이 있는 폴더 입니다.

app.set('views ', path.join(__dirname,'views')); 로 지정 



generator를 통해서 기본적인 구조를 파악 한 후에 간단한 더미데이터를 던져 주는 서버를 제작해 보았습니다.


// dummy Data Server

https://github.com/lgance/VanillaJS/tree/master/myVanillaJS/legacy/dummyServer


사용은 


git clone https://github.com/lgance/reactStudy.git 로 클론을 뜬 후에 내부에 dummyServer가 있을 겁니다.


cd dummyServer 


npm update ( package.json 과 package-lock.json 을 통한 모듈 설치 -> git에는 node_modules를 올리지 않음 )


node app.js


요청은  localhost:3505/dummys?columns=20&rows=50 와같이 사용하시면 됩니다.


원하는 컬럼과 로우에 맞게 데이터를 던져 줍니다(JSON) 


[결과]













git을 쓰다보면 예전에 만들어 놓은 폴더를 날리고 싶은데


gitlab 같은 웹페이지에서는


파일 자체 삭제는 제공하지만  폴더 통째로 날리는 법은 제공을 안해주는 것 같습니다.


그래서 어떻게 하면 지울수 있을까 하다가


찾아본 방법이 있습니다.


우선 git CLI 에서 git pull 을 해야 될거 같으니 이거 먼저 합시다 


git pull


git rm -r --cached [날리고싶은 폴더]


> 만약에 

[폴더] TestA

[폴더] TestB

[폴더] TestC

[폴더] TestD

[파일] .gitignore

[파일] README.md


이형식인데

A,B를 git에서 제거하고 싶다!


git rm -r --cached TestA

git rm -r --cached TestB


하게되면 현재 두 폴더에 대한 캐시가 날아가게 됩니다.( 없다는것 처럼 인식 )


git commit -m"TestA TestB 삭제"


.gitignore에서 저 위에 폴더 실제로 삭제 되진 않았기 때문에


.gitignore 파일


/TestA

/TestB


위와 같이 .gitignore파일을 작성 후


git push origin master


!! 짜잔 해당 폴더가 없어졌네요



** 번외 편 폴더 추가 

// 폴더 생성

mkdir addFolder


// 생성된 폴더 안에 .gitkeep 생성 // git은 폴더만은 인식 하지 못하기 때문에 파일을 넣어 줌

touch addFolder/.gitkeep


// git status 에서 인식이 되기 때문에 추가 가능 폴더를 추가

git add addFolder


// 마스터 푸쉬!

git push origin master


포스팅 읽어 주셔서 


감사합니다.






안녕하세요 오늘은 gitlab 에있는 웹훅 (webhook) 기능을 사용하다 발생한 이슈에 대해서 작성 하려고 합니다.


최신 버전 GitLab 에서 같은 서버에있는 CI(Jenkins) 에 webhook 을 요청시에는


Internal Server Error 500 이 나타납니다.


일단 해당 이슈는 ssrf 관련 이슈이기 때문에 gitlab ssrf 라고 검색 하여도 충분한 결과를 얻을수는 있을 겁니다.


ssrf이슈인지 파악이 안됐었.. ㅜ


해당 내용 설명에 앞서 ssrf에 대해서 간단하게 작성하자면


SSRF ( Server - Side - Request - Forgery ) 서버 요청 위조 

CSRF ( Client - Side - Request - Forgery ) - 클라이언트 요청 위조

SSRF는 CSRF 와 달리 서버가 직접 호출해서 발생하는 문제입니다.  서버가 직접 요청하는 바람에 외부에서 내부에 있는 리소소스 등 접근해서 서버 직접 제어가 가능해지기 때문에 해당 의 경우 SSRF의 위험성이 있기 때문에


Jenkins 서버와 GitLab이 같은 서버에 위치할때 루프백 (자기자신) 으로 요청하게 되면 SSRF 가 발생하게됩니다.


gitlab webhook 은 기본적으로 내부 서버 요청을 서버가 직접 하는것들을 SSRF 이슈로 인해 허용하지 않기 때문입니다.


그래서 기본적으로 gitlab 생성후 webhook 을 내부 같은 서버에 있는 jenkins(CI)에 호출하게되면 500 Internal Server Error 가 발생합니다.


우선 gitlab 업데이트 노트를 보겠습니다.



SSRF 이슈때문에 설정을 변경하여야 한다고 되어있습니다.


GitLab 에 접속합니다.  (ROOT 계정)


루트 계정으로 접속하게되면 위와같이 admin Area 가 있습니다. 해당 스패너를 클릭합시다.




최하단에보면 Settings 라고 있습니다.


그리고 우측에서 쭉 내리다보면


Outbound requests가 있습니다.

Expand 해 주신 후에

Allow requests to the local network from hooks and services 

체크 해줍시다.





자 이제 gitlab을 재시작 하고 webhook 을 테스트 해보면 정상적으로 됨을 확인 하실수 있습니다.


gitlab 시작 및 종료


sudo -s gitlab-ctl start

sudo -s gitlab-ctl stop


gitlab 재 설정 후 재 시작


sudo -s gitlab-ctl reconfigure


// gitlab 기본 설정 

https://ipex.tistory.com/entry/gitlab-기본-설정?category=768899




감사합니당~


안녕하세요 리액트를 제대로하기전에 


라이프 사이클 까지보았고 이번에는 리액트의 스타일에 대한 작성을 해보려고합니다.


기본적으로 앞서서 스타일을 작성하는 방법에서는


2가지 방법이 있었죠


1. Inline Style CSS 

인라인 방식의 CSS는 클래스 또는 컴포넌트형 함수들 에서 

js Object 형식으로 만들어서 직접 태그에 넣는 방식의 스타일 방식입니다.


인라인 스타일 방식입니다.


render 함수에서 직접 작성합니다.


render() {
const tempStyle={
display:"inline-block",
width:"100px",
height:"100px",
boder:"1px solid black",
background:"orange",
}
return (
<Fragment>
<div style={tempStyle}></div>
</Fragment>
);
}
}


const tempStyle 이라고 작성된 style을 직접 리턴하는 태그에 style로 넣어주게됩니다.

위의 코드에서는 변수를 만들어서 넣었지만 같은형식으로 태그에도 직접 넣어줘도 됩니다.


<div style={{
display:'inline-block',
width:'100px',
height:'100px'
}}></div>



해당 인라인으로 작성후 npm start 로 확인 시 


정상적으로 렌더링 된점을 확인 하실 수 있습니다.


이 방식이 인라인 스타일 방식입니다.



2. Import Style CSS

미리 작성해둔 CSS를 불러와서 (import) 태그에 className으로 작성하여서 사용하는 스타일 방식

import 하여서 css를 사용하는 경우 다른 경우(리액트가 아닌 경우) 에서는


<link rel="stylesheet" href="./style/styles.css"/> 와 같은 방식으로 가져오게 되지만


리액트에서는 import 구문을 통하여서 가져와야합니다.


import styles from './App.css';


해당과 같이 호출 하여서


<div className={styles.box} ></div>


.box{
display:inline-block;
width:100px;
height:100px;
border:1px solid black;
position:fixed;
top:50%;
left:50%;
transform:translate(-50%,-50%);
}


의 box 클래스를 가져와서 입힐 때는 위와같이 작성하여야 합니다.

하지만 작성엔 문제가 없지만


화면에 렌더링시에는 나타나지 않습니다.


왜!!!? webpack 설정이 안되어있기 때문이죠 


테스트용이기 때문에 webpack production 은 건드리지 않고 dev만 건드리면


webpack.config.dev.js 에  css-loader 부분이 있습니다.


** 만약에 create-react-app 으로 만들어졌는데 webpack.config.dev.js가 없다면??

해당 프로젝트에서 npm run eject 명령어를 입력하시면 해당 파일이 생성됨을 확인하실수 있습니다.


이부분에


loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
// modules 지정안할시는 아예 import가 되지않음
modules:true,
},

modules 옵션을 추가해줍시다.!!


그러면 정상적으로 화면에 렌더링이 되는 점을 볼수 있습니다.


위의 코드에서 styles.box 로 넣었지만 리액트는 여러개의 클래스도 넣을 수 있습니다.


<div className={[styles.box,styles.blue].join(' ')}></div>



해당 방법은 너무 지저분하기도 하고 코드 가독성도 그냥 그래서 조금 더 줄이기 위해서 classnames라는 lib를 사용한다고 합니다.



npm i classnames


- .join 이 빠지고 단순 괄호로 묶어서 사용 ( 하지만 style.box style.box  style이 중복되는 현상 발생 )

>classnames에 bind라는 기능을 사용 !! 



import classNames from 'classnames';


<div className={classNames(style.box,style.blue)}></div>




결과


from classnames를 classnames/bind로 꼭 수정하셔야됩니다.


const st = classNames.bind(styles);


-> 해당 css파일들에 대한 클래스를 st가 묶어서 가지고 있는 것으로 보입니다.


그래서 결국 다중 클래스 를 집어 넣을시에는


st('box','second',third') 로 하게되면


App.css에 있는

.box{}   .second{} .third{} 가 순서대로 불려와집니다.


중복되는 클래스가 있을 경우 뒤의 css 스타일이 적용됩니다. (유의바람!)


import React, { Component,Fragment} from 'react';
import classNames from 'classnames/bind';
import PropTypes from 'prop-types';
import styles from './App.css';


const st = classNames.bind(styles);

class App extends Component {
static propTypes = {
name: PropTypes.string,
}
render() {
const isBlue = true;
const tempStyle={
display:"inline-block",
width:"100px",
height:"100px",
boder:"1px solid black",
background:"orange",
}
return (
<Fragment>
<div className={st('box',{
blue:isBlue
})}>
</div>
</Fragment>
);
}
}
export default App;



다음에는 sass에 대해서 작성하겠습니다!

안녕하세요 정말 중요한 부분인거 같아서 메인 포스팅 전의 서브 포스팅을 합니다.


React.js 에서의 라이프 사이클 에 대한 이야기인데요


**** 해당 라이프 사이클에 대한 내용은 현재 보고있는


" 리액트를 다루는 기술 " 책을 9할 이상 공홈에 1할정도 참고 하였습니다.

리액트 입문을 이책으로 하고 있는데 설명이 너무 좋습니다.


1. 마운트 

react 공식 홈 에서는  DOM 에 처음으로 렌더링 될때 라고 되어있습니다.


DOM이 생성되고 웹 브라우저상에 나타나는 작업입니다.  마운트 됐을때의 라이프 사이클

> 컴포넌트 생성


> constructor

-    컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자


> getDerivedStateFromProps (update 사이클에서도 있는 메서드입니다.)

-    props에 있는 값을 state에 동기화하는 메서드

(16.3 새로운 메서드)


static getDerivedStateFromProps(nextProps,prevState){
if(nextProps.value != preState.value){
return { value : nextProps.value };
}
return null; // state 변경 이 필요 없을 시
}

> render

-    생성된 Component UI 를 렌더링 하는 메서드


> componentDidMount

-    컴포넌트가 웹 브라우저상에 나타나는 후에 호출되는 메서드  (마운트가 끝났을 때 겠네요)

 


2. 언마운트


DOM 에 생성되어있는 컴포터를 제거하는 과정

>    componentWIllUnmount

-    컴포넌트가 브라우저(DOM)에서 사라지기 직전에 호출


3. 업데이트 


*****업데이트 는 매우 중요할 것으로 보입니다.

업데이트가 되는 경우 

- props변경 시

- state 변경 시

- 부모 컴포넌트가 리렌더링시 

- this.forceUpdate() 로 강제 렌더링 트리거 시 


[ 참조 - 리액트 를 다루는 기술 ] 


3-1 getDerivedStateFromProps (마운트에도 있던 메서드)

마운트 과정에서도 호출되며 props가 바뀌여서 업데이트시에도 호출이 되는 메서드


3-2 shouldComponentUpdate - 메서드 명 대로 해야할지 말아야할지 를 결정합니다.

컴포넌트가 리렌더링을 할지 말지 결정하는 메서드 return 이 false인 경우는 이 다음에 나오는 메서드를 호출하지않습니다.


3-3 render 

컴포넌트를 리렌더링 합니다.


3-4 getSnapshotBeforeUpdate

컴포넌트 변화를 DOM 에 반영하기 바로 직전에 호출하는 메서드 (DOM 에 적용된게 아닙니다.) 

(16.3 새로운 메서드) - 리액트 공식홈

getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}

3-5 componentDidUpdate

컴포넌트의 업데이트 작업이 끝난 후 호출하는 메서드 



대충 10건 정도의 메서드들이 있네요 









안녕하세요 리액트 시작했는데 뭔가 하나하나씩 포스팅 을 직접 하자니 괜히 게시물만 늘리는거 같고 그래서


한땀한땀 보단 한번씩 정리 해서 포스팅을 하려고합니다.


1. 생성 (컴포넌트)

리액트 컴포넌트는 생성시 파스칼 케이스를 따릅니다. 

gdlbutton  - X

gdlButton  - X


GdlBUtton - O


2. 값 전달 

props 는 부모에서 컴포넌트로 값을 전달하기 위한 속성입니다.



기본 세팅은 와 같이 합니다.  (props로 전달된 basic이없을 경우는 '베이직'이 사용됩니다.)

static defaultProps= {

basic:'베이직'

}


<GdlButton name={test} />


this.props.test

하지만 props가 너무 많은 경우에 대비해서

      예를 들면

props로  name,age,grades, class, email 등이 넘어 오게 되면

this.props.name

this.props.age

this.props.grades

.... 너무 길어집니다.


const {name,age,grades,class,email} = this.props; ( 비 구조화 할당을 사용합시다.)



state 는 컴포넌트 내부에서 이동되는 값입니다.



절대로 this.state.name = "test" 같은 작업은 하지 않습니다.

this.setState({

name : 'test'

}); 

setState를 사용하셔야 리렌더링이 발생합니다.


ref 는 컴포넌트에 있는 함수를 외부에서 호출할수 있도록 해주는  속성입니다.


// 1. 컴포넌트 객체에 ref를 선언하고 => 를 통해서 this.GdlButton = ref를 생성한다.

// 이와같지 하지 않고 this.GdlButton.button으로 바로 사용시에는 렌더링 전에 값이 undefined 이기때문(this.GdlButton)

<GdlButton ref={ (ref) => this.GdlButton= ref} />


// 2. 만들어진 this.GdlButton 을 이용하여 함수 사용 

<button type="button"  

onClick={()=> this.GdlButton.buttonsetText("setText")}>Ref Test</button>



class GdlButton extends Component {

// ref를 달기 위한 함수 작성 

buttonsetText= (addText) =>{

const{ innerText} = this.button;    

this.button.innerText = innerText+addText;


}

render(){

return (

<div 

// ref를 달아서 현재 컴포넌트를 리턴

ref={(ref) => {this.button=ref}}>

{/* .... do thing */}

</div>


);

}

}


export default App;


3. 컴포넌트 여러게 생성 


내부의 count만큼 버튼을 생성하고 싶은 경우


const btnList = Array(this.props.count).fill(null).map((i,index) =>{
return <button type="button" style={btnStyle} key={"Btn_"+index} >
                        {this.props.name +"_"+index}</button>;
});


주의점 ** key 값을 유니크하게 설정 해주어야 합니다. ( 리액트자체 렌더링시 해당 key 값을 통하여서 DOM비교를 하는 알고리즘을 가지고있기 때문에 설정 안할시 warning이 뜨긴하지만 성능 문제가 발생합니다. 키 값이 중복되면 에러가 발생)


Array(count) 로 카운트 만큼 생성 후 .fill을 통해 내부값을 채웁니다. (채워야 map 이 순환)

map을 통하여 채워진 배열만큼 버튼을 생성하여 return 합니다.


사용은 render 함수에서


return (
<Fragment>
{/* porps 로 count가 넘어오면 개수만큼 카운트 없으면
기본 버튼 렌더 */}
{
this.props.count ?
btnList :
<button type="button" style={btnStyle}
onClick={ ()=>{
this.setState({
dName: this.state.dName.split('_')[0]+"_"+this.state.number,
number:this.state.number+1
})
} }> {this.state.dName} </button>
}
</Fragment>


이와같이 사용합니다.

{ btnList } 


4. 컴포넌트 이벤트 전달 


이벤트 생성시에는 캐멀케이스(CamelCase)를 따릅니다.


on-click => onClick

onkeypress ==> onKeyPress 


클래스 내부에 함수를 선언후 바인딩합니다.


4-1 미리 선언된 함수 바인딩


handleEvent = ()=>{
console.log("precondition Event");
}
return (
<Fragment>
<button type="button" onClick={this.handleEvent}>handleEvent</button>
</Fragment>
);


           4-2 생성과 동시에 익명함수 사용


<button onClick={ ()=>{
console.log("Test");
}}></button>


5. 스타일 지정,클래스 지정  및 조건부 렌더링 방법


render() {
const btnStyle ={
display:"inline-block",
width:"auto",
border:"1px solid transparent",
borderRadius:"4px",
margin:'1px',
backgroundColor:"#5cb85c",
color:"#FFFFFF",
fontWeight:"400",
fontSize:"14px",
lineHeight:"1.42857143",
height:"100%"

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


와 같이 사용하며 주의할점은


background-color = 와 같은 케밥 케이스들은 캐멀케이스로 바뀌어야 한다.

backgroundColor

font-size = > fontSize

border-radius  = borderRadius


<div class  > </div> 가 아닌 <div className > </div> 으로 class가 아닌 className 을 사용 하여야 한다.


6. 이외


태그는 무조건 닫아야 합니다. /> 로  그래서 처음에 </br>로 엔터 효과를 내려고했으나  오류가 나서


<br/> 로 사용하여야 합니다.


주석은 


{ /* */ } 로 사용 


propTypes는 props의 타입을 지정할수 있습니다. ( ts 타입스크립트)와 비슷해보이지만


결국 런타임 후에 지정되는 것이고 ts는 런타임전에 알수 있기 떄문에 ts의 하위 호환이라고 봐도 되겠네요


constructor는 컴포넌트를 새로 만들어질때 호출된다. (아직 까진 사용의미를잘 모르겠습니다.)


state는 state = {

basic:'베이직'

}


기존의 state값중 array 가 있을 경우 push 를 해서는 안된다.(타 이벤트 핸들러에서)

push 를 하게되면 기존의 배열에 추가 되어서 더해지는 것이기 때문에 concat 이나 ... spread 연산자 slice를 통해 새로 생성후 합쳐서 새로운 배열을 대입해주어야 한다.


다음 은 리액트 라이프 사이클에 대해서 쓸건데 그전에 spread연산자부터 적고 가야겠네요


리액트 key 에러 


Each child React element in a collection should have a 'key' prop.


자식 Element(요소) 를 map같은 걸로 여러개 생성시 key 값을 지정하지 않으면 해당 워닝을 뱉어냅니다.


그 이유는


리액트에서는  DOM 트리를 업데이트 할때 key 속성을 통해 (리액트에만 있음) diff 알고리즘을 적용하여


렌더링을 최적화한다고 해요


그래서 key 속성이 없어도 화면에 뿌리는데는 문제는 없지만 diff알고리즘을 활용하지 못하기 때문에


렌더링 성능에 영향을 주게 됩니다.


그래서 에러는 아니고 경고 로 뿌려주게 된다고 하더라구요


그래서 현재 작성된 요소가 부모 의 자식으로 들어가는 경우는 key 속성을 넣는 버릇(?) 습관(?) 을 들여야 할것 같습니다.



// 리액트 에서 컴포넌트들을 생성하는것은 파스칼 케이스에 해당되기 때문에 gdlButton 와 같이 생성하면 렌더링이 되지 않습니다.


-> GdlButon 과 같이 첫 문자가 대문자로 오는 파스칼 케이스여야 합니다.


The tag <gdlButton> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.




+ Recent posts