블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2017. 11. 15. 16:31 Meteor/Angular + Meteor

Angular CLI와 Meteor를 분리하고, Meteor를 단순히 API 서버로 사용하면서 Angular CLI는 Webpack Dev Server를 통해 4200 port로 브라우져에서 접속하면 Meteor Client는  3000 port를 통해 Meteor Server와 DDP 통신을 한다. (이전 블로그 참조) 이번에는 외부 라이브러리로 Clarity CSS Framework을 추가해 본다. 





Clarity CSS Framework


Twitter Bootstrap 처럼 CSS Framework이지만, clarity-ui, clarity-icon, clarity-angular 3개의 파트로 구분된다. clarity-ui는 css만 존재하고, clarity-icon은 이름처럼 아이콘에 관련된 부분이며, clarity-angular는 Angular 컴포넌트를 제공한다. 


  - Clarity 홈페이지

  - Clarity 소스

  - Clarity Seed 소스


// 아이콘 관련

$ npm install clarity-icons --save

$ npm install @webcomponents/custom-elements@1.0.0 --save


// UI CSS

$ npm install clarity-ui --save


// Angular 컴포넌트 

$ npm install clarity-angular --save


Clarity-Angular는 ngModule에서 import를 하면되고 나머지는 아래 장의 설명처럼 ng eject 이전 상태라면 angular-cli.json 에 설정하고, ng eject가 되었다면 webpack.config.js에 설정한다. 

// 메인 모듈

import { ClarityModule } from 'clarity-angular';


@NgModule({

imports: [

BrowserModule,

ClarityModule.forRoot()

],

...

})

export class AppModule {} 





@angular/cli 설정을 webpack.config.js로 옮기기


Clarity Seed를 보면 @angular/cli 기반으로 생성되어 있고, angluar-cli.json 안에 설정이 다음과 같이 되어있다. 진행중인 프로젝트에 Clarity icons, ui에 대한 외부 경로 설정을 한다. 

"styles": [
"styles.css",
"../node_modules/clarity-icons/clarity-icons.min.css",
"../node_modules/clarity-ui/clarity-ui.min.css"
],
"scripts": [
"../node_modules/@webcomponents/custom-elements/custom-elements.min.js",
"../node_modules/clarity-icons/clarity-icons.min.js"
],


해당 설정을 이전강좌의 Angular CLI + Meteor 프로젝트의 angular-cli.json을 넣고 ng eject를 하게 되면 다음과 같은 내용이 webpack.config.js에 자동 설정된다. 

  - Module안에 "exclude"와 "include"의 "src/styles.css"이 있는 모든 곳에 설정.

  - Plugin안에 new ConcatPlugin내용 추가

"module": {

{

"exclude": [

path.join(process.cwd(), "src/styles.css"),

path.join(process.cwd(), "node_modules/clarity-icons/clarity-icons.min.css"),

path.join(process.cwd(), "node_modules/clarity-ui/clarity-ui.min.css")

]

...

},

{

"include": [

path.join(process.cwd(), "src/styles.css"),

path.join(process.cwd(), "node_modules/clarity-icons/clarity-icons.min.css"),

path.join(process.cwd(), "node_modules/clarity-ui/clarity-ui.min.css")

]

...

}

...

},

"plugins": [

new ConcatPlugin({

"uglify": false,

"sourceMap": true,

"name": "scripts",

"fileName": "[name].bundle.js",

"fileToConcat": [

"node_modules/@webcomponents/custsom-elements/custom-elements.min.js",

"node_modules/clarity-icons/clarity-icons.min.js"

]

})

]





Clarity 테스트


Clarity CSS Framework은 업무적으로 요하는 컴포넌트 요소를 잘 정리해 놓았다. Application Layout에 대한 내역을 app.component.html에 추가한다. 

<div class="main-container">
<div class="alert alert-app-level">
Alert
</div>
<header class="header header-6">
Angular Meteor
</header>
<nav class="subnav">
Navigation
</nav>
<div class="content-container">
<div class="content-area">
Main
</div>
<nav class="sidenav">
Side Menu
</nav>
</div>
</div>


