Fluent Reader is a modern desktop RSS reader built with Electron + React + Redux + TypeScript. It targets Windows, macOS (including Mac App Store), and Linux. The UI uses Microsoft's Fluent UI (v7) component library. Data is stored client-side using Lovefield (SQL-like browser DB) and NeDB. Articles are parsed with Mercury Parser and fetched via rss-parser. Settings are persisted with electron-store.
The repository is ~80 TypeScript/TSX source files under src/. There is no ESLint — formatting is handled solely by Prettier.
Always run commands from the repository root.
npm installRun this before every build. The lockfile (package-lock.json) is gitignored (.lock in .gitignore), so npm install resolves from package.json each time.
npm run buildThis runs webpack --config ./webpack.config.js, which produces three bundles in dist/:
electron.js— Electron main process (fromsrc/electron.ts)preload.js— Preload script (fromsrc/preload.ts)index.js+index.html— Renderer/React app (fromsrc/index.tsx)
Build takes ~30 seconds. A successful build ends with three "compiled successfully" lines — one per webpack config entry.
npm run electronOr combined install + build + run:
npm run startnpx prettier --check .To auto-fix formatting:
npm run formatAlways run npx prettier --check . after making changes to ensure code style compliance. The Prettier config is in .prettierrc.yml: 4-space tabs, no semicolons, JSX bracket on same line, arrow parens avoided, consistent quote props. .prettierignore excludes dist/, bin/, node_modules/, HTML, Markdown, and most JSON (except src/**/*.json).
Basic validation of code changes consists of:
npm run build— must compile without errors.npx prettier --check .— must pass with no formatting violations.
A private suite of E2E tests is available for project maintainers. Run the suite from the repository root:
npm --prefix tests/e2e testSee tests/README.md for test setup details.
- Windows:
npm run package-win - macOS:
npm run package-mac - Linux:
npm run package-linux - Mac App Store:
npm run package-mas(requires provisioning profile and entitlements inbuild/)
Two GitHub Actions workflows in .github/workflows/:
release-main.yml— Triggered on version tags (v*). Runs onwindows-latest. Steps:npm install→npm run build→npm run package-win-ci. Uploads.exeand.zipto a draft GitHub release.release-linux.yml— Triggered when a release is published. Runs onubuntu-latest. Steps:npm install→npm run build→npm run package-linux. Uploads.AppImage.
Both CI pipelines run npm install then npm run build. There are no lint or test steps in CI.
| File | Purpose |
|---|---|
package.json |
Dependencies, scripts, metadata (v1.1.4) |
webpack.config.js |
Three webpack configs: main, preload, renderer |
tsconfig.json |
TypeScript: JSX=react, target=ES2019, module=CommonJS, resolveJsonModule |
electron-builder.yml |
Electron Builder config for Win/Mac/Linux distribution |
electron-builder-mas.yml |
Electron Builder config for Mac App Store |
.prettierrc.yml |
Prettier formatting rules |
.prettierignore |
Files excluded from Prettier |
| Path | Description |
|---|---|
electron.ts |
Electron main process entry. Creates app menu, initializes WindowManager. |
preload.ts |
Preload script. Exposes settingsBridge and utilsBridge via contextBridge. |
index.tsx |
Renderer entry. Mounts React <Root> with Redux <Provider>. |
schema-types.ts |
Shared TypeScript enums and types (ViewType, ThemeSettings, etc.) |
bridges/ |
IPC bridges between renderer and main process (settings.ts, utils.ts). |
main/ |
Electron main-process modules: window.ts (BrowserWindow), settings.ts (electron-store + IPC handlers), utils.ts (IPC utilities), touchbar.ts, update-scripts.ts. |
scripts/ |
Renderer-side logic (runs in browser context). |
scripts/reducer.ts |
Root Redux store — combines: sources, items, feeds, groups, page, service, app. |
scripts/settings.ts |
Theme management, locale setup, Fluent UI theming. |
scripts/db.ts |
Lovefield database schema definitions (sources, items). |
scripts/utils.ts |
Shared utilities and type helpers. |
scripts/models/ |
Redux slices: app.ts, feed.ts, group.ts, item.ts, page.ts, rule.ts, service.ts, source.ts, plus services/ for RSS service integrations. |
scripts/i18n/ |
Internationalization. _locales.ts maps locale codes to JSON files. 19 languages. Translations are JSON files (e.g., en-US.json). Uses react-intl-universal. |
components/ |
React UI components. root.tsx is the top-level layout. Sub-dirs: cards/ (article card variants), feeds/ (feed list views), settings/ (settings panels), utils/ (shared UI helpers). |
containers/ |
Redux-connected container components that map state/dispatch to component props. |
The dist/ directory contains both webpack output and checked-in static assets. Files like dist/icons/, dist/article/, dist/styles/, dist/index.css, dist/fonts.vbs, and dist/fontlist are static and tracked in git. The webpack-generated files (*.js, *.js.map, *.html, *.LICENSE.txt) are gitignored.
Contains app icons (build/icons/), macOS entitlements plists, provisioning profiles, and resignAndPackage.sh for Mac App Store builds. Also has build/appx/ for Windows Store assets.
- IPC pattern: The renderer never imports Electron directly. All Electron APIs are accessed through
src/bridges/which are exposed viacontextBridgeinpreload.ts. Settings state flows: renderer → bridge (ipcRenderer) → main/settings.ts (ipcMain handlers) → electron-store. - State management: Redux with
redux-thunkfor async actions. The store shape is defined byRootStateinscripts/reducer.ts. Each model file inscripts/models/exports its own reducer, action types, and thunk action creators. - i18n: To add or modify translations, edit JSON files in
src/scripts/i18n/. Register new locales in_locales.ts. - RSS service integrations: Located in
src/scripts/models/services/(logic) andsrc/components/settings/services/(UI). Supported: Fever, Google Reader API (GReader), Inoreader, Feedbin, Miniflux, Nextcloud.
- All source is TypeScript (
.ts/.tsx). No plain JavaScript insrc/. - No semicolons. 4-space indentation. See
.prettierrc.yml. - Enums use
const enumpattern inschema-types.ts. - Components use both class components and function components (no strict rule).
- Redux containers in
containers/useconnect()from react-redux. - Griffel styling: Use
makeStylesfrom@griffel/reactfor component-scoped styles. ImportmergeClassesfor combining classes. Prefer Griffel over adding new CSS rules todist/styles/. styleClassprop convention: Reusable components expose astyleClass?: stringprop applied to the component's main element, allowing parents to pass Griffel-generated class overrides. If a component has multiple customizable elements, use element-specific prop names (e.g.,buttonStyleClass?: string). Combine base and override classes withmergeClasses.- Flat button components:
FlatButton,FlatButtonGroup, andFlatButtonSeparatorinsrc/components/utils/implement the Griffel +styleClasspattern. Use these instead of raw<button>/<div>with CSS class names for toolbar-style buttons.
After any code change, always run:
npm install && npm run build && npx prettier --check .All three must succeed. If the build fails, fix TypeScript errors. If prettier fails, run npm run format then verify.
Run the E2E test suite if available at the end of sessions to check for regressions, and update the test suite to cover any new features built.
Trust these instructions. Only search the codebase if information here is incomplete or found to be incorrect.