Deployment Web App using GitHub Actions & Netlify
Deployment VanillaJS Project with Webpack using GitHub Actions on GitHub Pages
1. What is the Action? ๐ฉโ
GitHub Actions
๋ ๊นํ๋ธ์์ ์ ๊ณตํ๋ CI/CD ๋ฅผ ๋์์ฃผ๋ ์๋น์ค๋ค. ์ ์ฌํ ์๋น์ค๋ก๋ CircleCI, Travis CI,
Jenkins, Fastlane ์ ๊ฐ์ ๊ฒ๋ค์ด ์กด์ฌํ๋ค. Actions ์ ์ฅ์ ์ ๊นํ๋ธ์์ ์ ๊ณตํ๋ ๊ฒ์ผ๋ก ์ค์ ์ด๋ ์ฐ๋์ด ์ฝ๋ค๋ ๊ฒ์ด๋ค.
๊นํ๋ธ ์ก์
์์ ๋ฐ๋์ ์์์ผ ํ ๊ฐ๋
์ Events
, Jobs
, Actions
, Runners
, Secrets
, Workflows
์
6๊ฐ์ง ๊ฐ๋
์ด๋ค.
1. Events
๊นํ๋ธ ์ก์ ์ ์คํํ ์ด๋ฒคํธ ํธ๋ฆฌ๊ฑฐ ์กฐ๊ฑด์ ์ง์ ํ๋ค.
์ด๋ฒคํธ ์ค ์ฃผ๋ก ์ฌ์ฉ๋๋ ํธ๋ฆฌ๊ฑฐ ์ ํ์ ๋ค์๊ณผ ๊ฐ๋ค.
- push: ์ฝ๋๋ฅผ ํธ์ํ ๋.
- pull_request: Pull Request ๋ฅผ ์์ฑํ๊ฑฐ๋ ์ ๋ฐ์ดํธํ ๋.
- issues: ์ด์๊ฐ ์์ฑ๋๊ฑฐ๋ ์ ๋ฐ์ดํธ๋ ๋.
- issue_comment: ์ด์์ ์๋ก์ด ๋๊ธ์ด ์์ฑ๋ ๋.
- pull_request_review: Pull Request ๋ฅผ ๋ฆฌ๋ทฐํ ๋.
- pull_request_review_comment: Pull Request ๋ฆฌ๋ทฐ์ ์๋ก์ด ๋๊ธ์ด ์์ฑ๋ ๋.
- repository_dispatch: ์ฌ์ฉ์ ์ ์ ์ด๋ฒคํธ๋ฅผ ์์ ํ ๋.
- schedule: ์ผ์ ์ ๋ฐ๋ผ ์ฃผ๊ธฐ์ ์ผ๋ก.
- workflow_dispatch: ์๋์ผ๋ก ์ํฌํ๋ก์ฐ๋ฅผ ์คํํ ๋.
2. Jobs
Workflows ์์ ์คํ๋๋ ๊ฐ๋ณ ์์ ๋จ์๋ก ์ค์ ๋ก ๋ฌด์์ ํ ๊น์ ๋ํ ์ ์๋ฅผ ํฌํจํ๋ค. ๋ฐ๋ผ์ Workflows YAML ํ์ผ์ ๋๋ถ๋ถ์ ์ฐจ์งํ๋ฉฐ, ๋์ปค ์ปดํฌ์ฆ๊ฐ ์ฌ๋ฌ ์ปจํ ์ด๋์ ๋ํ ์์ ์ ์ค์ ํ๋ฏ์ด Workflows ๋ ์ฌ๋ฌ Jobs ๋ฅผ ์ค์ ํ๊ฒ ๋๋ค.
๋ฐ๋ผ์ ํ์์ ๋ฐ๋ผ ํ๋์ Workflows ์์๋ ํ๋ ๋๋ ๊ทธ ์ด์์ Jobs ๋ฅผ ํฌํจํ๊ฒ ๋๋ค.
3. Actions
Jobs ๋ ๋ด๊ฐ ์ฌ์ฉํ ์์ ์ ๋ํด Workflows ์ ์ ์๋ฅผ ํ๋ ๊ฒ์ด๋ผ๋ฉด, Actions ๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋จ์๋ก, ๋์ปค์ ๋น๊ตํ๋ฉด Docker Hub ์ ๊ณต๊ฐ๋ ์ปจํ ์ด๋ ๋๋ ์ง์ ๋ง๋ ๋น๊ณต๊ฐ ์ปจํ ์ด๋๋ผ ๋ณผ ์ ์๋ค.
Actions ๋ฅผ ์ง์ ๋ง๋ค๊ธฐ๋ ํ์ง๋ง, Marketplace
๋ฅผ ํตํด ์ปค๋ฎค๋ํฐ๋ก ์ด์๋๋ ์ก์
์ ๊ฐ์ ธ์ Jobs ์ ์ฌ์ฉํ ์ ์๋ค.
Jobs ๊ฐ ์ค์ ๋ก Workflows ์์ ์ํ๋ ์์ ์ ๋ํด ์ ์ํ๋ค๋ฉด, Actions ๋ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋จ์๋ก ํจํค์ง ๋ chunk ์ ํด๋นํ๋ค.
4. Runners
๊นํ๋ธ์์ ์ ๊ณตํ๋ ํธ์คํ ํ๊ฒฝ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋ฌผ๋ก , Vercel, ์ ํ ํธ์คํ ๋ฑ์ ์คํ ํ๊ฒฝ์ ์ฌ์ฉํ ์ ์๋ค.
5. Secrets
.env
์ ๊ฐ์ ํ์ผ์ ์ฌ๋ ค์๋ ์ ๋๊ณ , ์ค์๋ก ์ธํ ์ ์ถ์ ๋ง๊ธฐ ์ํด ์ฌ๋ฆด ์ ์๋๋ก ๋งํ์๋ค. ํ์ง๋ง ์๋น์ค ํธ์คํ
์ ์ํด์๋
API
ํค ๋๋ DB Connection
์ ๋ณด ๋ฑ ๋ค์ํ ๋น๋ฐ ์ ๋ณด๊ฐ ํ์ํ๋ค. ๋ฐ๋ผ์ ๊นํ๋ธ๋ ์ด๋ฐ ์ ๋ณด๋ฅผ repositories ์ ์ฌ๋ฆฌ๋ ๋์
Secrets
๋ฅผ ์ ๊ณตํ๊ณ , ์ฌ๊ธฐ ์์ฑํ ์ ๋ณด๋ ์ํธํ ๋์๋ค Workflows ๊ฐ ์ํ๋ ๋ ๋ณตํธํ๋์ด ๊นํ๋ธ ์ก์
์ ํ๊ฒฝ ๋ณ์๋ก ์ฌ์ฉํ ์
์๋ ์ค์ ์ ์ ๊ณตํ๋ค.
6. Workflows
๊นํ๋ธ ์ก์
์์ CI/CD ๋ฅผ ์ํ ํต์ฌ ๋จ์๋ก ์ด๋ค ์์
์ ์ธ์ ์ด๋ป๊ฒ ํ ๊น์ ๋ํด ์ ์ํ ๋ฌธ์๋ก ๋์ปค์ ๋น๊ตํ๋ฉด
Docker-Compose ์ ํด๋นํ๋ค. ๊นํ๋ธ Workflows ์ญ์ yaml
ํ์ผ๋ก ์์ฑํ๋ค.
name: CI
on:
push:
branches:
- main # main ๋ธ๋์น๋ก ํธ์ํ ๋๋ง ์คํ
jobs:
build:
runs-on: ubuntu-latest # ์คํ ํ๊ฒฝ์ ์ฐ๋ถํฌ ์ต์ ๋ฒ์ ์ผ๋ก ์ง์
steps:
- name: Checkout code # ์ฝ๋ ์ฒดํฌ์์ ๋จ๊ณ
uses: actions/checkout@v3 # GitHub Actions์์ ์ ๊ณตํ๋ checkout ์ก์
์ฌ์ฉ
- name: Set up Node.js # Node.js ์ค์ ๋จ๊ณ
uses: actions/setup-node@v3 # Node.js ํ๊ฒฝ์ ์ค์ ํ๋ ์ก์
์ฌ์ฉ
with:
node-version: '20' # Node.js ๋ฒ์ ์ง์
- name: Install dependencies # ์์กด์ฑ ์ค์น ๋จ๊ณ
run: npm install # npm์ ์ฌ์ฉํ์ฌ ํ๋ก์ ํธ์ ์์กด์ฑ ์ค์น
- name: Run tests # ํ
์คํธ ์คํ ๋จ๊ณ
run: npm test # npm์ ์ฌ์ฉํ์ฌ ํ๋ก์ ํธ์ ํ
์คํธ ์คํ
2. Make Actions ๐ฉโ
1. Failure Case
์ฒ์ ๊นํ๋ธ ์ก์
์ ์ ํ๊ณ ์๋ํ์ผ๋ ์คํจํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์๋ง๋ ์ก์
์ ๊ฐ์ฅ ๋จผ์ ์ ํ ๋ ์ ์ก์
์์ฑ์ ๋์ค๋
Suggested for this repository
์ ๋ณด์ด๋ ์ ์ ์ฌํญ์ด์ง ์์๊น ์๊ฐ๋๋ค. ๋ณธ์ธ ์ญ์ ๊ทธ๋ฌํ๊ณ , ๊นํ๋ธ ์ก์
์์ ์ ๊ณตํ๋
Webpack ์ ์ํ ์ก์
์ด ๋ณด์ฌ ๋ฐ๋ก ์ด๊ฒ์ ์ฌ์ฉํ๋ค.
๊ธฐ๋ณธ yaml ํ์ผ์ ๋ค์๊ณผ ๊ฐ๋ค.
name: NodeJS with Webpack
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js $
uses: actions/setup-node@v3
with:
node-version: $
- name: Build
run: |
npm install
npx webpack
๋ค์ํ ๋
ธ๋ ๋ฒ์ ์ ํ
์คํธ ํ ํ์๋ ์์ด์ strategy.matrix.node-version
๋ถ๋ถ์ ์ญ์ ํ๊ณ ๋๋ ค๋ณด์๋ค. ๋น์ฐํ ๊นํ๋ธ ์ก์
์์
์ ๊ณตํ๋ ๊ฒ์ด๋ workflow ๋ ์ฑ๊ณต์ ์ผ๋ก ์ ๋์๊ฐ๋ค.
ํ์ง๋ง ๋ฌธ์ ๋ build๋ฅผ ์ํ Action ์ด๋ผ๋ ๊ฒ์ด๋ค. ์ ์ค์ ์ ๋จ์ํ packages.json ์ ์๋
๋ช
๋ น์ด๋ฅผ ์ฌ์ฉํ๋๋ก run
๋ช
๋ น์ ์ถ๊ฐํด ๋ณด์์ผ๋ ์ํ๋๋๋ก ๋์ง ์์๋ค. ๋ฌผ๋ก ์ Workflow ํ
ํ๋ฆฟ์ ์ ์์ ํด ์ฌ์ฉํ๋ฉด ํ
์คํธ ์๋ํ
๋ฐ Webpack build ํ deploy ์๋ํ๊น์ง ํ ์ ์๊ฒ ์ง๋ง ๊ทธ๋ฌ๊ธฐ์ ๋ฌ๋์ปค๋ธ๊ฐ ์๋นํ ๊ฒ์ผ๋ก ์์๋์๋ค.
๋ฐ๋ผ์ GitHub Pages ์ ํธ์คํ
์ ํด์ฃผ๋ actions ์ด ์ด๋ฏธ ์กด์ฌํ ๊ฒ์ด๋ผ ์๊ฐํ๊ณ , Chat-GPT ์ ๋ฌผ์ด๋ณด๋
peaceiris/actions-gh-pages
๋ฅผ ์ฌ์ฉํ๋ผ๊ณ ํ๋ค.
2. Try peaceiris/actions-gh-pages
peaceiris/actions-gh-pages ๋ฅผ ๋ฐฉ๋ฌธํด๋ณด๋ ๋ค์ํ ํ๊ฒฝ์์ GitHub Pages ํธ์คํ ์ ๊ฐ๋ฅํ๋๋ก Workflow ์ํ๋ค์ ์ ๊ณตํ๋ค. React ์์ด Node ํ๊ฒฝ์์ ๋์ฐ๋ ๊ฒ ๋ชฉ์ ์ด์๊ธฐ ๋๋ฌธ์ Static Site Generators with Node.js ํ ํ๋ฆฟ์ ์ฌ์ฉํ๊ณ , ๊ธฐ๋ณธ yaml ํ์ผ์ ๋ค์๊ณผ ๊ฐ๋ค(React and Next ๋๋ Vue and Nuxt ์ ์ฌ์ฉํ ํ๊ฒฝ ํ ํ๋ฆฟ๋ ์กด์ฌํ๋ค).
# peaceiris/actions-gh-pages ์์ ์ ๊ณตํ๋ ํ
ํ๋ฆฟ์ด๋ค. ์ค์ ์ ์ฉํ yaml ํ์ผ์ ์๋ ์์ฑ๋ yaml ์ ํ์ธํ ๊ฒ.
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
Cache dependencies
๋ถ๋ถ์ ๋ณด๋ฉด ์ง์์ ์ธ CI/CD ๋ฅผ ๋น ๋ฅด๊ฒ ํ๊ธฐ ์ํด ์คํ ์ด์์ฒด์ ์ package-lock.json
์ด
๋ณ๊ฒฝ๋์๋์ง ์ฌ๋ถ์ ๋ฐ๋ผ ์บ์๋ฅผ ์ฌ์ฉํ๋๋ก ๋์ด์๋ค.
npm ci
๋ npm install
๊ณผ ๋น์ทํ์ง๋ง package-lock.json
์ ์ฌ์ฉํด ์ข ๋ ์๊ฒฉํ๊ฒ ๋ช
์๋ ์ข
์์ฑ์ ๋ฐ๋ฅด๋๋ก ํ๋ฉฐ,
node_modules
๋ฅผ ๋ชจ๋ ์ ๊ฑฐํ ํ clean ํ ์ํ์์ ์๋กญ๊ฒ ์ค์นํ๋ CI ํ๊ฒฝ์ ์ํ
์ค์น ๋ช
๋ น์ด๋ค. ์ด๊ฒ์ Yarn ์ ์ฌ์ฉํ๋ ํ๊ฒฝ์์ yarn install --frozen-lockfile
๋ช
๋ น์ผ๋ก yarn.lock
ํ์ผ์
์์กด์ฑ์ ์๊ฒฉํ๊ฒ ๋ช
์๋ ์ข
์์ฑ์ ๋ฐ๋ฅด๋๋ก ์ค์นํ๋๋ก ํ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค.
๊ทธ ๋ค์ npm run build
๋ package.json ์ ์๋ ๋ช
๋ น์ด๋ฅผ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์ ๋ช
๋ น์ด๊ฐ ๋ค๋ฅด๋ค๋ฉด yaml ํ์ผ์ ์ํ๋ ๋ช
๋ น์
์ํํ๋๋ก ์์ ํด์ผํ๋ค.
๋ง์ง๋ง์ผ๋ก ๊น ์ปค๋ฐ์์ ์ด๋ค ๊ฒ์ ref
๋ก ํ ์ง ์ค์ ํ๋๋ก ๋์ด ์๋๋ฐ main ์ ์ฌ์ฉํ๋ค๋ฉด ๊ฑด๋๋ฆด ํ์๋ ์๊ณ ,
Actions ๋ฅผ ์ฌ์ฉํ๋ ค๋ repository ์ secret ์ ๋ค์ด๊ฐ ๊นํ๋ธ ํ ํฐ์ ์ ์ฅํด์ฃผ๋ฉด ๋๋ค. ์ฐธ๊ณ ๋ก GITHUB_TOKEN
๋
ํ ํฐ๋ช
์ผ๋ก ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐ๊ฟ์ ์ฌ์ฉํด์ผํ๋ค.
์ฐ์ ์ด๊ฒ์ ์ฌ์ฉํ๊ธฐ ์ํด์ ์์ ์ package.json
๊ณผ webpack.config.js
๋ฅผ ์ ํํ ์ดํดํ๊ณ ์์ด์ผ ํ๋ค. Webpack ๊ณผ
์ ์ฒ๋ฆฌ๊ธฐ ๊ด๋ จ๋ ๊ฒ๋ค๋ง ์ค์น๋์๋ค๋ ๊ฐ์ ํ์ package.json
์ ๋ค์๊ณผ ๊ฐ์ ๊ฒ์ด๋ค.
{
"name": "Project Name",
"version": "1.0.0",
"description": "Project Description",
"main": "index.js",
"scripts": {
"serve": "webpack serve --mode=development --node-env=development --open",
"watch": "webpack --watch --mode=development --node-env=development",
"build": "webpack --mode=production --node-env=production"
},
"keywords": [],
"author": "Project Author",
"license": "Project License",
"devDependencies": {
"css-loader": "^6.10.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"file-loader": "^6.2.0",
"gh-pages": "^6.1.1",
"html-loader": "^5.0.0",
"html-webpack-plugin": "^5.6.0",
"prettier": "^3.2.5",
"sass": "^1.70.0",
"sass-loader": "^14.1.0",
"style-loader": "^3.3.4",
"webpack": "^5.90.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1"
},
"dependencies": {
"reset-css": "^5.0.2"
}
}
- SCSS ์ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ:
sass
,sass-loader
,style-loader
,css-loader
- HTML ์ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ:
html-loader
,html-webpack-plugin
- Assets ์ ์ฒ๋ฆฌ๊ธฐ๋ฅผ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ:
file-loader
(url-loader
๋ฅผ ์ฌ์ฉํด๋ ์๋ํ๋ค. Module-script ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, webpack 5 ์์ deprecated ๋์์ผ๋ฏ๋ก ์ค์นํ์ง ์๋๋ค.) - GitHub Pages ๋ฅผ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ:
gh-pages
npm i -D webpack webpack-cli webpack-dev-server \
sass sass-loader style-loader css-loader \
html-loader html-webpack-plugin \
file-loader url-loader
gh-pages
๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก๋
npx webpack init
๋ช ๋ น์ ์ฌ์ฉํด webpack ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ค.npm i -D webpack webpack-cli @webpack-cli/generators
npx webpack init
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
index: "./src/html/main/index.js",
signIn: "./src/html/sign-in/index.js",
},
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
publicPath: process.env.NODE_ENV === "development" ? "/" : "/project-base-url/",
assetModuleFilename: "images/[hash][ext][query]",
},
module: {
rules: [
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
// file loader
test: /\.(png|svg|jpg|jpeg|gif)$/i,
use: {
loader: "file-loader",
},
generator: {
filename: "[path][hash][ext][query]", // ์ด๋ฏธ์ง๊ฐ ๋ฒ๋ค๋ ์์น๋ฅผ ๋ณ๊ฒฝ
},
},
{
// html loader
test: /\.html$/,
use: {
loader: "html-loader",
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/html/main/index.html",
filename: "index.html",
chunks: ["index"], // entry ์ JavaScript ์ด๋ฆ๊ณผ ๋์ผํ๊ฒ ์ง์ . ํด๋น JavaScript ๋ฅผ ๋ถ๋ฌ์จ๋ค.
}),
new HtmlWebpackPlugin({
template: "./src/html/sign-in/index.html",
filename: "sign-in/index.html", // directory ๊ฐ routing ๊ธฐ๋ฅ์ ํ๋๋ก "๋ผ์ฐํ
๊ฒฝ๋ก/index.html" ๋ก ์ค์ ํ๋ค.
chunks: ["signIn"],
}),
],
};
์ด๋ฏธ์ง์ ๊ฐ์ ๋ฆฌ์์ค๋ฅผ ์ ์์ ์ผ๋ก ๋ก๋ํ๊ธฐ ์ํด์๋ webpack ์ด ๊ด๋ฆฌํ ์ ์๋๋ก ํด์ผํ๋ค. ์ฆ, ์ด๋ฏธ์ง์
src
๊ฒฝ๋ก๋ฅผ javascript ์์ ๋จ์ ๋ฌธ์์ด๋ก ์ฌ์ฉํ๋ฉด ์ ๋๊ณ , webpack ์ด ์ผ๊ณ ๋ฒ๋ค๋ง ํ ์ ์๋๋ก html ๋ฌธ์๋ฅผ ํตํด src ๋ฅผ ์์ฑํ๊ฑฐ๋, javascript ๋ก ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํ ๋๋ import ๋ฅผ ์ฌ์ฉํด ํ์ผ์ ๋ถ๋ฌ์ ์ฌ์ฉํด์ผํ๋ค.
package.json type="module"
์ ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ด ์ผ๋ถ ์์ ์ด ํ์ํ๋ค
(Asset Modules ์ ์ํ๋ฉด webpack 5 ์์ deprecated ๋
raw-loader
, url-loader
, file-loader
์ ์ฌ์ฉ์ ๊ถ์ฅํ์ง ์๋๋ค. module script ์ฌ์ฉํ ๊ฒฝ์ฐ ์ด ๋ถ๋ถ๋ ํจ๊ป
๋ฐ๊ฟ์ฃผ๋ฉฐ, ๋์ด์ ์ loader ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ค์นํ ํ์๊ฐ ์๋ค).
import * as path from "path";
import HtmlWebpackPlugin from "html-webpack-plugin";
const __dirname = path.resolve();
export default {
entry: {
index: "./src/html/main/index.js",
signIn: "./src/html/sign-in/index.js",
},
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
publicPath: process.env.NODE_ENV === "development" ? "/" : "/project-base-url/",
assetModuleFilename: "images/[hash][ext][query]",
},
module: {
rules: [
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
// file loader
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
},
{
// html loader
test: /\.html$/,
use: {
loader: "html-loader",
},
},
],
parser: {
javascript: {
commonjsMagicComments: true,
dynamicImportMode: "lazy",
dynamicImportPreload: true,
dynamicImportPrefetch: true,
},
},
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/html/main/index.html",
filename: "index.html",
chunks: ["index"], // entry ์ JavaScript ์ด๋ฆ๊ณผ ๋์ผํ๊ฒ ์ง์ . ํด๋น JavaScript ๋ฅผ ๋ถ๋ฌ์จ๋ค.
}),
new HtmlWebpackPlugin({
template: "./src/html/sign-in/index.html",
filename: "sign-in/index.html", // directory ๊ฐ routing ๊ธฐ๋ฅ์ ํ๋๋ก "๋ผ์ฐํ
๊ฒฝ๋ก/index.html" ๋ก ์ค์ ํ๋ค.
chunks: ["signIn"],
}),
],
};
name: Deploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/gh-pages'
with:
github_token: ${{ secrets.GH_ACTION_TOKEN }}
publish_dir: ./dist
์์ ํ ๋ถ๋ถ์ ๋ณด์.
- node-version: ๊ธฐ๋ณธ ํ ํ๋ฆฟ์๋ node 14๋ก ๋์ด์๋๋ฐ ํด๋น ๋ฒ์ ์ ์ฌ์ฉํ๋ฉด ์ต์ ์ผ๋ก ์ค์น๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ผ๋ถ๋ฅผ ์ฐพ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. ๋ฐ๋ผ์ ๋ฒ์ ์ ๊ฐ๋ฐ ํ๊ฒฝ๊ณผ ๋์ผํ ๋ฒ์ ์ผ๋ก ์ฌ๋ ค์ค์ผํ๋ค.
- publish_dir: ์์์๋ ์ค๋ช
ํ๋ฏ์ด,
webpack.config.js
ํ์ผ์output.path
์ ์ผ์นํ๋๋ก ์์ ํด์ค์ผํ๋ค. ๋ฐ๋ผ์./dist
๋ก ์์ ๋์๋ค.
3. Configure GitHub Repository Setting
์ฐ์ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ด secrets์ ๊นํ๋ธ ํ ํฐ์ ๋ฑ๋กํ๋ ๊ฒ์ด๋ค. ํ
ํ๋ฆฟ์
ํ ๋ฏ ์ด๋ฆ์ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก GH_ACTION_TOKEN
๋ก ์์ ํ ํ ํฐ์ ๋ฑ๋กํด์ฃผ์๋ค.
๋ชจ๋ ๊ฒ์ด ์ ๋์๊ณ , ํด๋น Workflow ๋ ์ ์์ ์ผ๋ก ์ํ๋์๋ค. ํ์ง๋ง ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํ๋ฉด ๋จ๊ธด ๋จ๋๋ฐ HTML ๋ง ๋จ๊ณ , ์ฌ์ง์ด
์ ๋๋ก ๋น๋๋์ง๋ ์์ ์ฑ ๋ด๋ค. ๋ฌธ์ ์ ์์ธ์ ๋ ํฌ์งํ ๋ฆฌ ์ค์ ์ค GitHub Pages
๋ถ๋ถ์ด์๋ค(๊ณ์ ์ Pages ๊ฐ ์๋ ํด๋น
๋ ํฌ์งํ ๋ฆฌ ์ค์ ์์ Pages ๋ฅผ ๋ค์ด๊ฐ์ผํ๋ค).
์ Workflow ๋ฅผ ์ํํ๋ฉด ์๋์ผ๋ก gh-pages
๋ธ๋์น์ ๋น๋๋ ๊ฒฐ๊ณผ๋ฌผ์ ์ปค๋ฐ์ ํ๋ค.
๋ฐ๋ผ์ deployment ๋์ ๋ธ๋์น๋ฅผ main
์์ gh-pages
๋ก ๋ณ๊ฒฝํด์ค์ผํ๋ค.
Jekyll ์์ main
์ deploy ํ๋๋ก ๋์ด ์์ด์ ์ ๊ฒฝ ์ฐ์ง ์์๋๋ฐ ์ด ๋ถ๋ถ์ ๋์ณ ๋ช ์๊ฐ์ ๊ณ ๋ฏผํ์๋ค. ๊ผญ ๋์ ๋ธ๋์น๋ฅผ
ํ์ธํด์ผํ๋ค!!
์ ์์ ์ผ๋ก ๊นํ๋ธ ํ์ด์ง ํธ์คํ ์ด ๋์๋ค!!
3. Netlify ๐ฉโ
Netlify ์ ์ง์ ํธ์คํ ํ๋ ๊ฒ์ด ์๋, GitHub ์ push ๋ฅผ ํ๋ฉด ํน์ ๋ธ๋์น๋ก๋ถํฐ ์๋์ผ๋ก ๋ฐฐํฌ๋๋๋ก ์ฐ๋ํ๋ ๊ฒ์ ๋ํด ์ค๋ช ํ๋ค. Netlify ๋ก ๋ฐฐํฌํ ๊ฒฝ์ฐ ์ GitHub Actions ๋ ์ค์ ํ์ง ์์๋ ๋๋ค.
GitHub Pages ๋ก ๋ฐฐํฌํ ๊ฒฝ์ฐ ๊ธฐ๋ณธ ๊ฒฝ๋ก ์ค์ ์ ํ์ง ์์ผ๋ฉด root ๊ฐ repository ์ด๋ฆ์ ์ ์ธํ ๊ฒฝ๋ก๋ก ์ค์ ๋์
publicPath
๋ฅผ ์ค์ ํด์ฃผ์๋ค. Netlify ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ๊ฐ๊ฐ ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํ๋ฏ๋ก webpack.config.json
์์
output.publicPath: process.env.NODE_ENV === "development" ? "/" : "/project-base-url/"
๋ฅผ ์ญ์ ํ๋ค.
- Base directory: ํด๋น ๋ ํฌ์งํ ๋ฆฌ์์ ๋ฐฐํฌํ๋ ค๋ ์ฑ์ ๊ธฐ๋ณธ ๊ฒฝ๋ก๋ค. ํ๋์ ๋ ํฌ์งํ ๋ฆฌ์ ๋๋ ํ ๋ฆฌ๋ณ๋ก ์ฌ๋ฌ ๊ฐ์ ์ฑ์ ๋ฐฐํฌํ ๊ฒฝ์ฐ,
ํด๋นํ๋ ๊ฒฝ๋ก๋ฅผ ์
๋ ฅํ๋ฉด ๋๊ณ , ๋ ํฌ์งํ ๋ฆฌ ํ๋์ ํ๋์ ์ฑ์ผ ๊ฒฝ์ฐ root ๊ฒฝ๋ก์ด๋ฏ๋ก ๋น์๋๋ค
(๊ฒฝ๋ก๊ฐ ์
๋ ฅ๋ ๊ฒฝ์ฐ, โPackage directoryโ, โPublish directoryโ, โFunctions directoryโ ์์
base dir/
์ ์๋์ผ๋ก ์ ๋ ฅ๋๋ค). - Build command:
npm ci
๋ Netlify ๊ฐ ์์์ ์งํํ๋npm run build
๋ง ์์ฑํ๋ฉด ๋๋ค. - Publish directory: webpack ์
output.path
๋ฅผ ์ ๋ ฅํ๋ฉด ๋๋ค.
๋ง์ฝ, ์์ชฝ์ ๋ชจ๋ ๋ฐฐํฌ๋ฅผ ์ํ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ด ์ค์ ์ ๋๋ ์ ์๋ค.
1 ) script ๋ช ๋ น์ ๋ณ์๋ฅผ ์ฌ์ฉํด ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ
{
"scripts": {
"serve": "webpack serve --mode=development --node-env=development --open",
"watch": "webpack --watch --mode=development --node-env=development",
"build-github": "webpack --mode=production --node-env=production --base-url=project-base-url",
"build-netlify": "webpack --mode=production --node-env=production"
}
}
export default {
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
publicPath: process.env.BASE_URL === undefined ? "/" : process.env.BASE_URL,
assetModuleFilename: "images/[hash][ext][query]",
},
};
project-base-url ์
/github-name/repository-name/
ํํ๋ก ์์ฑํ๋ค.
2 ) webpack configuration ํ์ผ๋ก ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ
{
"scripts": {
"serve": "webpack serve --mode=development --config webpack.development.config.js --node-env=development --open",
"watch": "webpack --watch --mode=development --config webpack.development.config.js --node-env=development",
"build-github": "webpack --mode=production --config webpack.prod-github.config.js --node-env=production",
"build-netlify": "webpack --mode=production --config webpack.prod-netlify.config.js --node-env=production"
}
}
// webpack.development.config.js
export default {
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "images/[hash][ext][query]",
},
};
// webpack.prod-github.config.js
export default {
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
publicPath: "project-base-url",
assetModuleFilename: "images/[hash][ext][query]",
},
};
// webpack.prod-netlify.config.js
export default {
output: {
filename: "[name].[contenthash].bundle.js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "images/[hash][ext][query]",
},
};
project-base-url ์
/github-name/repository-name/
ํํ๋ก ์์ฑํ๋ค.
3 ) ํธ์คํ ์๋ฒ์ ํ๊ฒฝ๋ณ์๋ก ๋ถ๋ฆฌํ๋ ๋ฐฉ๋ฒ
BASE_URL
์ GitHub Pages ๋ Netlify ์ ํ๊ฒฝ๋ณ์๋ฅผ ์ค์ ํ๊ณ , ์ด๋ฅผ ๊ฐ์ ธ๋ค ์ฌ์ฉํ๋๋ก ํ ์ ์๋ค.
{
"scripts": {
"serve": "webpack serve --mode=development --node-env=development --open",
"watch": "webpack --watch --mode=development --node-env=development",
"build": "webpack --mode=production --node-env=production"
}
}
export default {
output: {
publicPath: process.env.NODE_ENV === "development" ? "/" : "/project-base-url/",
},
};
GitHub Pages ์ project-base-url ์
/github-name/repository-name/
ํํ๋ก ์์ฑํ๊ณ , Netlify ๋/
๋ก ์์ฑํ๋ค.
์ ์ธ ๊ฐ์ง ์ค ์ด๋ค ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ ,
output.publicPath
๋ HTML, JavaScript, Images ์ ๊ฐ์ Network ์์ฒญ์ ๋ณด๋ผ ๋ ๊ธฐ๋ณธ URL ์ ์ถ๊ฐํด์ค๋ค. ํ์ง๋ง<a href="/sign-in">
๊ณผ ๊ฐ์ ๊ฒฝ๋ก๋ ์์ ๋์ง ์๋๋ค. ์ฆ, ์ฝ๋๋ฅผ ์์ฑํ ๋ BASE_URL ์ ํ๊ฒฝ๋ณ์๋ก๋ถํฐ ๊ฐ์ ธ์ค๋๋ก ์ฝ๋ฉ์ ํด์ผํ๋ค. ๋ฐ๋ผ์ 2ํ์ด์ง ์ด์์ผ ๊ฒฝ์ฐ, Github Pages ๋ก ๋ฐฐํฌํ๋ ๊ฒ์ ๊ทธ๋ฅ Webpack ์์ด HTML, JavaScript ๋ฅผ ์ง์ ๋ฐฐํฌํ๊ฑฐ๋, React ๋ก ๋ฐฐํฌํด์ผํ๋ค. Vanilla JS ํ๋ก์ ํธ๊ฐ 2ํ์ด์ง ์ด์์ผ ๊ฒฝ์ฐ ๋ฐฐํฌ๋ Netlify ๋ก ํ๋ ๊ฒ์ด ๋ ์ข๋ค.
Reference
- peaceiris, โactions-gh-pages.โ GitHub. Mar. 31, 2023, [https://github.com/realm/SwiftLint].
- โ์ ๋ฐ ๊นํ๋ธ ์ก์ ๐ฅ ๋ชจ๋ฅด๋ ๊ฐ๋ฐ์ ์๊ฒํด ์ฃผ์ธ์ ๐.โ Youtube. Jun. 28, 2022, ์ ๋ฐ ๊นํ๋ธ ์ก์ ๐ฅ ๋ชจ๋ฅด๋ ๊ฐ๋ฐ์ ์๊ฒํด ์ฃผ์ธ์ ๐.
- โAsset Modules.โ Webpack Docs. Feb. 27, 2024, https://webpack.js.org/guides/asset-modules/.