바닐라로 상태 기반 렌더링 컴포넌트 만들기 3 - 환경 설정하기 (feat. 보일러 플레이트)

이 시리즈의 이전 글은 아래로...

실제 작업을 위한 환경 설정을 해보쟈!

레포지토리 보러가기🗃

Github - Vanilla Component

config/#1_Project-Setting 브랜치에서 자세히 확인 하실 수 있습니다! 😊

기술 스택 🦾

  • TypeScript: 개발의 생산성, 안정성을 위해 도입
  • SCSS: 개발의 생산성을 위해 도입
  • Webpack: 코드 압축, 모듈 이용을 위해 도입
  • Babel: 크로스 브라우징을 위해 도입
  • ES Lint: 코드 품질을 위해 도입
  • Prettier: 코드 스타일을 위해 도입

프로젝트 환경 설정 🔧

1. 프로젝트 버전 관리 시작하기

npm init -y

2. gitignore 설정하기

//.gitignore

# dependencies
/node_modules

# production
/dist

# etc
.DS_Store
.vscode

3. Webpack 설정하기

관련 패키지 설치

npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin copy-webpack-plugin
  • webpack-dev-server: webpack을 이용해서 개발 서버를 열 수 있는 패키지
  • html-webpack-plugin: html 기본 템플릿을 만들어주는 패키지
  • copy-webpack-plugin: static 요소를 dist 디렉토리로 복사해주는 패키지

package.json script 설정

// package.json
...
{
	"scripts": {
		"build": "webpack --mode production",
		"dev": "webpack-dev-server --mode development --open"
	}
}

webpack.config.js 설정

// webpack.config.js
const path = require('path')
const HtmlPlugin = require('html-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
    clean: true
  },
	module: {
		rules: [
			{
        test: /\.(png|jpg|gif)$/i,
        type: 'asset/resource',
        generator: {
          filename: 'assets/images/[name][ext]'
        },
      },
		]
	},
	devtool: "inline-source-map",
  devServer: {
    client: {
      logging: 'none'
    }
  },
  plugins: [
    new HtmlPlugin({
      template: './public/index.html',
      favicon: path.resolve(__dirname, 'public/favicon.ico')
    }),
    new CopyPlugin({
			patterns: [
				{ from: 'public/favicon.ico'}
			]
		})
  ]
}

4. TypeScript + Webpack 설정

관련 패키지 설치

npm i -D typescript ts-loader tsconfig-paths-webpack-plugin

tsconfig.path.json 설정

// tsconfig.path.json

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@assets": ["./assets"],
      "@assets/*": ["./assets/*"],
      "@api": ["./api"],
      "@api/*": ["./api/*"],
      "@services": ["./services"],
      "@services/*": ["./services/*"],
      "@utils": ["./utils"],
      "@utils/*": ["./utils/*"],
      "@constants": ["./data/constants"],
      "@constants/*": ["./data/constants/*"],
      "@models": ["./data/models"],
      "@models/*": ["./data/models/*"],
      "@router": ["./router"],
      "@router/*": ["./router/*"],
      "@components": ["./components"],
      "@components/*": ["./components/*"],
      "@hooks": ["./hooks"],
      "@hooks/*": ["./hooks/*"],
      "@core": ["./components/core"],
      "@core/*": ["./components/core/*"],
      "@base": ["./components/base"],
      "@base/*": ["./components/base/*"],
      "@domain": ["./components/domain"],
      "@domain/*": ["./components/domain/*"],
    }
  }
}

tsconfig.json 설정

// tsconfg.json

{
  "extends": "./tsconfig.path.json",
  "include": ["src/**/*"],
  "outDir": "./dist/js",
  "compilerOptions": {
    "baseUrl": "src",
    "target": "es5",
    "lib": [
      "DOM",
			"DOM.Iterable",
      "ESNext"
    ],
    "module": "esnext",
    "moduleResolution": "Node",
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "isolatedModules": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "strict": true,
    "resolveJsonModule": true
  }
}

webpack.config.js 추가 설정

// webpack.config.js

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
const tsConfigPath = path.resolve(__dirname, "./tsconfig.json")

