반응형
반응형
jquery mega cheat sheet

반응형
반응형

[JS] 14일 만에 GitHub 스타 천 개 받은 차트 오픈소스 개발기


:bar_chart: Re-usable, easy interface JavaScript chart library based on D3 v4+:chart_with_upwards_trend: 


billboard.js is a re-usable, easy interface JavaScript chart library, based on D3 v4+.

Documents

Playground

Play with the diverse option generating on the fly!

Supported chart types

Chart Types








1. 14일만에 GITHUB 스타 1K 받은    차트 오픈소스 개발기    박재성

2. 차트란 무엇인가?


3. 훗 차트, 너란녀석1) 데이터의 시각화 2) 차트 라이브러리? 1)의 구현을 위한 도구 그러나 차트의 적용은 무엇일까?  결국, 시각화가 기본이다. UI(디자인) + 인터렉션  구현(적용)이 관건


4. CHARTS ARE EVERYWHERE iOS 10  89% iOS 9  9% Earlier  2%


5. 차트 같은걸 끼얹나? 차트는 자주 접하지만, 개발은 그렇지 않다. 한번 개발(또는 경험)되더라도 지속적인  개선 요인이 별로 없어 경험 향상이 어렵다.

6. YOU, 차트 개발 해야함 몇 가지의 선택지들 직접 개발한다. 외부 라이브러리를 사용한다.  → 상용 or 오픈소스 어떤 기술을 사용할 것인가?  → Vector(SVG) or Bitmap(Canvas)


7. 그래, 직접 개발!Good Luck! 진심으로 행운을 빕니다.   

https://giphy.com/gifs/starwars-star-wars-force-3ohuPdEqZR8tDeuN3O


8. 역시, 외부 라이브러리!상용 or 오픈소스? 상용 → 결국 비용의 문제  라이센스 비용 부담 (ex. Highcharts 10 developer $3,320) 오픈소스 → 어떤 라이브러를 사용할 것인가?  결정의 어려움 (많은 고려요소 필요)

9. 다양한 차트 라이브러리어떤 것을 선택할 것인가?  [참고] https://bestof.js.org/tags/chart

10. 기술 선택 가이드 성능 중요(빠른 대용량 데이터 처리),  상대적으로 디자인은 덜 중요한 경우 → Canvas (비트맵) 디자인 및 요소별 커스터마이징,  다양한 해상도(Zoom) 중요 → SVG (벡터) [참고] SVG 대 캔버스: 선택 방법

11. 영역별 다른 관점, 디자인 보단 실시간 변화 표현 중요 대용량 트래픽의 실시간(realtime) 변화 확인 수치의 변화가 중요. 기본 디자인 사용에 문제 없음 관리도구 등에 적합. 소수의 참여자(admin)

12. 영역별 다른 관점, 엔드 유저대상, 다양한 디자인/UX 중요 주로 정적인 데이터의 시각화 디자인과 UX 적용의 유연성 필요 대규모의 불특정 사용자(엔드유저)를 대상

13. 그간 네이버에서의 차트서비스들마다 다른 라이브러리를 사용 그리고 그로 인한 다양한 문제

14. 문제들 기술적 know-how 축적 안됨 상용 라이브러리 사용시 비용 문제 경험이 누적되지 않아 차트 적용(디자인/개발)시,  매번 반복되는 리소스의 낭비

15. 물론, 처음엔 자체 개발 그러나, 성공적이진 못했다. 서비스 적용 이후, 메인터넌스 잘 안됨 개발 주체의 부재상황(이직 등)  또는 다른 서비스 개발 등으로 인한 지원 어려움 타 라이브러리 대비 범용성 부족

16. 그렇다면 오픈소스 사용은 어떨까? 지속적 업데이트, 기술적 트렌드 반영, 안정성 등을  기대할 수 있으니 합리적이지 않을까? 향후 오픈소스 업데이트 지속되지 않을 경우,  fork를 통한 유지 고려도 가능 공통된 라이브러리를 사용하면, 각각 다른 라이브러리 사용으로 인한 관리 및 기술경험 누적되지 않는 이슈 해결 기대 [참고] 그간 사용되었던 다양한 차트 라이브러리들:  ,  ,  ,  ,  , etc.NVD3 C3.js Chart.js Highcharts echarts

17. 직접 개발도 해봤고, 외부(상용/오픈)의 것도 사용해 봤으니 간접적인 형태로 접근해 보자 라이브러리의 발전은 생태계에 맡기자. 필요한 기능은 PR을 통해 해결 오픈소스는 일정 수준 검증 되었다. 다양한 문서, practice가 존재한다.

18. 그래서, 만들다. C3.JS 확장 라이브러리 개발

19. C3.JS 선정이유 가장 인기있는 D3.js 기반 한정 Popularity 비교:  → GitHub star, 써드파티 앱, StackOverflow 질문 수, etc. 간결한 인터페이스 풍부한 문서, 예제 등  → 구글검색 결과: C3.js(22만) Vs. NVD3(6만4천) 네이버 서비스들에서 이미 다수에서 사용 엔드 유저 대상이므로, 디자인/기능 커스터마이징 용이성 중요

20. 개발 시작 고난의 시작

21. 개발시 겪게 되는 문제들 커뮤니케이션 디자인 & 인터렉션 커스터마이징 그리고 또 그리고 수많은...