결과 화면





Clarity Icon 선택적으로 적용하기


plugins부분에 clarity-icons/clarity-icons.min.js 은 전체 아이콘을 포함하고 있다. 전체을 적용하지 않고, Core와 일부분만 적용하고 싶을 경우 다음과 같이 한다. 


// webpack.config.js에서 clarity-icons.min.js 제거

"plugins": [

new ConcatPlugin({

"uglify": false,

"sourceMap": true,

"name": "scripts",

"fileName": "[name].bundle.js",

"fileToConcat": [

"node_modules/@webcomponents/custsom-elements/custom-elements.min.js"

]

})

]


src/main.ts안에 import

import 'clarity-icons';
import 'clarity-icons/shapes/essential-shapes';
import 'clarity-icons/shapes/technology-shapes';


app.component.html안에 clr-icon 적용 테스트. 자세한 사항은 문서를 참조한다. Clarity-icons은  svg icon으로 사용자 정의 아이콘을 추가 할 수도 있다.

<div class="content-area">
<p><clr-icon shape="user" size="24"></clr-icon> lives in the Core Shapes set.</p>
<p><clr-icon shape="pencil" size="24"></clr-icon> lives in the Essential Shapes set.</p>
<p><clr-icon shape="tablet" size="24"></clr-icon> lives in the Technology Shapes set.</p>
</div>


posted by 윤영식
2017. 11. 8. 17:20 Meteor/Angular + Meteor

Ionic CLI 와 Meteor CLI 로 프로젝트 구성하기는 모바일 프로젝트를 진행할 때 사용하면 되고, 이번에는 Angular CLI 와 Meteor CLI를 통해 프로젝트 구성을 어떻게 하는지 살펴본다. 




Webpack 기반 프로젝트 초기화


Angular CLI를 통해 프로젝트를 생성한다. @angular/cli v1.5.0이 설치되고, webpack은 v3.8.1 이고, 내부적으로 @angular-devkit, @ngtools/webpack, @schematics등이 사용된다.

$ npm install -g @angular/cli


@angular/CLI 설치후 프로젝트를 생성한다. ng <command>의 상세 내용은 위키를 참조한다.

$ ng new <projectName>


Webpack 환경파일을 수정해야 하므로, eject 명령을 수행하고, 결과로 출력된 가이드에 따라 "npm install" 명령을 수행한다. eject 명령에 대한 다양한 options은 위키를 참조한다. eject시에 옵션을 주면 옵션이 적용된 webpack.config.js가 생성된다.

$ ng eject --aot --watch


====================================================

Ejection was successful.


To run your builds, you now need to do the following commands:

   - "npm run build" to build.

   - "npm test" to run unit tests.

   - "npm start" to serve the app using webpack-dev-server.

   - "npm run e2e" to run protractor.


Running the equivalent CLI commands will result in an error.

====================================================

Some packages were added. Please run "npm install".


$ npm install

$ npm run build


eject를 수행한 경우에는 "ng serve" 명령으로 테스트 서버를 뛰울 수 없다. package.json에 적용된 스크립트인 "npm start"를 수행하고 4200 port로 브라우져에서 

$ npm start


 10% building modules 3/3 modules 0 activeProject is running at http://localhost:4200/

webpack output is served from /

....


Webpack 환경 내역은 크게 entry, output, module (for loader), plugins 로 구성된다. (참조)

  - entry: 파일 위치

  - output: 결과 위치

  - module: css, .ts, .html 파일 관리 및 변환기 -> 자바스크립트 모듈로 만들기 위한 것. postfix가 "-loader" 이다. 로더는 파일단위 처리

  - plugins: 압축, 핫로딩, 복사, 옮기기등. 플러그인은 번들된 결과물을 처리





Angular CLI 환경에 Meteor 설정



이전 포스트처럼 루트에 api 폴더를 만들고 이를 Meteor의 백앤드로 사용토록 설정한다.

