This is the React-based frontend client for FreeFeed — an open-source social network. The app is a single-page application built with React 19, Redux, and Vite.
- Framework: React 19
- State management: Redux 5
- Builder: Vite 7
- Styling: SCSS (Sass), CSS Modules, Bootstrap 3
- Testing: Vitest + Testing Library
- Package manager: Yarn 4 (Berry)
- Linting: ESLint 9 (flat config), Stylelint 17, Prettier
src/components/— React componentssrc/redux/— Redux actions, reducers, middlewaressrc/services/— Side-effect services (API, lightbox, real-time socket, etc.)src/utils/— Pure utility functions and helpersstyles/— Global SCSS styles and shared partialsconfig/— App configuration defaults and schematest/jest/— Snapshot tests (run via Vitest)test/unit/— Unit tests
yarn start # dev server with hot reload (uses candy.freefeed.net as backend)
yarn test # run all tests
yarn lint # ESLint
yarn stylelint # Stylelint for SCSS
yarn checks # run tests + lint + stylelint in parallel
yarn build-prod # production build into _dist/
yarn build-modern # faster build (modern browsers only), useful for build validationBefore submitting any changes, make sure they pass all of the following checks:
yarn lint— ESLint must report no errorsyarn stylelint— Stylelint must report no errorsyarn test— all tests must pass
Run yarn checks to execute all three in parallel. Use yarn build-modern to quickly verify the build compiles without errors (faster than the full production build).
Before opening a pull request, add a brief description of the proposed change to the ## [x.y.z] - Not released section of CHANGELOG.md.
Feature branches must be started from the stable branch.
Commit messages must be in English, ideally fitting in one line ≤80 characters. More detailed commit messages (with body after the subject) are used only for complex and non-obvious changes.
Entry point: src/index.js loads config.json, then bootstraps src/app.jsx.
src/app.jsx creates the Redux store, defines all routes, and renders the root <App> component.
Data flow:
- A route change or user action dispatches an action creator from
src/redux/action-creators.js - Action creators that need the API attach an
apiRequestproperty —apiMiddlewarepicks it up and callssrc/services/api.js - The response is dispatched as a follow-up action and handled by reducers in
src/redux/reducers/ - Real-time events arrive via Socket.IO (
src/services/realtime.js) and are dispatched as regular actions
Routing: Routes are declared in src/app.jsx using <Route> / <Switch> / <Router> from src/services/nouter/. To add a new page:
- Create a component in
src/components/your-page/ - Add a
<Route path="your-path" component={YourPage} />insrc/app.jsx - If the route needs data, add an
onEnter/onChangehook that dispatches the appropriate action creator
Adding a Redux action:
- Add a constant to
src/redux/action-types.js - Add a creator function to
src/redux/action-creators.js(attachapiRequestfor API calls) - Handle the action in the relevant reducer in
src/redux/reducers/. Prefer adding new reducers as separate files insrc/redux/reducers/rather than extending the monolithicsrc/redux/reducers.js
- JSX files use
.jsxextension - Prefer functional components with React hooks over class components
- CSS Modules are used for component-scoped styles (
.module.scss) - Use
lodash-es(notlodash) for tree shaking - Imports must be at the top of files
- Comments in code must be in English
- Pre-commit hooks run Prettier and ESLint via lint-staged (managed by Husky)
- Current (unreleased and current year) changes go in
CHANGELOG.mdat the repo root - The top section is always
## [x.y.z] - Not releasedfor changes not yet deployed - Past years are archived in
changelogs/CHANGELOG_YYYY.md - Follow Keep a Changelog format
- The lightbox is powered by PhotoSwipe 5 (
src/services/lightbox-actual.js);src/services/lightbox.jsis a thin facade - Text parsing (posts, comments) is handled by
social-text-tokenizer lodash-esis used instead oflodashfor tree shaking — do not import fromlodash- Redux DevTools are supported in development (via
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__)