22. 커뮤니케이션나의 이름은 무엇 인가요?  차트 개발 경험이 많이 없는 경우, 부르는 명칭도 제각각

23. 디자인 가이드 각 요소들의 크기와 위치를 가이드에 맞춰주세요.

24. OMG! SVG TEXT I'm SVG text 텍스트 스타일링은 가능 <br> 같은거 안됨. 줄바꿈은 새로운 노드로 위치(via attributes) 여백 등의 조정이 어려움  → transform:translate 또는 <tspan> 사용

25. 모바일 환경 C3.js는 모바일 환경 미지원 Swipe 제스처를 통한 데이터 확인 UX 필요


26. 환경별 다른 이벤트 발생 터치하고 바로 떼었을 때


 iOS 11 (iPhone 7) touchstart → touchend → mouseover → mousemove → mouseout (포커스 이동되면 발생)

 Android 7 (Galaxy S8) touchstart → touchend → mouseover → mousemove → mousedown → mouseup → click → mouseout (포커스 이동되면 발생) http://jsbin.com/xiyara


27.   최소값y축 기반 값에 따른 up/down 표현 0 1 2 3 4 100,000 100,500 101,000 101,500 102,000 102,500 103,000 103,500 104,000 0 1 2 3 4 0 10,000 20,000 30,000 40,000 50,000 60,000 70,000 80,000 90,000 100,000 110,000 위의 차트는 모두 동일한 값을 표현하고 있습니다.

28. 데이터는 없지만, 데이터는 표현해야 한다? 데이터가 0인 경우,  표현이 되어야 할까? 안되어야 할까? 

29. C3+ C3.JS 확장 라이브러리를 만들다.

30. C3+? C3.js를 확장한 테마 형태의 디자인 차트 생성 C3.JS: 확장 + 기능 보완 + 테마 커스텀 축 지원 범례 템플릿 모바일 지원 테마를 통한 차트 생성 확장 옵션

31. 블로그/포스트 통계 적용[네이버 블로그] 블로그 통계가 새로워졌습니다! [네이버 포스트] 훨씬 좋아진 통계, 지금 제공합니다!

32. C3+ GOAL 매번 다른 기술/라이브러리를 다루는  반복적인 비용 제거 기본적 디자인(테마)을 활용해  커스터마이징(디자인)에 따른 비용 제거 기술적 경험 축적: SVG, D3, C3.js

33. BUT, 현실적 문제직면 장기적 관점에서, C3+ 발전을 위해 외부 공개 목표 하지만, 래퍼/애드온 형태의 지속적 발전과 효용성 의문 기반 라이브러리인 C3.js 지속성 의문 오픈소스의 발전에 기댈 수 있을 것이란 기대는  C3.js의 더딘 발전(또는 중단?)으로 위기 직면

34. Re-usable, easy interface JavaScript chart library based on D3 v4+

35. 차트를 만들어 봅시다.

36. STEP 1 파일을 로딩 합니다.<!-- D3.js를 로딩 --> <script src="https://d3js.org/d3.v4.min.js"></script> <!-- billboard.js와 기본 스타일을 로딩 --> <script src="billboard.js"></script> <link rel="stylesheet" href="billboard.css">

37. STEP 2 차트가 노출될  영역을 설정합니다. <div id="chart"></div>

38. STEP 3 옵션과 함께 차트를 생성합니다. Declarative API bb.generate({ bindto: "#chart", data: { columns: [ ["data1", 30, 200, 100, 400, 150, 250], ["data2", 100, 80, 130, 240, 350, 90], ["data3", 150, 120, 58, 135, 258, 159] ], type: "bar", colors: { data1: "#2acefd", data2: "#f87070", data3: "#1f77b4" }, labels: true } });

39. 짠! bar   line   spline   pie   gauge   area‑spline   step   donut   scatter 30 200 100 400 150 250 100 80 130 240 350 90 150 120 58 135 258 159 0 1 2 3 4 5 0 50 100 150 200 250 300 350 400 450 data1 data2 data3

40. 커스터마이징150개 이상의   제공 SVG 노드: 필요한 경우, 직접 핸들링 가능  CSS로 스타일링 가능  다양한 옵션

41. THE UNKNOWN WAY TO FORK에서 공개까지

42. C3.JS 프로젝트 참여 시도원 개발자 및 커미터에게 메일을 통한 문의 

43. 일단 활동하자PR도 보내고 이슈들에 대한 답변도 하고 [참고] https://github.com/c3js/c3/issues/1924#issuecomment-271224192

44. 그렇게 몇 주가 흘렀지만 메일 회신도 없고, 프로젝트 ACTIVITY도 딱히 없는 상태...

45. 공개적 문의issue를 등록해 공개적으로 프로젝트 유지 문의 [참고] https://github.com/c3js/c3/issues/1965

46. 그리고, 그 다음날

47. 그래, FORK 하자'향후 오픈소스의 업데이트 지속 안될 경우,  fork를 통한 유지'의 명제 당면한 C3.js의 미해결 과제들: D3 최신버전 v4+ 미지원 모바일 환경에 대한 지원 부족 오래된 개발 스타일 코드 (ES3) SVG polyfill 제거 등등...

48. 합리성, 당위성 & 신뢰 Fork 한다고 해서 사용자가 오진 않는다. 기존 커뮤니티에 당위성이 제시 필요 과연 이 사람(개발자)이 믿을만 한가?

49. THE JOURNEY GOING FROM D3 V3 TO V4  WITHIN TWO MONTHS