// webpack.config.js


const webpack = require('webpack');

...

resolve: {

  alias: {

    'api': path.resovle(__dirname, 'api/server'),

    ...

  }

}


externals: [ resolveExternals ],


plugins: [ ..., new webpack.ProvidePlugin({ __extends: 'typescript-extends' }) ],


node: { ..., __dirname: true }


// 맨 마지막에 넣음 

function resolveExternals(context, request, callback) {

  return resolveMeteor(request, callback) ||

    callback();

}

 

function resolveMeteor(request, callback) {

  var match = request.match(/^meteor\/(.+)$/);

  var pack = match && match[1];

 

  if (pack) {

    callback(null, 'Package["' + pack + '"]');

    return true;

  }

}


루트에 있는 tsconfig.json에 Meteor 백앤드 관련 내용을 추가한다.

"compilerOptions: {

"baseUrl": ".",

"module": "commonjs",

...

"skipLibCheck": true,

"stripInternal": true,

"noImplicitAny": false,

"types": [ "@types/meteor" ]

},

"include": [ ..., "api/**/*.ts" ],

"exclude": [ ..., "api/node_modules", "api" ]


src/tsconfig.app.json과 tsconfig.spec.json안에 api에 대한 exclude도 설정해야 한다.

// src/tsconfig.app.json

"exclude": [

   ...,

   "../api/node_modules"

]


// src/tsconfig.spec.json

"exclude": [ "../api/node_modules" ]


관련 패키지를 설치한다.

$ npm install --save-dev typescript-extends

$ npm install --save-dev @types/meteor

$ npm install --save-dev tmp




Meteor Server API 생성 및 설정


Meteor CLI를 설치하고 api 명으로 Meteor 프로젝트를 생성한다.

$ curl https://install.meteor.com/ | sh

$ meteor create api


api 폴더 밑의 필요없는 폴더를 삭제하고 루트에 있는 것으로 대체한다.

$ cd api

// 삭제

api$ rm -rf node_modules client package.json package-lock.json


// 심볼릭 링크

api$ ln -s ../package.json

api$ ln -s ../package-lock.json

api$ ln -s ../node_modules

api$ ln -s ../src/declarations.d.ts


Meteor 백앤드를 Typescript 기반으로 개발하기 위한 패키지를 설치한다.

api$ meteor add barbatus:typescript


api$ cd ..

$ npm install --save babel-runtime

$ npm install --save meteor-node-stubs

$ npm install --save meteor-rxjs


Typescript의 tsconfig.json 파일을 api 폴더안에 생성하고 다음 내역을 붙여넣는다.

{

  "compilerOptions": {

    "allowSyntheticDefaultImports": true,

    "declaration": false,

    "emitDecoratorMetadata": true,

    "experimentalDecorators": true,

    "lib": [

      "dom",

      "es2017"

    ],

    "module": "commonjs",

    "moduleResolution": "node",

    "sourceMap": true,

    "target": "es6",

    "skipLibCheck": true,

    "stripInternal": true,

    "noImplicitAny": false,

    "types": [

      "@types/meteor"

    ]

  },

  "exclude": [

    "node_modules"

  ],

  "compileOnSave": false,

  "atom": {

    "rewriteTsconfig": false

  }

}


Meteor의 server/main.js를 main.ts로 바꾼다. 위에서 설치한 meteor-rxjs는 클라이언트단의 Meteor를 RxJS Observable기반으로 사용할 수 있도록 한다.

// 예) Meteor 클라이언트단 Collection 구성

import { MongoObservable } from 'meteor-rxjs';


export const Chats = new MongoObservable.Collection('chats');




Meteor Client 준비


Meteor Server <-> Client 연동을 위해 Client를 Bundling한다.

$ sudo npm install -g meteor-client-bundler


