Назад к блогу

Создание Chrome Extension с React, TypeScript и Vite

Пошаговое руководство по созданию и публикации Chrome расширения с использованием React 18, TypeScript, Vite и Manifest V3.

4 декабря 2025 г.автор: Rodion

В этой статье мы создадим Chrome расширение с нуля, используя React, TypeScript и Vite. Построим Freelance Rate Calculator — калькулятор рыночных ставок для разработчиков.

Статья включает:

  • Настройка проекта React + Vite + TypeScript для Chrome Extension
  • Конфигурация manifest.json для Manifest V3
  • Создание UI калькулятора с Tailwind CSS
  • Локальная загрузка и тестирование расширения
  • Публикация в Chrome Web Store

Настройка проекта

Создаём новый Vite проект с React и TypeScript:

npm create vite@latest rate-calculator -- --template react-ts
cd rate-calculator
npm install

Добавляем Tailwind CSS:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Настраиваем tailwind.config.js:

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

Добавляем директивы Tailwind в src/index.css:

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

Добавляем Lucide иконки:

npm install lucide-react

Добавляем Manifest V3

Создаём public/manifest.json:

{
  "manifest_version": 3,
  "name": "Freelance Rate Calculator",
  "version": "1.0.0",
  "description": "Calculate your freelance rate based on tech stack, experience, and location",
  "action": {
    "default_popup": "index.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}

Создаём папку public/icons/ и добавляем иконки расширения в размерах 16x16, 48x48 и 128x128.

Добавляем данные ставок

Создаём src/data/rates.ts с технологиями, уровнями опыта и локациями:

export interface TechStack {
  id: string;
  name: string;
  baseRate: number;
  demand: "high" | "medium" | "low";
}
 
export interface ExperienceLevel {
  id: string;
  name: string;
  years: string;
  multiplier: number;
}
 
export interface Location {
  id: string;
  name: string;
  multiplier: number;
}
 
export const techStacks: TechStack[] = [
  { id: "genai", name: "GenAI / LLM", baseRate: 175, demand: "high" },
  { id: "rust", name: "Rust", baseRate: 135, demand: "high" },
  { id: "react", name: "React", baseRate: 90, demand: "high" },
  { id: "typescript", name: "TypeScript", baseRate: 92, demand: "high" },
  { id: "nodejs", name: "Node.js", baseRate: 85, demand: "high" },
  { id: "python", name: "Python", baseRate: 90, demand: "high" },
  // добавьте больше стеков...
];
 
export const experienceLevels: ExperienceLevel[] = [
  { id: "junior", name: "Junior", years: "0-2 года", multiplier: 0.55 },
  { id: "mid", name: "Middle", years: "3-5 лет", multiplier: 1.0 },
  { id: "senior", name: "Senior", years: "5-8 лет", multiplier: 1.45 },
  { id: "lead", name: "Lead / Architect", years: "8+ лет", multiplier: 1.85 },
];
 
export const locations: Location[] = [
  { id: "usa", name: "США", multiplier: 1.0 },
  { id: "uk", name: "Великобритания", multiplier: 0.85 },
  { id: "germany", name: "Германия", multiplier: 0.82 },
  { id: "japan", name: "Япония", multiplier: 0.62 },
  { id: "india", name: "Индия", multiplier: 0.32 },
  // добавьте больше стран...
];

Формула расчёта ставки:

const getMarketRate = (
  stack: TechStack,
  exp: ExperienceLevel,
  loc: Location
) => {
  const base = stack.baseRate * exp.multiplier * loc.multiplier;
  return {
    low: Math.round(base * 0.85),
    mid: Math.round(base),
    high: Math.round(base * 1.15),
  };
};

Пример: Senior React разработчик в Германии = 90 * 1.45 * 0.82 = $107/час

Создаём UI калькулятора

Обновляем src/App.tsx с формой калькулятора:

import { useState } from "react";
import { techStacks, experienceLevels, locations } from "./data/rates";
import type { TechStack, ExperienceLevel, Location } from "./data/rates";
 
function App() {
  const [stack, setStack] = useState<TechStack | null>(null);
  const [experience, setExperience] = useState<ExperienceLevel | null>(null);
  const [location, setLocation] = useState<Location | null>(null);
  const [myRate, setMyRate] = useState("");
  const [showResult, setShowResult] = useState(false);
 
  const getMarketRate = () => {
    if (!stack || !experience || !location) return null;
    const base = stack.baseRate * experience.multiplier * location.multiplier;
    return {
      low: Math.round(base * 0.85),
      mid: Math.round(base),
      high: Math.round(base * 1.15),
    };
  };
 
  const handleCheck = () => {
    if (stack && experience && location && myRate) {
      setShowResult(true);
    }
  };
 
  // рендерим форму или результаты в зависимости от showResult
  return (
    <div className="w-[400px] h-[600px] p-4 bg-gray-900 text-white">
      {/* форма и результаты */}
    </div>
  );
}
 
export default App;

Устанавливаем фиксированные размеры popup в src/index.css:

body {
  width: 400px;
  height: 600px;
  margin: 0;
  overflow: hidden;
}

Форма ввода с dropdown для стека, опыта и локации:

Форма ввода Rate Calculator

Экран результатов со сравнением рыночных ставок:

Результаты Rate Calculator

Сборка расширения

Обновляем vite.config.ts для сборки расширения:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
 
export default defineConfig({
  plugins: [react()],
  build: {
    outDir: "dist",
    rollupOptions: {
      input: "index.html",
    },
  },
});

Собираем расширение:

npm run build

Это создаёт папку dist/ с файлами расширения.

Загрузка расширения локально

Открываем Chrome и переходим на chrome://extensions. Включаем "Режим разработчика" в правом верхнем углу.

Нажимаем "Загрузить распакованное расширение" и выбираем папку dist/.

Расширение загружено в Chrome

Нажимаем на иконку расширения в панели инструментов для тестирования popup.

Публикация в Chrome Web Store

Переходим в Chrome Web Store Developer Dashboard.

При первой публикации требуется единоразовая оплата $5.

Подготавливаем ассеты:

  • Иконка расширения: 128x128 PNG
  • Скриншот: 1280x800 или 640x400
  • Промо-плитка: 440x280

Создаём ZIP папки dist/:

cd dist && zip -r ../extension.zip . && cd ..

Загружаем ZIP, заполняем описание, добавляем скриншоты, отправляем на проверку.

Проверка занимает 1-3 дня. Частые причины отклонения:

  • Переспам ключевых слов в описании
  • Отсутствие политики конфиденциальности (при использовании разрешений)
  • Некорректные скриншоты

После одобрения:

Расширение опубликовано в Chrome Web Store

Заключение

Готово. Мы создали Chrome расширение с React, TypeScript и Vite, протестировали локально и опубликовали в Chrome Web Store.

Финальный стек:

  • React 18
  • TypeScript
  • Vite
  • Tailwind CSS
  • Manifest V3

Расширение: Freelance Rate Calculator

Понравилась статья? Подписывайтесь на Twitter @Nefayran — #buildinpublic контент.

Похожие статьи

Создание Chrome Extension с React, TypeScript и Vite - AllKeep Blog