50. OOPS~, D3 V4v3 → v4: Breaking Changes  공식 문서( ) 있으나,  마이그레이션 가이드 없고 만들지 않을거임.  Changes in D3 4.0 [참고]   https://github.com/d3/d3/issues/2893 D3 V4 - What's new?

51. D3 V4로 업그레이드변경된 모듈에 대한 목록을 모두 작성  v3 v4 d3.time.scale d3.scaleTime d3.svg.line() d3.line d3.behavior.drag d3.drag ... 모듈의 behavior 변경되어, 기존과 유사한 것도 있지만  다르게 처리되는 것들이 대다수 이전 버전과 변경된 문서를 읽고 비교하고, 테스트 하고...

52. 그외 작업들 차트 생성 흐름에 따른 오류들의 순차적 해결/변환 ES3 → ES6로 전환 병행 및 개발 환경 변경 API 문서화 ( ) 테스트 코드 업데이트(d3 v4 호환) 및 커버리지 개선 JSDoc

53. RELEASE 3주전 YAY~!, 이제 끝이 보인다.

54. 어느 날, 갑자기 두둥~ 갑작스러운 C3.js 차기 릴리즈 계획과 새로운 커미터 추가 [참고] https://github.com/c3js/c3/issues/2033

55. 고민이미 많은 진전을 통해 릴리즈를 앞둔상황 계획만을 통한 발전에 대한 의문 커미터 추가 후에도 활발한 활동 없어,  빠른 시일 내 D3 v4 지원 어렵다는 판단 계획대로  릴리즈 하자.

56. 오픈소스 네이밍원래는 C3+ 2.0으로 계획, 그러나 C3.js 연관성의 부정적 의견 'billboard'는 음악 차트 의미는 다르지만 '차트'를 연관 오랫동안 친숙한 이름 FE 프로젝트에서는 기 등록된 npm 모듈명 확인 필요 [참고] Open Source Project Name Checker

57. RELEASE!2017년 6월8일, v1.0.0 공개

58. 그러나, 공개한다고 갑자기 관심과 사용자가 몰려오진 않는다. 홍보전략 필요

59. 직접 발로뛰기 다수의 'ECHO' 사이트에 등록하기 JavaScript Live Echo JS Hacker News 많은 곳에서 해당 사이트에 등록된 정보를 활용, 재전파 한다.

60. 뉴스레터 소개 요청하기 JavaScript Weekly [참고] FE 관련 뉴스레터는 사실, 한 곳에서 발행  https://cooperpress.com/

61. 유력 매체 소개     JavaScript Weekly 소개 JavaScript Daily 소개

62. GITHUB TRENDING!JavaScript 언어부문 3위 기록 [참고] https://github.com/trending/javascript

63. GITHUB STAR 공개 후, 첫 6일간 700개 14일 후, 1,000개 도달! Star의 가치는?  cdnjs 등록은 최소 200개 요구됨 Vuejs도 첫 6일간 615개 How I Got From 0 to 1 000 Stars on GitHub in Three Months

64. THIRD-PARTY APPS!Angular, React, R, Web Components 등의  자발적인 프로젝트들의 등장 [참고] https://github.com/naver/billboard.js/wiki/Third-party-applications

65. 지속적 성장월 npm 다운로드 수 June 370 July 479 Aug 862 Sep 1,124 [참고] npm-stat: billboard.js, 2017.6.8 ~ 9.30

66. 충실한 문서문서 작성은 아주, 아주 중요하다. 대표 사이트:  C3.js에서 마이그레이션 하기 가이드 잘 작성된 API 문서 왜 Fork 하게 되었나? Readme https://naver.github.io/billboard.js/

67. 80여개의 풍부한 예제많은 예제는 '무엇'이 가능 또는 할수 있는지 보여줄 수 있다.  https://naver.github.io/billboard.js/demo/

68. 이제 부터가 시작 Star의 수는 보다 발전할 수 있도록 도와주는 역할 이슈에 대한 빠른 대응 필요 신규 기능과 버그에 대한 처리 을 통해 향후 방향에 대한 정보제공Roadmap

69. 사용자를 위한 지속적 기능 추가

70. PLAYGROUND온라인에서 바로 옵션들을 수정하고 확인  [참고] https://naver.github.io/billboard.js/playground/

71. 신규 옵션들과 문서 C3+ 경험들을 통한 신규 옵션  꾸준한 문서 업데이트 API는 한번 작성되면 끝이 아니다. 정확한 의미와 동작을 기술 그리고 지속적 업데이트

72. 오픈소스의 중요한 요소들 안정성, 충분한 문서 그리고 책임감 [참고] http://opensourcesurvey.org/2017/

73. 오픈소스의 어려움누군가의 노력이 대가없이 제공되는 것.  그러나, 쉽게 비난 받기도 한다.   https://twitter.com/spf13/status/907403135592878080

74. 의연하게 대처하기 You shouldn’t let strangers on the internet negatively affect your mood or your drive  ...  The trolls feed on your  annoyance and discourse.  ― Sindre Sorhus [참고]   Between the Wires: An interview with open source developer Sindre Sorhus 1,139 npm Packages

75. WHY DO OPEN SOURCE? 세상에서 내가 도움 받은 것에 대해  다시 기여하는 의미있고 가치있는 행동 [참고]   네이버 오픈소스 가이드 GitHub Open Source Guides

