2. METEOR DOCKER 환경 ( 윈도우10 기준 )
• 단비 기본 도커환경을 우선 사용
• Jams777/meteor-tutorial 이미지를 kitematic 에서 다운로드
• Port 는 3000 : 3000 셋팅
• Port 는 3001 : 3001 셋팅 ( 몽고디비 )
• 쉘은 bash 로 함
• Vscode 에서 도커에 직접 연결해서 사용
• Vscode Remote – Containers 확장 기능 사용
4. METEOR 프로젝트 생성
• 튜토리얼 페이지 접속
• https://react-tutorial.meteor.com/simple-todos/01-creating-app.html
• 설치는 도커라 패스
• 도커환경 bash shell 실행(exec)
• 프로젝트 생성
• meteor create --react . 현재폴더에 생성
5. VSCODE 도커 연결
• Vscode Remote – Containers 설치
• F1 클릭 후 Remote-Containers: Attach to Running Container..
• meteor-tutorial 이미지 선택 ( jams777/meteor-tutorial )
• 폴더 열기 버튼 클릭
• /app/web 선택
17. 할일 컬렉션 생성 ( RDB테이블 같은것 )
• 파일 생성 imports/api/TasksCollection.js
import { Mongo } from 'meteor/mongo';
export const TasksCollection = new Mongo.Collection('tasks’);
18. 할일 샘플 데이터 임시 생성
• 파일 수정 server/main.js
import { Meteor } from 'meteor/meteor';
import { TasksCollection } from '/imports/api/TasksCollection';
// 추가 함수
const insertTask = taskText => TasksCollection.insert({ text: taskText });
Meteor.startup(() => {
// 데이터 없을때 7개 생성
if (TasksCollection.find().count() === 0) {
[
'First Task',
'Second Task',
'Third Task',
'Fourth Task',
'Fifth Task',
'Sixth Task',
'Seventh Task'
].forEach(insertTask)
}
});
19. 화면에 데이터 연동 모듈 설치
• meteor add react-meteor-data
• React hook 를 사용한다고 함 ( https://reactjs.org/docs/hooks-faq.html )
20. REACT 할일 DB 데이터 화면 표시
• 파일 수정 imports/ui/App.jsx
import React from 'react';
import { useTracker } from 'meteor/react-meteor-data'; // 여기추가
import { TasksCollection } from '/imports/api/TasksCollection'; // 여기추가
import { Task } from './Task';
// 삭제
const tasks = [
{_id: 1, text: 'First Task'},
{_id: 2, text: 'Second Task'},
{_id: 3, text: 'Third Task'},
];
export const App = () => {
const tasks = useTracker(() => TasksCollection.find({}).fetch()); // 여기추가
return (
<div>
<h1>Welcome to Meteor!</h1>
<ul>
{ tasks.map(task => <Task key={ task._id } task={ task }/>) }
</ul>
</div>
);
};
60. 할일의 사용자 정보 같이 입력
• 기존 정보 삭제
• db.tasks.remove({});
61. 할일의 사용자 정보 같이 입력
• 파일 수정 server/main.js
....
const insertTask = (taskText, user) =>
TasksCollection.insert({
text: taskText,
userId: user._id,
createdAt: new Date(),
});
....
Meteor.startup(() => {
....
}
const user = Accounts.findUserByUsername(SEED_USERNAME);
// 데이터 없을때 7개 생성
if (TasksCollection.find().count() === 0) {
[ ……
].forEach(taskText => insertTask(taskText, user));
}
....
62. 할일의 사용자 정보 처리
• 파일 수정 imports/ui/App.jsx
....
const hideCompletedFilter = { isChecked: { $ne: true } };
const userFilter = user ? { userId: user._id } : {};
const pendingOnlyFilter = { ...hideCompletedFilter, ...userFilt
er };
const tasks = useTracker(() => {
if (!user) {
return [];
}
return TasksCollection.find(
hideCompleted ? pendingOnlyFilter : userFilter,
{
sort: { createdAt: -1 },
}
).fetch();
});
const pendingTasksCount = useTracker(() => {
if (!user) {
return 0;
}
return TasksCollection.find(pendingOnlyFilter).count();
});
....
<TaskForm user={user} />
....
63. 할일의 사용자 정보 처리
• 파일 수정 imports/ui/TaskForm.jsx
....
export const TaskForm = ({ user }) => {
....
TasksCollection.insert({
text: text.trim(),
createdAt: new Date(),
userId: user._id
});
setText("");
};
return (
....
68. 할일 데이터 관리 백엔드 서비스로
• https://react-tutorial.meteor.com/simple-todos/08-methods.html
• 화면에서 데이터 베이스 접속안되게
• meteor remove insecure
• 백엔드 서비스로 할일 관리 함수 변경
• 화면에서 Meteor.call 로 호출하기
• Optimistic UI ( https://blog.meteor.com/optimistic-ui-with-meteor-67b5a78c3fcf )
• 조회는 미니몽고에서
69. 할일 데이터 관리 백엔드 서비스
• 파일 생성 imports/api/tasksMethods.js
import { check } from 'meteor/check';
import { TasksCollection } from './TasksCollection';
Meteor.methods({
'tasks.insert'(text) {
check(text, String);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
TasksCollection.insert({
text,
createdAt: new Date,
userId: this.userId,
})
},
'tasks.remove'(taskId) {
check(taskId, String);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
TasksCollection.remove(taskId);
},
'tasks.setIsChecked'(taskId, isChecked) {
check(taskId, String);
check(isChecked, Boolean);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
TasksCollection.update(taskId, {
$set: {
isChecked
}
});
}
});
70. 할일 데이터 관리 백엔드 서비스 등록
• 파일 수정 server/main.js
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { TasksCollection } from '/imports/db/TasksCollection';
import '/imports/api/tasksMethods';
....
71. 할일 데이터 관리 서비스 호출
• 파일 수정 imports/ui/TaskForm.jsx
import { Meteor } from 'meteor/meteor';
import React, { useState } from 'react';
// import { TasksCollection } from '/imports/api/TasksCollection'; // 이제 사용안함
export const TaskForm = () => { // 이제 사용자 안받음
const [text, setText] = useState("");
// 추가
const handleSubmit = e => {
e.preventDefault();
if (!text) return;
// 백엔드 호출로 변경
Meteor.call('tasks.insert', text);
setText("");
};
return (
....
72. 할일 데이터 관리 서비스 호출
• 파일 수정 imports/ui/App.jsx
import { Meteor } from 'meteor/meteor';
import React, { useState, Fragment } from 'react';
……
const toggleChecked = ({ _id, isChecked }) => {
Meteor.call('tasks.setIsChecked', _id, !isChecked);
};
const deleteTask = ({ _id }) => Meteor.call('tasks.remove', _id);
const logout = () => Meteor.logout();
……
<TaskForm />
…..
73. 할일 데이터 연결 함수 폴더 변경
• 파일 수정 imports/api/tasksMethods.js
• 파일 수정 imports/ui/TaskForm.jsx
• 파일 수정 server/main.js
• 파일 수정 imports/ui/App.jsx
// 이걸로 변경
import { TasksCollection } from '/imports/db/TasksCollection';
74. 사용자별로 구독처리되게 개선
• https://react-tutorial.meteor.com/simple-todos/09-publications.html
• 현재 전체 데이터 구독되는 부분제거
• meteor remove autopublish
• 구독 API 추가
• 화면 구독방식 변경
75. 사용자별로 구독 서비스 추가
• 파일 생성 imports/api/tasksPublications.js
import { Meteor } from 'meteor/meteor';
import { TasksCollection } from '/imports/db/TasksCollection';
Meteor.publish('tasks', function publishTasks() {
return TasksCollection.find({ userId: this.userId });
});
76. 사용자별로 구독 서비스 등록
• 파일 수정 server/main.js
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { TasksCollection } from '/imports/db/TasksCollection';
import '/imports/api/tasksMethods';
import '/imports/api/tasksPublications';
....
78. 화면 구독 중 상태 관리
• 파일 수정 imports/ui/App.jsx
....
<div className="filter">
<button onClick={() => setHideCompleted(!hideCompleted)}>
{hideCompleted ? 'Show All' : 'Hide Completed'}
</button>
</div>
{isLoading && <div className="loading">loading...</div>}
<ul className="tasks">
....
79. 화면 구독 중 상태 스타일
• 파일 수정 client/main.css
.loading {
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
align-items: center;
font-weight: bold;
}
80. 자신의 할일만 수정할 수 있는 권한 추가
• 파일 수정 imports/api/tasksMethods.js
....
'tasks.remove'(taskId) {
…..
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
const task = TasksCollection.findOne({ _id: taskId, u
serId: this.userId });
if (!task) {
throw new Meteor.Error('Access denied.');
}
TasksCollection.remove(taskId);
},
....
....
'tasks.setIsChecked'(taskId, isChecked) {
check(taskId, String);
check(isChecked, Boolean);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
const task = TasksCollection.findOne({ _id: taskId, use
rId: this.userId });
if (!task) {
throw new Meteor.Error('Access denied.');
}
TasksCollection.update(taskId, {
$set: {
isChecked
}
});
}
....
89. 테스트 데이터 삭제되게
• 파일 생성 imports/api/tasks.tests.js
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { mockMethodCall } from 'meteor/quave:testing';
import { assert } from 'chai';
import { TasksCollection } from '/imports/db/TasksCollection';
import '/imports/api/tasksMethods';
if (Meteor.isServer) {
describe('Tasks', () => {
describe('methods', () => {
const userId = Random.id();
let taskId;
beforeEach(() => {
TasksCollection.remove({});
taskId = TasksCollection.insert({
text: 'Test Task',
createdAt: new Date(),
userId,
});
});
it('can delete owned task', () => {
mockMethodCall('tasks.remove', taskId, { context: { u
serId } });
assert.equal(TasksCollection.find().count(), 0);
});
});
});
}
90. 테스트 데이터 삭제되게 등록
• 파일 수정 tests/main.js
import assert from "assert";
import '/imports/api/tasksMethods.tests.js';
import '/imports/api/tasks.tests.js';
....
94. 테스트 수행 명령어
• 파일 확인 package.json
• meteor npm test
• meteor npm run test-app
....
"scripts": {
"start": "meteor run",
"test": "meteor test --once --driver-package meteortesting:mocha",
"test-app": "TEST_WATCH=1 meteor test --full-app --driver-package meteortesting:mocha",
"visualize": "meteor --production --extra-packages bundle-visualizer"
},
....