Webpack과 React를 이용한 정적 웹사이트 만들기 (1)

Webpack + TypeScript + React + TailwindCSS = TA-DA!

1/10/2023, 5:00:48 AM에 LiteHell이(가) 작성
카테고리 : Dev
태그 : React

들어가는 글

본래 내 개인 웹사이트Next.js의 Static HTML Export 기능GitHub Pages를 이용해 배포됐다. 디자인에는 bulma CSS 프레임워크를 이용했다.

홈페이지 재디자인 전의 이미지

위와 같이 bulma에서 제공하는 component들을 이용해 간단하게 디자인했다.

그러나 내 웹사이트를 몇 번 보다보니 디자인을 좀 설렁설렁하게 한 느낌이 들었다. 그래서 디자인을 한 번 바꿔보고 싶었고, 이번 기회에 Next.js를 쓰지 않고 직접 정적 파일로 배포하는 경험도 해보고 싶었다.

이 글은 개인 홈페이지를 재작성한 경험에 기반하여 쓰는 글이지만, 독자들이 따라하며 참고할 수 있도록 일부 변형하여 작성했다. 설명을 최대한 자세하게 하려 노력했지만, 글 쓰는 실력이 좋은 편이 아니라 읽기 불편할 수 있으니 양해해주셨으면 좋겠다.

Webpack과 Babel, 그리고 Typescript

Next.js는 쓰지 않았다. 간단한 한 페이지 정적 페이지 만드는 데에는 Webpack이면 충분하다.

이제 어떤 기술스택을 쓸 지 정했다, 이제 필요한 의존성을 먼저 설치하면 된다. 의존성을 한 번 설치해보자.

의존성 설치하기

먼저 React와 Typescript를 설치한다. 재디자인 전에 했듯이 이번에도 React로 개발할 것이다.

yarn add react-dom react
yarn add --dev typescript react @types/react @types/react-dom

그 다음, 다음 명령어로 tsconfig.json을 생성한다.

npx tsc --init

생성된 tsconfig.json에서 jsx 속성을 react로(다르게 해도 되긴 한데 나는 이렇게 했다), 그리고 moduleResolution 속성은 node로 바꾸어야 한다. 이 외에 나머지 속성들은 개인 취향대로 하면 된다. 일단 개인 취향대로 하고 나중에 코딩하다 tsconfig.json때문에 오류나면 그때 수정하면 된다.

참고로 내 tsconfig.json는 다음과 같다.