76. SPECIAL THANKSMASAYUKI TANAKA AND ALL OF THE C3.JS CONTRIBUTORS,  FOR YOUR GREAT EFFORTS AND WORKS TO THE COMMUNITY!

77. 고맙습니다.  Thank You.  Gracias.  https://github.com/naver/billboard.js/



...

반응형
반응형

[Node.js] chromium binding 기술을 node.js에 적용해보자


https://deview.kr/2017/schedule/213


chromium binding 기술을 node.js에 적용해보자

1. Chromium Binding 기술을 Node.js에 적용해보자! Name: Jinho Bang E-Mail: zino@chromium.org

2. 0. 요약

3. 이 세션에서 다룰 내용은..

4. Node.js에서 Native Module을 바인딩 하는 방법이다.

5. 그런데 이미 Node.js에는 바인딩을 위한 방법들이 제공되고 있다.

6. 그러나 그 방법이 아름답지 않다.

7. 이 세션에서는 그러한 문제를 분석하고

8. 좀 더 아름답게 해결하는 방안을 모색해본다.

9. 1. JS에서 왜 Native Module을 사용하는가?

10. 성능(Performance)

11. Low Level APIs

12. 기존에 잘 만들어진 코드가 Native 일때

13. 어쨌든 Node.js를 사용한다면 사용중인 패키지의 30%는 Native이다.

14. 2. 예제를 통해 알아보는 기존의 Native Module 연동 방식

15. sum()함수를 구현해보자(JS 호출) let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); JS JS function sum(elements) { let s = 0; elements.forEach(element => { s += element; }); return s; }

16. sum()함수를 구현해보자(Native 호출) let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); JS Native int sum(std::vector<int> elements) { int s = 0; for (int i = 0; i < elements.size(); i++) s += elements[i]; return s; } ?

17. 그런데 Javascript에서 어떻게 호출할까?

18. 기존의 Native Module 연동 방식 var spawn = require('child_process').spawn; var sum = spawn('sum', [...]); sum.stdout.on('data', result => { process(result); ... }); 아마 우리가 원한게 이런것은 아니지 말입니다..

19. 기존의 Native Module 연동 방식 • Node.js C++ Addon • https://nodejs.org/dist/latest-v8.x/docs/api/addons.html • NAN(Native Abstraction for Node) • Node.js C++ Addon이 V8 Public API를 사용하기 때문에 V8 변화에 민감하다. • Node.js를 업데이트 할때마다 문제가 발생하는 것을 해결. • https://github.com/nodejs/nan • N-API ß Latest! • Node.js 8.0이후부터 지원, 8.6에서 Stable Release • NAN과 유사한 방식이지만, ABI-Stable을 보장. (즉, 재컴파일 불필요) • V8 Public API가 아닌 Node.js에서 한번 Wrapping하여 제공하므로 다른 엔진으로 교체도 가능. • https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html

20. N-API에 이르기까지 많은 개선이 있었지만, Binding 코드를 작성하는 것을 위한 개선은 없었다.

21. N-API를 사용하여 Binding 해보자 napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } 다음의 예제는 N-API를 사용하여 Native Binding을 하고 있다. 그러나.. 6줄 짜리 sum()함수가 35줄이 된다.

22. N-API를 사용하여 Binding 해보자 const sum = require(‘sum’); let s = sum([1, 2, 3, 4, 5, 6, 7, 8, 9]); N-API를 사용하여 Binding을 하면 Javascript에서 호출 할 수 있다.

23. 3. 기존의 문제점 파헤치기

24. 지금부터 코드가 많이 나오는데.. 굳이 그 코드들을 이해하실 필요는 없습니다!

25. 문제점1: Argument Check napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); // 문제점1. JS argument는 Runtime에 결정되므로 개발자가 직접 체크해야한다. if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; }

26. 문제점2: Type Checking for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); // 문제점2. 각 Array Element의 Type Checking도 직접해야한다. napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; }

27. 문제점3: Type Converting // 문제점3. JS에서 Native Type Converting을 직접해야한다. double value; napi_get_value_double(env, element, &value); sum += value; } // 문제점3. Native에서 JS Type Converting을 직접해야한다. napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum;

28. uint32_t length = 10000; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); ... } 문제점4: Memory Management napi_value length . . . … 내가 아는 Stack Pop Push

29. uint32_t length = 10000; for (int i = 0; i < length; i++) { // napi_get_element()를 호출할 때마다 // 새로운 object를 생성하고 HandleScope에 // 쌓이게 됨. napi_value element; napi_get_element(env, i, &element); ... } 문제점4: Memory Management napi_value napi_value napi_value napi_value napi_value napi_value … napi_value i = 9999 i = 9998 i = 4 i = 3 i = 2 i = 1 i = 0 HandleScopeStack Heap

30. 문제점4: Memory Management for (int i = 0; i < length; i++) { napi_handle_scope scope; napi_status status = napi_open_handle_scope(env, &scope); napi_value element; napi_get_element(env, i, &element); ... napi_close_handle_scope(env, scope); }

31. 문제점5: Readability napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } int sum(std::vector<int> elements) { int s = 0; for (int i = 0; i < elements.size(); i++) s += elements[i]; return s; } // 문제점5. Binding 코드가 많이 삽입되면서 가독성이 떨어진다.

