제작 컨셉
모든 코드는 Typescript로 작성 한다.
Express를 통해 기본적인 라우팅을 구현한다.
Node.js는 싱글 스레드 기반이므로 express-cluster를 이용하여 한대의 머신에 여러개의 서버를 구동한다.
클라이언트와의 통신은 REST가 아닌 GraphQL 방식으로 한다.
Apollo를 통해 GraphQL을 편리하게 사용한다.
NoSQL 방식인 mongoDB를 통해 데이터를 관리한다.
Typescript 코드로 빌드된 JS 코드를 Webpack으로 번들화 하여 최종적으로 하나의 파일로 묶어준다.
구성요소
Node.js, Typescript, Webpack, Express, express-cluster, Apollo, MongoDB
Node.js 프로젝트 생성
$ mkdir project-name
$ cd project-name
$ yarn init
$ yarn install
Typescript 적용
로컬에 타입스크립트 설치 [참고]
$ yarn add typescript --dev
프로젝트 root에 tsconfig.json 작성:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"sourceMap": true,
"allowJs": true,
"strict": true,
"lib": [
"dom",
"esnext",
"dom.iterable",
"scripthost"
],
"rootDir": ".",
"outDir": "./build_ts/",
"baseUrl": ".",
"paths": {
"*": [
"*"
],
"@res/*": [
"res/*"
],
"@gql/*": [
"src/graphql/*"
],
"@models/*": [
"src/models/*"
]
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
* 동작하는 곳이 브라우저가 아니기 때문에 하위 호환을 위해서 target을 'es5'로 변경 할 필요가 전혀 없다.
* 리소스는 @res, graphql은 @gql, DB모델은 @model로 접근 가능하다.
Webpack 설치
로컬에 Webpack 설치
$ yarn add --dev webpack webpack-cli mini-css-extract-plugin clean-webpack-plugin webpack-dev-server tsconfig-paths-webpack-plugin ts-loader url-loader file-loader css-loader
프로젝트 root에 webpack.config.js 작성:
const path = require('path');
const webpack = require('webpack');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
require('dotenv').config();
module.exports = (env, argv) => {
let isProductionMode = (env && env.production) || process.env.production === 'true' || false;
let devtool;
const plugins = [new MiniCssExtractPlugin({ filename: 'app.css' })];
if (isProductionMode) {
isProductionMode = 'production';
devtool = false;
plugins.push(new CleanWebpackPlugin());
} else {
isProductionMode = 'development';
devtool = 'inline-source-map';
}
return {
mode: isProductionMode,
devtool,
entry: './src/index',
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js',
sourceMapFilename: '[file].map',
publicPath: '/',
},
devServer: {
hot: true,
host: 'localhost',
port: 3000,
contentBase: path.resolve(__dirname, 'build'),
},
resolve: {
modules: [path.join(__dirname, 'src'), 'node_modules'],
extensions: ['.ts', '.tsx', '.js', '.json'],
plugins: [new TsconfigPathsPlugin()],
},
module: {
rules: [
{
// Include ts, tsx, js, and jsx files.
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
loader: 'ts-loader',
},
{
// Images
test: /\.(png|svg|jpe?g|gif)$/,
loader: 'url-loader',
options: {
outputPath: 'images/',
limit: 10000,
},
},
{
// Font files.
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
},
{
// css, scss files.
test: /\.css$/,
exclude: /node_modules/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
externals: [nodeExternals()],
plugins,
};
};
* mode를 production으로 하면 코드 난독화 및 소스 용량을 줄일 수 있다.
* ts-loader: Typescript 빌드하기 위한 용도
* mini-css-extract-plugin: 최종 Entry에 사용된 CSS만을 뽑아서 추출하는 용도
* clean-webpack-plugin: 프로덕션을 깨끗하게 클린 후 빌드하기
* webpack-dev-server: 개발을 보다 편리하게 하기 위한 개발 서버 설정 (Auto hot loading 등을 위한 용도)
* tsconfig-paths-webpack-plugin: tsconfig의 paths 속성을 webpack에서 그대로 쓰기
* 별도의 추가적인 옵션을 적용하고 싶다면 [이곳]을 참고하면 된다.
서버 코드 작성
서버 제작에 필요한 모듈들 추가
$ yarn add express express-cluster apollo-server apollo-server-express graphql mongoose --save
$ yarn add --dev @types/express @types/express-cluster @types/apollo-server @types/apollo-server-express @types/express @types/graphql @types/mongoose
테스트 코드
src/index.ts 코드를 다음과 같이 작성해 준다.
import express from "express";
import cluster from 'express-cluster';
import { ApolloServer, gql } from "apollo-server-express";
const PORT = 3000;
const app = express();
const path = "/graphql";
const typeDefs = gql`
type Query {
"""
Test Message.
"""
testMessage: String!
}
`;
const resolvers = {
Query: {
testMessage: (): string => {
return "Hello World!";
}
}
};
cluster(worker => {
const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app, path });
// respond with "hello world" when a GET request is made to the homepage
app.get("/", function(req, res) {
res.send("hello Express!");
});
app.listen(PORT, () => {
console.log(
`GraphQL Server is now running on http://localhost:${PORT}/graphql`
);
});
}, {});
프로젝트 실행
Webpack으로 빌드
개발용
$ npx webpack
프로덕트 생성용
$ npx webpack --env.production
또는
.env 파일에 production = "true" 를 넣어주고 다음 명령을 실행하면 된다.
$ npx webpack
소스코드 자동 빌드
소스코드를 변경 할 때 마다 매번 webpack 빌드 명령어를 치기가 여간 번거롭다.
감시자를 동작하여 알아서 빌드 되게끔 구성한다.
$ webpack --watch
빌드 된 번들 실행하기
$ node ./build/main.js
* http://localhost:3000 으로 접속하면 express로 routing 된 화면을 볼 수 있다.
* http://localhost:3000/graphql 으로 접속 하면 apollo 쿼리 스키마를 확인 해 볼 수도 있고 쿼리도 처리 해 볼 수 있다.