{
  "compilerOptions": {
    "target": "es2016",
    "lib": ["DOM"],
    "jsx": "react",
    "module": "ESNext",
    "moduleResolution": "node",
    "typeRoots": ["node_modules/@types", "src/types"],
    "allowJs": false,
    "checkJs": false,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*.tsx", "src/**/*.ts"],
  "exclude": ["node_modules"]
}

그 다음으로는 Webpack이 필요하다. 다음 명령어로 Webpack을 추가하자.

yarn add webpack webpack-cli
yarn add --dev webpack-dev-server ts-loader style-loader clean-webpack-plugin css-loader html-webpack-plugin

각 패키지들의 설명은 다음과 같다.

  • webpack, webpack-cli : Webpack이다. 설명이 필요없다.
  • webpack-dev-server : 수정이 되면 자동으로 webpack 재빌드해서 새로고침되는 웹 서버를 열기 위해 이용한다. 디버깅이 편해진다.
  • webpack loader: Webpack에서 특정 유형의 파일을 불러오거나 변형한다.
    • ts-loader: .ts.tsx파일을 Webpack에서 읽을 때 쓴다.
    • css-loader: css 파일에서 @importurl() 구절들을 import/require()와 같은 식으로 해석하는 loader다.
    • style-loader: css를 웹페이지에 추가하는 loader다
  • webpack plugin
    • clean-webpack-plugin: 출력 디렉토리내 파일들을 삭제하는 플러그인이다.
    • html-webpack-plugin: 생성된 js 파일의 스크립트 태그들이 추가된 html파일을 자동으로 생성한다

나는 이번에 babel을 쓸 것이다. babel은 최신 버전의 자바스크립트 기능을 브라우저 지원에 신경쓰지 않고 쓸 수 있게 해준다. 아래 명령어로 babel도 설치하자.

yarn add --dev @babel/core @babel/preset-env @babel/preset-react babel-loader

TailwindCSS가 웹사이트 빠르게 만드는 데 좋다갈래 반신반의하는 느낌으로 한 번 써보려 한다. TailwindCSS를 쓰려면 다음 패키지들을 설치해야 한다.

yarn add --dev autoprefixer postcss postcss-loader tailwindcss

Webpack 설정하기

이제 Webpack을 설정해야 한다. 루트 디렉토리에 webpack.config.js를 생성하고 내용을 다음과 같이 한다.

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const dev = process.env.NODE_ENV === 'development';
module.exports = {
    // 개발시라면 개발 모드로 한다.
    mode: dev ? "development" : "production",
    optimization: {
      splitChunks: {
        // 청크를 가능한만큼 다 분리한다.
        // 파일 각각의 용량을 줄여들어서 웹페이지 로드속도 감소에 도움이 된다.
        chunks: 'all'
      },
      // 개발중이 아니라면 압축한다.
      minimize: !dev
    },
    // 진입 파일이다.
    // ./src/index.tsx 파일에 필요한 모듈들을 번들링한다고 이해하면 된다.
    //
    // 즉, 다시 말해 출력파일을 실행하면 ./src/index.tsx을 실행하는 것과 동일한 효과를 가진다,
    // 다만 필요한 모듈들이 같이 번들링되어 있어 웹 환경 등에서도 실행이 용이할 뿐이다.
    entry: './src/index.tsx',
    output: {
        path: path.resolve(__dirname, 'dist'),
        // index.js로 하면 splitChunks 속성때문에 오류가 난다.
        filename: '[name].js'
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js', '.css']
    },
    module: {
        rules: [
            // 참고: use 속성은 마지막 아이템에서 첫 아이템으로의 순서, 즉 다시 말해 오른쪽에서 왼쪽으로의 순서로 해석된다.
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                use: [
                    // Babel은 현대 자바스크립트를 브라우저 지원여부을 고려할 필요없이 쓸 수 있도록 해준다.
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-react', '@babel/preset-env']
                        }
                    },
                    // Typescript를 Javascript로 컴파일해준다.
                    'ts-loader'
                ]
            },
            {
                test: /\.css$/,
                // postcss-loader는 TailwindCSS 적용에 이용된다.
                use: ['style-loader', 'css-loader', 'postcss-loader']
            }
        ]
    },
    plugins: [
        // 빌드전에 dist 디렉토리내 파일들을 먼저 지우고 
        new CleanWebpackPlugin(),
        // 빌드후 출력파일들이 script태그로 포함된 html파일을 생성한다.
        new HtmlWebpackPlugin({
        title: 'Yeonjin Shin',
        filename: 'index.html'
    })],
    // 디버깅할 때 쓰는 웹서버에 관한 설정이다.
    // webpack serve로 열 수 있다.
    devServer: {
        static: {directory: path.join(__dirname, 'dist')},
        open: true,
        port: 'auto',
    },
    // 이거 안하면 node_modules내 수 많은 파일의 변경여부도 같이 확인하기 때문에
    // 디버깅용 웹서버가 정상적으로 작동하지 않는다.
    watchOptions: {
        ignored: /node_modules/
    }
}

TailwindCSS 설정하기

TailwindCSS를 적용하려면 TailwindCSS 설정파일을 생성해야 한다. TailwindCSS 설정 파일은 다음 명령어로 생성할 수 있다. -p 매개변수를 주면 PostCSS 설정파일도 같이 생성해준다.

npx tailwindcss init -p

postcss.config.js는 생성된 그대로 쓰면 되고, tailwind.config.js만 수정하면 된다. tailwind.config.jscontent 속성에 TailwindCSS를 사용할 파일 패턴을 넣는다.

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,css,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

이제 TailwindCSS를 쓰기 위해 한 가지만 더 하면 된다. 다음과 같이 @tailwind 구문들이 들어간 css파일을 생성하고, 그 css 파일을 프론트엔드 코드에서 추가해주면 된다.

/* styles/index.css */

@tailwind base;
@tailwind components;
@tailwind utilities;

/* ...more css here */
// src/index.tsx

import '../styles/index.css';
// ...more imports and code here

TailwindCSS가 추가하는 CSS 코드는 PostCSS와 postcss-loader에 의해 CSS 파일에 자동으로 추가된다. 그리고 그 CSS 파일은 위와 같이 import만 해주면 style-loader에 의해 웹브라우저에서 html에 자동으로 추가된다.

이제 TailwindCSS, Webpack, React를 쓰기 위한 준비가 끝났다. 코딩만 하면 된다.

코딩

아래와 같이 코드를 작성해보자.

// src/index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import '../styles/index.css';

function Index() {
    return <div className="bg-gray-400">
      Hello, World!
    </div>
}

const rootDiv = document.createElement('div');
document.body.appendChild(rootDiv);
const root = ReactDOM.createRoot(rootDiv);
root.render(<Index />)

이렇게 하고 npx webpack build하면 잘 빌드될 것이다. dist/index.html 파일을 웹 브라우저로 열였을 때 "Hello, World!"가 뜨면 정상이다.

위와 같은 식으로 코딩하면 된다. 개발할 때는 npx webpack serve로 웹 서버를 열면 편하게 디버깅할 수 있다.