만약 익스텐션을 만들때 복잡한 작업을 일일이 하기 싫다면 보일러 플레이트라는 것을 이용하면 된다.
보일러 플레이트란? 개발 과정에서 반복적으로 사용되는 코드 조각이나 텍스트 블록을 지칭하는 용어인데 깃허브에 오픈소스로 많이 올라와 있으므로 골라서 사용하면 된다.
예시) 익스텐션 보일러 플레이트
해당 글은 예시의 보일러플레이트를 기반으로 생성되었습니다.

전에 설명했던 background contentScript option popup폴더를 확인 할 수 있다.
npm init -y

npm install react react-dom
npm install --save-dev typescript @types/react @types/react-dom
Q) 타입스크립트를 개발 의존성으로 설치하는 이유
타입스크립트 코드가 실제 실행 시간(runtime)에 필요한 자바스크립트(JavaScript) 코드로 변환(트랜스파일)된 후에는 타입스크립트 컴파일러 자체가 프로덕션 환경에서는 더 이상 필요하지 않기 때문입니다. 즉, 타입스크립트는 개발 과정에서만 필요하며, 배포된 애플리케이션을 실행할 때는 필요하지 않습니다.
{
"compilerOptions": {
"module": "es6",
"target": "es6",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": ["./src/**/*"],
"exclude":["node_modules"]
}
{
"compilerOptions": {
"module": "es6", //생성될 JavaScript 모듈 시스템을 지정
"target": "es6", //컴파일된 코드의 ECMAScript 대상 버전
"jsx": "react", //JSX 코드를 어떻게 처리할지 지정합니다. react로 설정되어 있으므로, JSX는 React.createElement 호출로 변환됩니다.
"allowJs": true //TypeScript 컴파일러가 .js 파일을 포함하여 컴파일합니다.
"moduleResolutioin": "node", //모듈 해석 방식을 지정합니다. node로 설정되어 있으므로, Node.js의 모듈 해석 메커니즘을 따릅니다.
"esModuleInterop":true // CommonJS 모듈을 ES6 모듈처럼 더 쉽게 사용할 수 있도록 합니다. 이 옵션은 import * as express from 'express' 대신 import express from 'express'와 같은 문법을 가능하게 합니다.
},
"include": ["src/**/*"] //컴파일러가 처리할 파일 또는 디렉토리를 지정합니다. 여기서는 src 디렉토리 아래의 모든 파일을 포함합니다.
"exclude":["node_modules"]
}

//웹팩만 설치할 경우
npm install --save-dev webpack webpack-cli
//Babel도 설치할 경우
npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
webpack.config.js 파일을 만들어 준다음에
설정을 하나하나 추가해 나가면 된다.
웹팩은 모듈 번들링을 위해, Babel은 최신 JavaScript(ES6+)와 JSX를 구형 브라우저에서도 호환되는 JavaScript로 변환하기 위해 사용된다.
Babel은 매우 유연하고 다양한 플러그인을 통해 코드 변환을 맞춤 설정할 수 있습니다. 예를 들어, 최신 JavaScript 문법, JSX, 실험적인 JavaScript 기능 등을 다룰 수 있습니다.
그냥 글로만 봐서는 사실 감이 잘 오지 않는다...
Babel을 사용하면, 다른 Babel 기반 변환(예: JSX 처리, JavaScript 최신 문법 사용)과의 통합이 용이합니다.
=> Babel을 사용해 본적이 없고 필요성을 느끼지 못해서 설정을 따로 해주지는 않았다.
webpack에서 ts-loader라는 녀석을 사용하는데 TypeScript 컴파일러(tsc)를 직접 사용하여 TypeScript 코드를 JavaScript로 변환하고 이 과정에서 TypeScript의 타입 검사를 포함한 모든 컴파일 단계를 수행한다.
Babel을 사용하여 TypeScript를 처리할 때, Babel은 TypeScript 코드에서 타입 주석을 제거하고, ES6 이상의 코드를 이전 버전의 JavaScript로 변환하는 역할만 수행합니다. 타입 검사는 수행하지 않으며, 이는 별도의 도구(예: IDE, tsc 명령어 등)를 통해 진행해야 합니다.
크롬 익스텐션을 개발할 때 웹팩이 필수는 아니다. 웹팩 없이도 익스텐션 개발이 가능한 경우는 다음과 같다.
본인은 리액트가 익숙하기 때문에 웹팩을 사용하여 익스텐션을 만들었다.
npm install -D webpack webpack cli webpack-dev-server
외에 각종 플러그인들과 로더들을 설치해 주면 된다
npm install webpack webpack-cli typescript ts-loader html-webpack-plugin copy-webpack-plugin dotenv-webpack clean-webpack-plugin style-loader css-loader file-loader --save-dev
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
popup: path.resolve('src/popup/popup.tsx'),
options: path.resolve('src/options/options.tsx'),
background: path.resolve('src/background/background.ts'),
contentScript: path.resolve('src/contentScript/contentScript.ts'),
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(jpg|jpeg|png|woff|woff2|eot|ttf|svg)$/,
type: 'asset/resource'
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new CleanWebpackPlugin({
cleanStaleWebpackAssets: false,
}),
new CopyPlugin({
patterns: [
{
from: path.resolve('src/static'),
to: path.resolve('dist'),
}
]
}),
...getHtmlPlugins([
'popup',
'options'
]),
],
output: {
filename: '[name].js',
path: path.resolve('dist'),
},
optimization: {
splitChunks: {
chunks(chunk) {
return chunk.name !== 'contentScript' && chunk.name !== 'background'
}
},
}
}
function getHtmlPlugins(chunks) {
return chunks.map(chunk => new HtmlPlugin({
title: 'React Extension',
filename: `${chunk}.html`,
chunks: [chunk],
}))
}
contentScript, background, options, popup은 각각 다른 entry를 가져야한다. 왜냐하면 그들의 역할, 실행 컨텍스트, 상호 작용 방식이 서로 다르고manifest.sjon 파일에서 정의하는 구조와 규칙에 맞아야 하기 때문이다.