번들링시에 Meteor Server 기본 주소는 localhost:3000 으로 설정된다. Meteor Client는 DDP를 이용하기 때문에 번들할 때 --config 옵션 또는 --url 옵션으로 Meteor Server 위치를 지정한다.  -s 옵션을 주면 Client<->Server 같은 버전의 패키지를 사용하고 -s 옵션을 주지않으면 config 설정내용을 참조한다. (참조)

$ meteor-client bundle --destination meteor.bundle.js --config bundler.config.json


// config file

{ "release": "1.6", "runtime": { "DDP_DEFAULT_CONNECTION_URL": "http://1.0.0.127:8100" }, "import": [ "accounts-base", "mys:accounts-phone", "jalik:ufs@0.7.1_1", "jalik:ufs-gridfs@0.1.4" ] }


package.json에 번들링 명령을 등록하고 수행한다. 

"scripts": {

   ...,

   "meteor-client:bundle": "meteor-client bundle -s api"

}


//번들링 - 최초 한번만 수행한다.

$ npm run meteor-client:bundle


Angular 클라이언트에서 Meteor Client를 사용하기 위해 src/main.ts에서 "meteor-client"를 import한다.

import "meteor-client";




Collection 생성하고 Meteor 기능 사용 테스트


api/server 에 model을 하나 만든다. Angular와 Meteor가 같이 사용하는 모델 타입이다.

// api/server/models.ts

export enum MessageType {

  TEXT = <any>'text'

}


export interface Chat {

  _id?: string;

  title?: string;

  picture?: string;

  lastMessage?: Message;

  memberIds?: string[];

}


export interface Message {

  _id?: string;

  chatId?: string;

  senderId?: string;

  content?: string;

  createdAt?: Date;

  type?: MessageType;

  ownership?: string;

}


api/server/collections 폴더를 생성하고 Chat 컬렉션을 생성한다. meteor-rxjs 는 RxJS로 Mongo Client를 wrapping해 놓은 것으로 Rx방식으로 Mongo Client를 사용할 수 있게 한다.

// api/server/collections/chats.ts

import { MongoObservable } from 'meteor-rxjs';

import { Chat } from '../models';


export const Chats = new MongoObservable.Collection<Chat>('chats'); 


// api/server/collections/messages.ts

import { MongoObservable } from 'meteor-rxjs';

import { Message } from '../models';


export const Messages = new MongoObservable.Collection<Message>('messages');


api/server/main.ts안에 샘플 데이터를 넣는다.

$ npm install --save moment


// api/server/main.ts

import { Meteor } from 'meteor/meteor';

import { Chats } from './collections/chats';

import { Messages } from './collections/messages';

import * as moment from 'moment';

import { MessageType } from './models';


Meteor.startup(() => {

  // code to run on server at startup

  if (Chats.find({}).cursor.count() === 0) {

    let chatId;


    chatId = Chats.collection.insert({

      title: 'Ethan Gonzalez',

      picture: 'https://randomuser.me/api/portraits/thumb/men/1.jpg'

    });


    Messages.collection.insert({

      chatId: chatId,

      content: 'You on your way?',

      createdAt: moment().subtract(1, 'hours').toDate(),

      type: MessageType.TEXT

    });


    chatId = Chats.collection.insert({

      title: 'Bryan Wallace',

      picture: 'https://randomuser.me/api/portraits/thumb/lego/1.jpg'

    });


    Messages.collection.insert({

      chatId: chatId,

      content: 'Hey, it\'s me',

      createdAt: moment().subtract(2, 'hours').toDate(),

      type: MessageType.TEXT

    });

  }

});


다음으로 Angular에 Chat 컬렉션을 사용한다.

// src/app/app.component.ts

import { Component, OnInit } from '@angular/core';

import { Chats } from '../../api/server/collections/chats';

import { Chat } from '../../api/server/models';


@Component({

  selector: 'app-root',

  templateUrl: './app.component.html',

  styleUrls: ['./app.component.css']

})

export class AppComponent implements OnInit {

  title = 'app';

  chats: Chat[];

