diff --git a/FE/package-lock.json b/FE/package-lock.json index 856d7d3..c4dc835 100644 --- a/FE/package-lock.json +++ b/FE/package-lock.json @@ -18,6 +18,7 @@ "axios": "^1.6.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-ga4": "^2.1.0", "react-router-dom": "^6.18.0", "recoil": "^0.7.7" }, @@ -34,6 +35,7 @@ "@typescript-eslint/parser": "^6.9.1", "babel-loader": "^9.1.3", "copy-webpack-plugin": "^11.0.0", + "dotenv-webpack": "^8.0.1", "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.1", @@ -5622,6 +5624,39 @@ "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dev": true, + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-webpack": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.0.1.tgz", + "integrity": "sha512-CdrgfhZOnx4uB18SgaoP9XHRN2v48BbjuXQsZY5ixs5A8579NxQkmMxRtI7aTwSiSQcM2ao12Fdu+L3ZS3bG4w==", + "dev": true, + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -9257,6 +9292,11 @@ "react": "^18.2.0" } }, + "node_modules/react-ga4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-ga4/-/react-ga4-2.1.0.tgz", + "integrity": "sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==" + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/FE/package.json b/FE/package.json index a89b414..7d2901d 100644 --- a/FE/package.json +++ b/FE/package.json @@ -20,6 +20,7 @@ "axios": "^1.6.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-ga4": "^2.1.0", "react-router-dom": "^6.18.0", "recoil": "^0.7.7" }, @@ -36,6 +37,7 @@ "@typescript-eslint/parser": "^6.9.1", "babel-loader": "^9.1.3", "copy-webpack-plugin": "^11.0.0", + "dotenv-webpack": "^8.0.1", "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.1", diff --git a/FE/src/index.tsx b/FE/src/index.tsx index 9d1fe4a..812794b 100644 --- a/FE/src/index.tsx +++ b/FE/src/index.tsx @@ -1,4 +1,5 @@ import ReactDOM from 'react-dom/client'; +import ReactGA from 'react-ga4'; import { worker } from '@/mocks/browser'; import App from '@/App'; @@ -9,6 +10,11 @@ async function deferRender() { return worker.start(); } +//GA 추적 태그 설정 +if (process.env.REACT_APP_GTAG_ID) { + ReactGA.initialize(process.env.REACT_APP_GTAG_ID); +} + deferRender() .then(() => { const rootElement = document.getElementById('root'); diff --git a/FE/webpack.config.js b/FE/webpack.config.js index ce0a424..d77ac0a 100644 --- a/FE/webpack.config.js +++ b/FE/webpack.config.js @@ -2,6 +2,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('path'); const webpack = require('webpack'); const CopyPlugin = require('copy-webpack-plugin'); +const Dotenv = require('dotenv-webpack'); module.exports = { mode: process.env.production === 'true' ? 'production' : 'development', @@ -44,6 +45,7 @@ module.exports = { new CopyPlugin({ patterns: [{ from: 'public/mockServiceWorker.js', to: '' }], }), + new Dotenv(), ], module: { rules: [