웹팩(Webpack)은 자바스크립트(JS) 애플리케이션을 위한 정적 모듈 번들러다.
웹팩은 애플리케이션을 처리할 때 프로젝트에 있는 모듈을 재귀적으로 빌드하여 하나의 파일(또는 여러 파일)로 번들링하는데, 웹팩의 주요 개념에는 Entry, Output, Loaders, Plugins 등이 있다. 이 개념들을 통해 웹팩은 모듈의 의존성을 파악하고, 애플리케이션을 적절히 조합 및 최적화한다.
나는 참고로 이 다섯가지 플러그인을 사용 하였고
CleanWebpackPlugin: 빌드 전에 dist 폴더를 정리합니다.
CopyPlugin: 정적 파일을 dist 폴더로 복사합니다.
HtmlPlugin: 각 HTML 페이지를 생성합니다. 여기서는 팝업과 옵션 페이지를 위한 HTML 파일을 생성합니다.
DotenvWebpack: .env 파일의 환경 변수를 Webpack으로 불러옵니다.
getHtmlPlugins:이는 동적으로 여러 HTML 파일을 생성하기 위해 사용됩니다.
로더는
ts-loader
style-loader
css-loader를 사용하였다.
tailwind를 사용하기위해 postcss-loader를 사용 하였다.
tailwind를 사용한 것은 나중에 패착으로 이어졌는데 Utility-First CSS때문인지 contentScript가 홈페이지 주입될 때 익스텐션 자체css와 웹페이지 css에 영향을 주었다. 그래서 contentScript를 주로 사용하는 서비스라면 다른 방법을 추천한다.
본인은 이 글을 작성함과 동시에 tailwind가 아닌 다른방식 styled-compoents 또는 css-module을 이용해서 만들어 봄으로써 tailwind가 정말로 문제였는지 알아 보려고 한다.
그 외에 optimization/splitChunks 등을 사용하였다.
구글링과 chatGpt를 이용하면 webpack설정하는 법이 금방 감이 올 것이다.


해당 파일을 만들면 기초적인 설정은 어느정도 한 셈이다.
실제로 익스텐션을 개발하려면 build를 해줘야되는데
package.json에서 설정해 주면된다.
"scripts": {
"start": "webpack --watch --progress --config webpack.dev.js",
"build": "webpack --progress --config webpack.prod.js"
},

모든 파일을 다 만들고 npm run start를 하면 dist폴더가 생성된다.
여기까지 왔는데 빌드가 안된다거나 할경우에는 글의 맨 처음에 있는 깃허브를 참조하거나 git clone해서 구조를 천천히 뜯어보다 보면 해결 될 것이다.





이제부터 본격적으로 익스텐션을 만들 준비가 된 것이다.
(여기서 popup을 설정 해줬다면 익스텐션 아이콘을 클릭하면 popup이 나타날 것이다. 하지만 아무런 설정을 해주지 않았다면 아이콘을 눌러도 아무일도 일어나지 않을 것이다.)
또한 여기서 prettier와 eslint설정은 따로 다루지 않을 생각이다. 본인이 쓰던 설정을 써도 무방하다.