32. 요약 • 기존의 방법은 TypeChecking/Converting과 같은 노가다를 반복해야 한다. • Memory 관리 Mechanism이 다르고 Binding을 위해 사용되는 API를 다룰 줄 알아야 하므로 V8, N-API, JS, C++과 같은 지식 모두를 필요로 한다. • 전체적인 코드의 복잡도가 증가한다.

33. 4. Chromium에서 Blink와 V8은 어떻게 연결되나?

34. 왜 Chromium을 살펴보나?

35. Chromium은 V8의 또 다른 Embedder이다.

36. ♥ ≡ ♥ Blink (Rendering Engine) V8 (Javascript Engine) Node.js Native Module V8 (Javascript Engine)

37. document.getElementById();

38. <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

39. V8 Engine과 Blink Engine의 관계 V8 Engine Chromium Loader <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

40. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader DOM Parsing <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

41. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing <script> document.getElementById(‘hello’); </script> JS Evaluate <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

42. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate Actually, called document.getElementById(); <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script> <script> document.getElementById(‘hello’); </script>

43. V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script> <script> document.getElementById(‘hello’); </script>

44. <script> document.getElementById(‘hello’); </script> V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate V8 Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Type Checking/Converting Manage Isolate and Context <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

45. <script> document.getElementById(‘hello’); </script> V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate WebIDL Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Auto-generated!! <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

46. V8 Binding이란? • Chromium에서 V8과 Blink를 연결하는 코드이다. • 사용자가 직접 짜지 않고 WebIDL으로부터 자동 생성(auto-generation)된다. • WebIDL은 JS Engine과 Web Engine을 연결하는 Web 표준에 의해 정의된다. • https://heycam.github.io/webidl/ • https://www.w3.org/TR/api-design/

47. 코드레벨로 살펴보는 WebIDL // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); };

48. 코드레벨로 살펴보는 WebIDL // WebIDL [Constructor] interface Calculator { double sum(sequence<long> elements); }; napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } VS

49. 코드레벨로 살펴보는 WebIDL // User’s Native Code class Calculator { public: double Sum(std::vector<int> elements) { int sum = 0; for (int i = 0; i < elements.size(); i++) sum += elements[i]; return sum; } };

50. 코드레벨로 살펴보는 WebIDL // User’s JS code var calculator = new Calculator(); console.log(calculator.sum([1, 2, 3, 4, 5, 6, 7, 8, 9]));

51. 요약 • Chromium에서 V8과 Blink의 관계는 Node.js에서 V8과 Native Module의 관계와 동 등하다. • V8과 Blink를 연결하는 Layer를 V8 Binding(WebIDL Binding)이라고 부른다. • V8 Binding(WebIDL Binding)은 WebIDL을 이용해 Auto-generated 된다.

52. 5. Node.js Native Module과 V8은 어떻게 연결되나?

53. const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

54. V8 Engine과 Native Module의 관계 V8 Engine Node Runtime const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

55. V8 Engine과 Native Module의 관계 V8 Engine V8 Engine Node Runtime JS Evaluate const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

56. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Actually, called open() and read() const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8');

57. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Return JS Wrapper Object const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8'); Actually, called open() and read()

58. V8 Engine과 Native Module의 관계 V8 Engine Native Module V8 Engine V8 Engine Node Runtime JS Evaluate Return JS Wrapper Object V8 Binding Type Checking/Converting Manage Isolate and Context const fs = require('fs'); let contents = fs.readFileSync('temp.txt', 'utf8'); Actually, called open() and read()

59. 복습: N-API를 사용하여 Binding 해보자 napi_value Sum(napi_env, napi_callback_info info) { napi_status status; size_t args = 1; napi_value args[1]; napi_status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (argc < 1) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } uint32_t length = 0; napi_get_array_length(env, args[0], &length); double sum = 0; for (int i = 0; i < length; i++) { napi_value element; napi_get_element(env, i, &element); napi_valuetype valuetype; napi_typeof(env, element, &valuetype); if (napi_valuetype != napi_number) { napi_throw_type_error(env, nullptr, "…"); return nullptr; } double value; napi_get_value_double(env, element, &value); sum += value; } napi_value js_sum; napi_create_double(env, sum, &js_sum); return js_sum; } 이미 우리가 여러번 말했듯이 이러한 과정을 반복한다. 이런식으로 장인 정신을 발휘하면 잘 만들 수 있다!

60. <script> document.getElementById(‘hello’); </script> 복습: V8 Engine과 Blink Engine의 관계 V8 Engine Blink Engine V8 Engine Chromium Loader V8 Engine DOM Parsing JS Evaluate WebIDL Binding Actually, called document.getElementById(); Return JS Wrapper Object let div = document.getElementById(‘hello’); Auto-generated!! <div id="hello"></div> <script> let div = document.getElementById(‘hello’); </script>

61. Node.js에 Auto Binding을 적용한다면.. • IDL을 제외하고는 추가적인 Binding 코드를 직접 작성하지 않아도 된다. • 바인딩 코드와 실제 User Implementation이 완벽히 분리된다. • V8(또는 N-API)을 이해하지 않아도 된다. • 안전하고 빠르게 바인딩할 수 있다.

62. 실제 사례: Open CV Binding // Open CV Matrix를 생성하는 5개의 함수 오버로딩.. let m1 = new Matrix(); let m2 = new Matrix(rows, cols); let m3 = new Matrix(10, 20, CV_32F); let m4 = new Matrix(10, 20, CV_32F, [1, 2, 3]); let m5 = new Matrix(m4, 10, 20, 30, 40);

