-
Chrome Extension 개발 이제 여기에 react를 끼얹은...javascript 2021. 2. 12. 01:48
검색검색을 하다가 비교적 최신의, 귀여운 react로 만든 chrome extension 프로젝트를 찾았다.
이 문서는 아래 아티클에 대한 번역 + 따라가는 과정이 담겨있습니다.
https://react.christmas/2020/12
Chrome Extension의 기초
extension에는 세가지 메인 컴포넌트가 있습니다. popup, content script, background script입니다.
- Popup은 extension icon이 눌리면 뜨는 콘텐츠입니다.
- Content script는 Javascript나 CSS로 된 코드이고, 현재 웹 페이지의 context에 주입(inject)됩니다.
- Background script는 브라우저에서 분리된 인스턴스로 실행되는 javascript 코드입니다. 그리고 거의 이벤트를 listening하고, 브라우저를 다루기 위해서 사용됩니다.
(저) 아티클에서는 react와 typescript를 이용하여 chrome extension을 만들어 보도록 하겠습니다.
프로젝트 셋팅
create-react-app으로 리액트 프로젝트를 시작하면 쉽지만, chrome extension으로 개발하기에는 좀 까다로운 편이어서 저 아티클에서는 Webpack을 기반으로 리액트 프로젝트를 구상합니다.
미리 만든 보일러플레이트를 기반으로 우선 디렉토리를 구상합니다.
$ npx degit https://github.com/sivertschou/react-typescript-chrome-extension-boilerplate.git#christmas snow-extension
npx degit 명령어는 clone을 하고, 그 repository의 git 파일들을 삭제합니다. 따라서 위 git repo의 파일을 순수하게 (기존 git dependency 없이 사용할 수 있습니다)
이 프로젝트는, react의 build 결과 -> dist 폴더를 extension으로 업로드 하도록 구성되어 있습니다.
그래서 일단 manifest를 조작할 수 있는 public부터 보시죠
public
public 폴더에는 extension의 meta data가 되는 애들이 들어갑니다.
icon 이미지 파일들, popup으로 띄울 - react의 mounting point인 popup.html, extension의 config가 되는 manifest.json
manifest.json이 extension개발의 가장 중요한 파일이므로 이 파일을 먼저 봅시다.
우선, metadata가 되는 name, description, manifest_version, version을 설정합니다.
(여기서는 manifest_version을 2로 설정했네요)
그리고 아이콘은 적어도 16, 48, 128에 대해서는 제공해야만 합니다.
// public/manifest.json { "name": "Snow Extension", "description": "Chrome Extension for making it snow in your browser!", "manifest_version": 2, "version": "1.0.0", "icons": { "16": "icon16.png", "48": "icon48.png", "128": "icon128.png" }, ...
extension을 클릭 할 때 띄울 popup에 대한 설정은 browser_action이나 page_action으로 가능합니다.
page_action은 특정 페이지에서만 뜨도록 설정되는데, 그에 반해 browser_action으로 설정하면 어떤 페이지든 브라우저에서 popup을 띄울 수 있으므로, 여기서는 browser_action으로 popup에 대한 설정을 하겠습니다.
browser_action의 default_icon은 브라우저에서 클릭 가능한 아이콘의 이미지를 의미합니다. 우리가 클릭하는 바로 그 아이콘 말이죠.
그리고 defuault_popup 은 그 아이콘이 클릭될 때 뜰 popup에 대한 설정 정보입니다. 여기서는, React 코드를 실행할 그 popup.html이죠.
// public/manifest.json ... "browser_action": { "default_icon": { "16": "icon16.png", "48": "icon48.png" }, "default_popup": "popup.html" } ...
background script는 아래와 같이 설정합니다.
.ts가 아닌 .js로 쓴 것은 이 script는 그대로 browser에서 실행되는 것이어서, ts로는 실행이 불가합니다. 우리는 .ts로 파일을 만들더라도 이게 js로 빌드된 결과물이 들어가야하죠.
persistent: false 설정은, 이 background script를 항상 불러올지, idle일땐 업로드하지 않을지에 대한 설정입니다. 여기서는 false로 하면서 extension이 idle 상태일 때 background script가 로딩되지 않게 설정하였습니다.
// public/manifest.json ... "background": { "scripts": [ "background.js" ], "persistent": false }, ...
content_scripts 에서는 "특정" 웹 페이지에서 실행될 script를 설정합니다. matches를 통해 해당 script가 주입되고, 실행 될 페이지 주소를 지정할 수 있고, 여기서는 모든 페이지로 설정했습니다. background script 설정과 같이 content_scripts로 지정하는 js 역시 .js 포맷이어야 합니다.
// public/manifest.json ... "content_scripts": [ { "matches": [ "*://*/*" ], "js": [ "content.js" ] } ] }
src 둘러보기
우리가 필요할 파일은 popup.html에 들어갈 popup.js(보통의 react 프로젝트에서의 index.js), background.js, content.js 입니다.
물론 우리는 이 프로젝트를 ts로 개발 할 것이기 때문에, 빌드 결과물이 그렇게 나와야겠죠. - 이 부분은 webpack의 도움을 받읍시다.
popup.tsx로 index.js와 같은 구성을 하고 - document의 특정 id에 <App/>을 root로 두는 React component를 뿌립니다. - 그 이하 App의 구성 component들이 있겠죠. 여기서는 App.tsx로 충분했습니다. 따라서 다음과 같은 파일 구성이 되었습니다.
- App.css - App.tsx - background.ts - content.ts - custom.d.ts - logo.svg - popup.css - popup.tsx
Content script 작성하기
현재 content script는 console.log를 찍는 한 줄 뿐입니다. 지금대로면 모든 페이지 진입시마다 content.ts가 실행되고, console log가 찍히는 것을 볼 수 있습니다.
console.log("Hello from content script!")
여기다가 눈이 내리게 하는 코드를 끼얹으면 끝! 이 이하는 코드 복붙으로 완성되어서 넘어갑니다. - 리액트 관련된건 넘어갔으니!
Webpack 설정 보기
여기서는 3개의 entry가 필요합니다. 각각 popup.tsx, content.ts, background.ts 이죠. 그리고 각각 그 이름으로 된 js 파일로 output 되어야 합니다.
const config = { entry: { popup: path.join(__dirname, "src/popup.tsx"), content: path.join(__dirname, "src/content.ts"), background: path.join(__dirname, "src/background.ts"), }, output: { path: path.join(__dirname, "dist"), filename: "[name].js" },
module로는 js babel-loader, css loader, ts loader, svg loader, png loader가 들어갔습니다.
..., module: { rules: [ { test: /\.(js|jsx)$/, use: "babel-loader", exclude: /node_modules/, }, { test: /\.css$/, use: ["style-loader", "css-loader"], exclude: /\.module\.css$/, }, { test: /\.ts(x)?$/, loader: "ts-loader", exclude: /node_modules/, }, { test: /\.css$/, use: [ "style-loader", { loader: "css-loader", options: { importLoaders: 1, modules: true, }, }, ], include: /\.module\.css$/, }, { test: /\.svg$/, use: "file-loader", }, { test: /\.png$/, use: [ { loader: "url-loader", options: { mimetype: "image/png", }, }, ], }, ], },
아래 설정은 참고 할만 한 것 같습니다
resolve: { extensions: [".js", ".jsx", ".tsx", ".ts"], alias: { "react-dom": "@hot-loader/react-dom", }, }, devServer: { contentBase: "./dist", }, plugins: [ new CopyPlugin({ patterns: [{ from: "public", to: "." }], }), ],
여기까지 코드를 바탕으로 react, typescript로 chrome extension 개발하는 틀을 잘 잡을 수 있을 것 같군요 :b
'javascript' 카테고리의 다른 글
Chrome Extension 개발 해보기 - Getting Started 따라하기 (0) 2021.02.11 [typescript] nodejs 서버 구축하기 - 1 (0) 2020.12.07 Javascript class의 내부 함수, method (0) 2020.11.26 Javascript Import에 대하여 - import React from 'react' (0) 2020.11.23 javascript를 쓰지만 내가 잘 몰랐던 것들 (0) 2020.10.20