module.exports = {
  entry: './src/main.ts',
  resolve: {
    extensions: ['.ts', '.js'],
    plugins:[
      new TsconfigPathsPlugin({
        configFile: tsConfigPath
      })
    ]
  },
  module: {
    rules: [
    ...
      {
        test: /\.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
}

5. SCSS + Webpack 설정

관련 패키지 설치

npm i -D sass sass-loader css-loader mini-css-extract-plugin
  • mini-css-extract-plugin: css 파일을 별도로 추출해주는 패키지

webpack.config.js 추가 설정

// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
    ...
      {
        test: /\.s[ac]ss$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
        exclude: /node_modules/
      }
    ]
  },
  plugins: [
  ...
    new MiniCssExtractPlugin({
      filename: 'assets/css/style.[contenthash].css',
    })
  ]
}

6. Babel 설정

관련 패키지 설치

npm i -D @babel/core @babel/preset-env @babel/preset-typescript @babel/plugin-proposal-class-properties
npm i core-js whatwg-fetch
  • @babel/plugin-proposal-class-properties: private과 같은 공식 스펙이 아닌 class 속성에 대한 폴리필
  • core-js: 전역 오염성이 있는 pollyfill 대신 사용하는 폴리필
  • whatwg-fetch: Web API인 fetch 호환을 위해 사용하는 폴리필

webpack.config.js 추가 설정

// webpack.config.js

module.exports = {
  module: {
    rules: [
    ...
      {
        test: /\.m?js$/,
        include: [path.resolve(__dirname, 'src')],
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ["@babel/preset-env", {
                "useBuiltIns": "usage",
                "corejs": 3
              }],
              "@babel/preset-typescript"
            ],
            plugins: ["@babel/plugin-proposal-class-properties"]
          }
        }
      }
	  ]
  }
}

7. ESLint 설정

관련 패키지 설치

npm i -D eslint eslint-plugin-import-helpers @typescript-eslint/parser @typescript-eslint/eslint-plugin

.eslintrc 설정

// .eslintrc.js
module.exports = {
	root: true,
	env: {
		browser: true,
		es2021: true,
		node: true
	},
	parser: '@typescript-eslint/parser',
	parserOptions: {
		project: './tsconfig.json'
	},
	plugins: ['@typescript-eslint', 'eslint-plugin-import-helpers'],
	extends: [
		'eslint:recommended',
		'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended'
	],
	ignorePatterns: ['webpack.config.js','**/*.config.js', '.eslintrc.js'],
	rules: {
		'import-helpers/order-imports': [
			'error', {
				newlinesBetween: 'never',
				groups: [
					'absolute',
					'module',
					['parent', 'sibling', 'index'],
					'/^@shared/',
				],
				alphabetize: { order: 'asc', ignoreCase: true },
			},
		],
		'no-prototype-builtins': 0,
		'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
		'@typescript-eslint/consistent-type-imports': 'error',
		'@typescript-eslint/explicit-function-return-type': 'error',
		'@typescript-eslint/member-ordering': 'error',
		'@typescript-eslint/method-signature-style': ['error', 'method'],
		'@typescript-eslint/no-confusing-void-expression': 'error',
		'@typescript-eslint/no-duplicate-imports': 'error',
		'@typescript-eslint/no-non-null-assertion': 'off',
		'@typescript-eslint/no-explicit-any': 'off',
		'@typescript-eslint/type-annotation-spacing': ['error', {
			before: false,
			after: true,
			overrides: { colon: { before: true, after: true }}
		}]
	}
}

package.json script 추가 설정

// package.json

"scripts": {
	...
	"lint": "eslint ./src/**/*.ts",
    "lint:fix": "tsc --noEmit && eslint --fix ./src/**/*.ts"
},

8. Prettier 설정

관련 패키지 설치

npm i -D prettier eslint-plugin-prettier eslint-config-prettier

.prettierrc.json 설정

// .prettierrc.json
{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "trailingComma": "none",
  "bracketSpacing": true,
  "bracketSameLine": true,
  "arrowParens": "avoid",
  "endOfLine": "auto"
}

동작 확인하기 🤩

1. 개발 서버 동작 시키기

// 완성본을 다운받은 경우, npm install
npm run dev

2. console.log를 열어 'test'가 잘 입력되었다면 설정 완료!

// ./src/main.ts
export const test = 'test'
console.log(test)

좋은 웹페이지 즐겨찾기