63. 실제 사례: Open CV Binding // 이 Matrix의 실제 Binding 구현은 다음과 유사하다. // https://github.com/peterbraden/node-opencv/blob/master/src/Matrix.cc#L132 Matrix* mat; if (info.Length() == 0) { mat = new Matrix; } else if (info.Length() == 2 && info[0]->IsInt32() && info[1]->IsInt32()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue()); } else if (info.Length() == 3 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue()); } else if (info.Length() == 4 && info[0]->IsInt32() && info[1]->IsInt32() && info[2]->IsInt32() && info[3]->IsArray()) { mat = new Matrix(info[0]->IntegerValue(), info[1]->IntegerValue(), info[2]->IntegerValue(), info[3]->ToObject()); else { // if (info.Length() == 5) { ... }

64. 실제 사례: Open CV Binding // 만약 WebIDL Binding을 사용했다면.. [ Constructor(), Constructor(long rows, long cols), Constructor(long rows, long cols, long type), Constructor(long rows, long cols, long type, sequence<long> scalar), Constructor(Matrix m, long x, long y, long z, long w) ] interface Matrix { ... };

65. 실제 사례: Open CV Binding // 만약 당신이 WebIDL 고수였다면.. [ Constructor(), Constructor(long rows, long cols, optional long type, optional sequence<long> scalar), Constructor(Matrix m, long x, long y, long z, long w) ] interface Matrix { ... };

66. 요약 • Node.js에서 V8과 Native Module 사이의 Binding은 개발자가 직접 한땀 한땀 개발해 야만 했다. • Chromium에서 사용되는 WebIDL Binding을 도입한다면, 그러한 장인정신을 발휘하 지 않고도 쉽고 빠르게 개발할 수 있다.

67. 6. Node.js를 위한 WebIDL Auto Binding 구현하기

68. What should we do? • WebIDL을 해석한 후 N-API를 사용하는 적절한 Binding 코드를 생성한다.

69. Blink에서 WebIDL이 처리 되는 과정 WebIDL User Native Implementation

70. Blink에서 WebIDL이 처리 되는 과정 WebIDL IDL Parser User Native Implementation Input

71. Blink에서 WebIDL이 처리 되는 과정 WebIDL IDL Parser Binding Code GeneratorInput User Native Implementation

72. Blink에서 WebIDL이 처리 되는 과정 WebIDL Code Template IDL Parser Binding Code GeneratorInput Input User Native Implementation

73. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code GeneratorInput Input Build User Native Implementation

74. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code Generator User Native Implementation Input Input Build Reference

75. Blink에서 WebIDL이 처리 되는 과정 WebIDL Generated Code Based on V8 Code Template IDL Parser Binding Code Generator Output Binary User Native Implementation Input Input Build Build Reference Build

76. What should we do? • IDL Parser를 구현한다. (Front End) • Code Generator를 구현한다. (Back End)

77. How to implement • IDL Parser를 구현한다. (Front End) • 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js • 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다. • Code Generator를 구현한다. (Back End)

78. How to implement • IDL Parser를 구현한다. (Front End) • 이미 잘 구현 된 WebIDL Parser가 있다: https://github.com/w3c/webidl2.js • 우리는 AST(Abstract Syntax Tree)를 IDL Definitions로 만들어 주는 것만 하면 된다. • Code Generator를 구현한다. (Back End) • Python의 Jinja2를 JS로 포팅 한 Nunjucks가 있다: https://github.com/mozilla/nunjucks • 우리는 C++ Binding Code (N-API를 사용한)를 잘 생성해주는 로직을 짜기만 하면 된다.

79. IR (IDL Definitions) • Compiler의 FrontEnd의 역할. IR(Intermediate Representation)을 생성. • Constructing 단계에서 다음의 두가지 요소가 추가적으로 필요함. • Extended attribute validation • Dependency resolution. IDL Parser (Front End) IDL Tokens AST (Abstract Syntax Tree) Lexing Parsing Constructing