  ngOnInit() {

    Chats.find({}).subscribe((chats: Chat[]) => this.chats = chats );

  }

}


// src/app/app.component.html 에 추가

<div> {{ chats | json }} </div>




Angular & Meteor 기동


Meteor 기동

$ cd api

api$ meteor


Angular 기동

$ npm start


Webpack dev server는 4200이고meteor client는 server에 websocket 3000 port로 접속을 한다. Meteor 의 mongo로 접속해서 chats collection을 확인해 본다.

$ meteor mongo

MongoDB shell version: 3.2.15

connecting to: 127.0.0.1:3001/meteor

Welcome to the MongoDB shell.

For interactive help, type "help".

For more comprehensive documentation, see

http://docs.mongodb.org/

Questions? Try the support group

http://groups.google.com/group/mongodb-user

meteor:PRIMARY> show collections

chats

messages



하단에 Chat 내역이 json 형식으로 출력된다.




<참조>


- Webpack v3 환경설정 요약

- Meteor Client bundler의 작도방식 by Uri

- Meteor Client Bundler Github


posted by 윤영식
2017. 11. 6. 15:57 Meteor/Angular + Meteor

angular-meteor.com의 Socially Merge를 따라하며 내용을 요약해 보았다. socially merge는 meteorionic의 조합을 webpack으로 묶어 프로젝트를 구성해보는 과정이다. 여기서 익힐 수 있는 것은 Angular 로 작성된 ionic을 프론트앤드로 사용하고 metetor를 백앤드로 구성하는 방법을 배울 수 있다.




Webpack 기반 프로젝트 초기화


meteor와 ionic는 서로의 CLI를 제공한다. ionic을 먼저 설정한다.

$ npm install -g ionic cordova


초기 프로젝트 구성을 ionic CLI를 통해 생성한다.

ionic start whatsapp blank --cordova --skip-link

...

? Install the free Ionic Pro SDK and connect your app? (Y/n) n


$ cd whatsapp

$ ionic serve


Ionic은 Angular를 사용하기 때문에 Typescript 최신버전을 설치한다.

$ npm install --save typescript


타입스크립트기반에서 외부라이브러리를 사용하기 위해서 src/declarations.d.ts 파일을 생성해 놓는다. d.ts작성법은 공식문서를 참조한다. 다음으로 Ionic 3가 Webpack을 기반으로 빌드되는 설정을 package.json에 추가한다.

//  package.json

"config": {

    "ionic_webpack": "./webpack.config.js"

}


Ionic은 webpack config에 대한 샘플 파일을 제공하고 이를 복사한다. webpack.config.js안에는 dev와 prod환경 기본값이 설정되어 있다.

$ cp node_modules/@ionic/app-scripts/config/webpack.config.js .




Ionic 에 Meteor 설정


프로젝트 폴더의 루트에 api 폴더를 만들고 이를 Meteor의 백앤드로 사용하는 설정을 webpack.config.js에 한다. meteor 관련된 것은 external로 취급하는 것 같다.

// dev, prod양쪽에 넣는다.

resolve: {

...

alias: {

'api': path.resolve(__dirname, 'api/server')

}

},


externals: [ resolveExternals ],


plugins: [ ..., new webpack.ProvidePlugin({ __extends: 'typescript-extends' }) ],


node: { ..., __dirname: true }


// 맨 마지막에 넣음 

function resolveExternals(context, request, callback) {

  return resolveMeteor(request, callback) ||

    callback();

}

 

function resolveMeteor(request, callback) {

  var match = request.match(/^meteor\/(.+)$/);

  var pack = match && match[1];

 

  if (pack) {

    callback(null, 'Package["' + pack + '"]');

    return true;

  }

}


다음으로 Meteor를 외부 의존하는 것으로 tsconfig.json에 Meteor관련 내용을 추가한다.