80. IDL Parser (Front End) [Constructor] interface Hello { double test(World world); }; [{ type: 'interface', name: 'Hello', partial: false, members: [ [...] ], inheritance: null, extAttrs: [ [...] ] }] [Constructor] interface World { readonly attribute value; }; Dependency Resolution Constructing Parsing [{ ... name: 'Hello', members: [ [{ idlType: 'World’, ... }] ], }]

81. Code Generator (Back End) V8 Engine Native Binding Code IR (IDL Definitions) Contexts Logic Processing Template Processing Code Template • Compiler의 BackEnd의 역할. IR을 Input으로 최종 결과물(binding code) 생성. • 코드 생성을 위해 Nunjucks Template Engine을 사용.

82. Code Generator (Back End) {% for argument in member.arguments %} auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}} >::NativeValue(info.Env(), info[{{loop.index - 1}}]); {% endfor %} {% if member.type != "void" %}auto return_value = {% endif %} {% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %} {{member.name | camelcase}}({{-member.arguments[0].name-}} {%- for i in range(1, member.arguments.length) -%} , {{member.arguments[i].name-}} {% endfor %}); return JSTypeTraits(info.Env(), return_value);

83. Code Generator (Back End) {% for argument in member.arguments %} auto {{argument.name}} = NativeTypeTraits<IDL{{argument.type | camelcase-}} >::NativeValue(info.Env(), info[{{loop.index - 1}}]); {% endfor %} {% if member.type != "void" %}auto return_value = {% endif %} {% if member.is_static -%} {{name}}::{% else %} impl_->{% endif %} {{member.name | camelcase}}({{-member.arguments[0].name-}} {%- for i in range(1, member.arguments.length) -%} , {{member.arguments[i].name-}} {% endfor %}); return JSTypeTraits(info.Env(), return_value);

84. Code Generator (Back End) if (info.Length() != 2) { Napi::RangeError::New(info.Env(), "Invalid").ThrowAsJavaScriptException(); return Napi::Value(); } // 복잡한 Type Mapping 및 Converting은 개발자에게 노출하지 않는다. double number1 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[0]); double number2 = NativeTypeTraits<IDLDouble>::NativeValue(info.Env(), info[1]); // 사용자가 작성한 User Native Implementation을 여기서 호출한다. auto return_value = impl_->Add(number1, number2); return JSTypeTraits(info.Env(), return_value);

85. Code Generator (Back End) class Calculator { public: Calculator() {} // 개발자는 JS Engine의 public API가 어떻게 동작하는지 알 필요가 없다. // WebIDL Spec에 따라 IDL type이 정확한 platform object type과 mapping된다. double Add(double number1, double number2) { return number1 + number2; } }

86. 요약 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다.

87. 7. Bacardi Project

88. Introduce Bacardi Project • Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소 스 프로젝트입니다. • https://github.com/lunchclass/bacardi

89. Introduce Bacardi Project • Node.js에서 Chromium이 사용하는 WebIDL Auto Binding을 적용하기 위한 오픈소 스 프로젝트입니다. • https://github.com/lunchclass/bacardi • Chromium Committer들이 주축으로 만들어 갑니다. zino@chromium.org hwanseung@chromium.org

90. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi

91. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi # If you are using MacOS $ xcode-select –install # If you are using Linux $ sudo apt-get install g++ git make python wget

92. How to test Bacardi # Git clone repository $ git clone https://github.com/lunchclass/bacardi # If you are using MacOS $ xcode-select –install # If you are using Linux $ sudo apt-get install g++ git make python wget # Build & Test $ ./bacardi build && ./bacardi test

93. Details 

• 자세한 것은 Repository를 참조. 

• https://github.com/lunchclass/bacardi 

• 테스트가 아닌 간단한 예제는 examples 디렉토리를 참조. 

https://github.com/lunchclass/bacardi/tree/master/examples

94. Bacardi with Electron # Build for Electron & Run Electron app $ ./bacardi build_electron && ./bacardi electron

95. Bacardi with Electron - SimRank 두 객체의 유사도를 구하는 알고리즘.

96. Bacardi with Electron - SimRank 만약 여러분이 사용하고 싶은 구현이 Node.js에 존재하지 않는다면..

97. Bacardi with Electron - SimRank 구글링(Googling)을 해보니 SimRank의 C++ 구현은 존재한다. 

https://github.com/roukaour/simrank

98. Bacardi with Electron - SimRank

99. Bacardi with Electron - SimRank 이것을 그대로 Javascript로 binding하여 Electron app에 출력해보자. 

https://github.com/lunchclass/bacardi/pull/135 [ Constructor(), Constructor(long k, double c) ] interface ElectronNative { void addEdge(string head, string tail); void calculateSimRank(); double similarity(string node1, string node2); };

100. Bacardi with Electron - SimRank

101. Bacardi with Electron - SimRank

102. Bacardi의 향후 계획

• 2017년 4분기까지 C++ Binding 구현 완료 - NPM 배포 

• OpenCV & Tensor Flow Binding Bacardi로 옮기기 

• Cross Platform Build 지원 

• Welcome to contribution (https://github.com/lunchclass/bacardi)

Bacardi project is an effort to provide multi-language binding for Node.js native layer.

103. 요약

 • Node.js에 WebIDL Binding을 구현하기 위해서는 IDL Parser와 Code Generator 두 가지를 구현해야 한다. 

• 모두가 같은 노력을 할 필요 없으므로 오픈소스 프로젝트(Bacardi Project)로 진행중이 며, 이를 Node.js Native Module 개발에 활용할 수 있다.

104. 8. Binding 성능에 관한 이야기

105. Native가 JS보다 느릴 수도 있다 

• V8은 매우 빠르다. 

• V8과 Native Addon을 연결하는 Binding은 생각보다 Overhead가 있다. 

• Chromium에서 하드웨어 가속을 써서 ASM + C++을 사용한 Matrix의 구현보다 Pure JS의 구현이 10배 이상 더 빠르다. (관련링크: https://groups.google.com/a/chromium.org/d/msg/blink-dev/V_bJNtOg0oM/lECG9SikFwEJ) V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation

106. Native가 JS보다 느릴 수도 있다

107. Native가 JS보다 느릴 수도 있다 

• Matrix 계산이 Binding Layer를 지나기 위한 Overhead보다 작기 때문에 발생 

• 어떤 연산이 Binding Layer의 Overhead보다 작고 빈번히 호출이 된다면 JS가 더 빠를 수도 있다. V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation 이 Layer를 많이 지나다닐 수록 성능은 떨어집니다!

108. 이것을 개선하려면? 

• 가능하면 한 쪽 World에서 머무르도록 한다. 

• uftrace와 같은 프로파일링 툴을 통해 실제 빈번하게 호출되는 지점을 찾을 수 있음. 

https://github.com/namhyung/uftrace V8 Engine Native ModuleV8 Engine V8 Binding Standalone JS Implementation Native Implementation 이 Layer를 가능하면 적게 지나다니는 것이 Key Point

109. uftrace를 사용한 call-graph 추적

110. uftrace를 사용한 call-graph 추적 Native Type Converting을 위해 Type Checking을 반 복적으로 하고 있음을 알 수 있음.

111. No Type Checking // Binding Overhead를 줄이기 위해 NoTypeChecking이라는 Extended Attribute를 추가할 수 있다. interface PerformanceTest { [NoTypeChecking] long fibonacci(long n); };

112. No Type Checking // 그러면 Native Code를 생성할 때 TypeChecking을 생략할 수 있다. // 어떤 Input이 들어올지가 명확하고 예상가능한 경우에 사용할 수 있다. if (!js_value.IsNumber()) { Napi::TypeError::New(env, "Invalid").ThrowAsJavaScriptException(); return Napi::Value(); } ASSERT(info[0].isNumber()); long n = js_value.ToNumber().DoubleValue();

113. Dictionary Key Caching 

• JSObject에 Value를 읽거나 Key값을 체크할 때, napi_has_named_property() 또는 napi_has_property()를 사용할 수 있다. 

https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_property 

https://nodejs.org/dist/latest-v8.x/docs/api/n-api.html#n_api_napi_has_named_property 

• napi_has_named_property() 함수는 napi_has_property()와는 달리 Native String을 JS String으로 변환해야 하므로 상대적으로 비싼 연산이다. 

• 이 문제를 개선하기 위해서 어떤 Object에 Value를 읽거나 Key값을 체크할 때 생성한 JSString을 Native World에서 Caching할 수 있다.

114. Q & A

115. Thank you



...

반응형
반응형
RabbitMQ, PHP, Node.js를 활용해 GCM push 처리하기

http://blog.hkwon.me/rabbitmq-php-node-jsreul-hwalyonghae-gcm-push-ceorihagi/
반응형
반응형

[javascript] 요즘 웹페이지에서 영상 플레이시 스크롤이 플레이어를 지나가면 레이어팝업으로 따라가는 스크립트. 


페이스북에서도 영상 플레이하면 스크롤 되었을때 좌측 상단에 레이어로 따라오더라. 

JTBC 뉴스 페이지에서 그렇게 나오길래 보니 jwPlayer를 사용하고 있다. 




jQuery로 적용되어있다. document.ready 에서 window.on('scroll',fun~~~  로 스크롤시 고정 플레이어의 위치를 확인해서 플레이어의 top을 벗어나면 플레이어 사이즈를 변경하고 우측 하단에 bottom 100px, right 50px 주고 fixed 하는 것으로 되어있네. 멋짐. ㅎㅎ 


영상을 보면서 들으면 지문을 읽을 수 있어서 좋다. 








...

반응형
반응형

[javascript] Nuxt.js란 무엇인가?


가이드 : https://ko.nuxtjs.org/guide


GitHub : https://github.com/nuxt/nuxtjs.org


Nuxt.js란 무엇인가?

Nuxt.js는 범용 Vue.js 애플리케이션을 만들기 위한 프레임워크로, 주요 범위는 클라이언트/서버 배포를 추상화하면서 UI 렌더링 을 하는 것입니다.

우리의 목표는 Nuxt.js를 기반 프로젝트로 하거나 Node.js 기반의 프로젝트에 추가해서 사용할 수 있도록 충분히 유연한 프레임워크를 만드는 것입니다.

Nuxt.js는 더 즐거운 서버 사이드 렌더링 Vue.js 애플리케이션 개발을 위해 필요한 모든 설정들이 미리 준비되어 있습니다.

또한 우리는 nuxt generate 라고 부르는 배포 옵션을 제공하며, 이는 Vue.js 애플리케이션을 정적으로 생성 하는 옵션입니다. 이 옵션이 마이크로 서비스를 지향하는 웹 애플리케이션 개발의 다음 단계가 될 수 있다고 생각합니다.

Nuxt.js 프레임워크는 비동기 데이터, 미들웨어, 레이아웃 등과 같이 클라이언트 측과 서버 측 사이에서 개발하는데 도움되는 많은 기능을 제공합니다.

어떻게 동작합니까?

Vue with Webpack and Babel

Nuxt.js는 훌륭한 웹 애플리케이션을 만들기 위해 아래의 기능들을 포함합니다:

총 용량은 28kb min+gzip 밖에 되지 않습니다. (vuex를 포함하면 31kb입니다.)

vue-loader와 babel-loader와 함께 Webpack을 사용해서 코드를 묶고, 분할하며, 압축합니다.

특징

  • Vue 파일 작성
  • 코드 분할 자동화
  • 서버 사이드 렌더링
  • 비동기 데이터 기반의 강력한 라우팅 시스템
  • 정적 파일 전송
  • ES6/ES7 지원
  • JS & CSS 코드 번들링 및 압축
  • HTML head 태그 관리
  • 개발 단계에서 핫 리로딩 사용하기
  • 전 처리기 지원: SASS, LESS, Stylus 등

구조

아래의 구조는 <nuxt-link>를 서버가 호출하거나 이를 통해 사용자가 이동한 경우, nuxt.js가 어떻게 동작하는지를 보여줍니다:

nuxt-schema




...

반응형

+ Recent posts