"compilerOptions": {

  "baseUrl": ".",

  "modules": "commonjs",

  "paths": { "api/*": ["./api/server/*"],

  ...,

  "skipLibCheck": true,

  "stripInternal": true,

  "noImplicitAny": false,

  "types": [

      "@types/meteor"

  ] 

},

"include": [ ..., "api/**/*.ts" ],

"exclude": [ ..., "api/node_modules", "api" ]


typescript-extends 패키지와 meteor 타입 패키지를 설치한다.

$ npm install --save-dev typescript-extends

$ npm install --save-dev @types/meteor


Ionic serve를 실행하고 브라우져의 console을 보면 다음 오류가 나온다. 이를 위해 src/app/app.component.ts에 cordova 설정을 한다.

// Chrome devtools 메세지

Native: tried calling StatusBar.styleDefault, but Cordova is not available. Make sure to include cordova.js or run in a device/simulator


// src/app/app.component.ts 설정




Meteor Server 생성 및 설정


Ionic의 webpack과 tsconfig안에 Meteor 서버 설정을 했고, Meteor CLI를 이용해 백앤드를 구성한다.

// 미티어 설치

$ curl https://install.meteor.com/ | sh


// api 폴더 미티어 초기화

$ meteor create api


api 폴더 밑으로 생성된 node_modules, client 폴더를 삭제하고, package.json, package-lock.json 파일도 삭제한다.

$ rm -rf api/node_modules

$ rm -rf api/client

$ rm api/package.json

$ rm api/package-lock.json


Meteor에서 사용하는 것을 Ionic 으로 심볼릭 링크를 건다.

$ cd api

api$ ln -s ../package.json

api$ ln -s ../pack-lock.json

api$ ln -s ../node_modules

api$ ln -s ../src/declarations.d.ts


Meteor 백앤드를 Typescript기반으로 개발하기 위해 다음 패키지를 설치한다.

api$ meteor add barbatus:typescript


// 별도 필요 패키지 설치 

$ npm install --save babel-runtime

$ npm install --save meteor-node-stubs

$ npm install --save meteor-rxjs


Typescript의 tsconfig.json 파일을 api 폴더안에 생성하고 다음 내역을 붙여넣는다.

{

  "compilerOptions": {

    "allowSyntheticDefaultImports": true,

    "declaration": false,

    "emitDecoratorMetadata": true,

    "experimentalDecorators": true,

    "lib": [

      "dom",

      "es2015"

    ],

    "module": "commonjs",

    "moduleResolution": "node",

    "sourceMap": true,

    "target": "es5",

    "skipLibCheck": true,

    "stripInternal": true,

    "noImplicitAny": false,

    "types": [

      "@types/meteor"

    ]

  },

  "exclude": [

    "node_modules"

  ],

  "compileOnSave": false,

  "atom": {

    "rewriteTsconfig": false

  }

}


Meteor의 server/main.js를 main.ts로 바꾼다. 위에서 설치한 meteor-rxjs는 클라이언트단의 Meteor를 RxJS Observable기반으로 사용할 수 있도록 한다.

// 예) Meteor 클라이언트단 Collection 구성

import { MongoObservable } from 'meteor-rxjs';


export const Chats = new MongoObservable.Collection('chats');




Meteor Client 준비


Meteor Server에 접속하기 위해 Meteor Client가 필요하기 때문에 하나의 bundler로 만들어 import해서 사용한다. 번들링도구를 설치한다.

$ sudo npm install -g meteor-client-bundler


// 필요 패키지를 설치

$ npm install --save-dev tmp


package.json 에 번들링 명령어를 설정하고, 번들링 명령을 수행한다.

// package.json

"scripts": {

...,

"meteor-client:bundle": "meteor-client bundle -s api"

}


// 번들링

$ npm run meteor-client:bundle


클라이언트 main.ts에 번들 내역을 import한다. 

// src/app/main.ts

import "meteor-client";




Ionic & Meteor 기동


Ionic 기동

$ ionic serve


Meteor 기동

$ cd api

api$ meteor


ionic HTTP는 8100이고, meteor client는 server에 websocket 3000 port로 접속을 한다.


posted by 윤영식
prev 1 next