Skip to content

Commit 1e96747

Browse files
authored
Decoupled arch v2 (#17)
* Add sdorsys boilerplate * Add sharp w typescript * Add frontend mock * Refactor backend into /electron * Add FE module * Add dynamic loading of FE assets * Add TS support to the FE * Add basic yarn workspace (shared/frontend) * Add waiting to electron module & update module import in electron * Update readme * Add storybook support * Add eslint to the electron ts code * Add jest support in the backend * Add tests to FE * Clean FE styles * Add render to render IPC communications * Add atoms and molecules (component library) * Add molecules and organisms * Add navBar molecule * Update molecules * Add start page, add static and clean tests * Add pre-processing and settings pages * Fix gallery bug and add dashboard page * Add shared types and add component type inference * Add redux dependency to FE * Add redux and real types * Update shared module types, message bug, and todos * Add BE messageBus handler skeleton & ML * Add DB module and tests * Add destroy handler, type refactors and twitter link * Add reset handler dep injection and tests * Update handlers and add utils * Break down services and add dependency injection * Add tests for the date service * Add file service types and tests * Add test coverage and comments to image service * Add exposed types in services and handlers * Fix webId population, add handler dep injection * Clean up sharp loading and add processing (not working yet) * Add test skeleton for the ML operations and test-images * Add tag tests, update classification services and types * Add custom tag types * Update tests * Add filter images with location, update types and message bus * Fix backend tests and clean up FE dead tests * Update FE build leftovers * Enable loading local image files * Add FE fonts * Add ML dependencies to BE * Add box shadow to UI buttons * Clean up isProcessing dependency from FE -> Redux * Remove unused prop isProcessing from store and UI * Fix flanky test (jest --clearCache) * Add fallback to map component * Fix shared build error (due to TF) * Fix button shadow * Silence process errors and fix image paths * Add react and redux extensions to electron main * Clean up unused config * Fix filtering bug * Add app icon and update todos * Update app naming in FE * Remove isDev dependency + skeleton of docs * Add CI support * Update CI workflow files * Add craco to fix map bug visgl/react-map-gl#1266 * Clean up sharp dependency * Fix the map issue by rolling back * Hide backend window in prod * Update isDev flag * Clean tasks * Add partial README * Add documentation * Optimize build * Update tests * Update CI to only run on PRs * Clean up old README * Remove CI * Add screenshot
1 parent 6da7edc commit 1e96747

File tree

207 files changed

+39019
-24145
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

207 files changed

+39019
-24145
lines changed

.babelrc

-6
This file was deleted.

.gitignore

+21-89
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,28 @@
1-
electron-old
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
22

3-
# Logs
4-
logs
5-
*.log
6-
npm-debug.log*
7-
yarn-debug.log*
8-
yarn-error.log*
9-
lerna-debug.log*
10-
11-
# Diagnostic reports (https://nodejs.org/api/report.html)
12-
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13-
14-
# Runtime data
15-
pids
16-
*.pid
17-
*.seed
18-
*.pid.lock
19-
.DS_Store
20-
21-
# Directory for instrumented libs generated by jscoverage/JSCover
22-
lib-cov
23-
24-
# Coverage directory used by tools like istanbul
25-
coverage
26-
*.lcov
27-
28-
# nyc test coverage
29-
.nyc_output
30-
31-
# node-waf configuration
32-
.lock-wscript
33-
34-
# Compiled binary addons (https://nodejs.org/api/addons.html)
35-
build/Release
36-
37-
# Dependency directories
38-
node_modules/
39-
jspm_packages/
40-
41-
# TypeScript v1 declaration files
42-
typings/
43-
44-
# TypeScript cache
45-
*.tsbuildinfo
46-
47-
# Optional npm cache directory
48-
.npm
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
497

50-
# Optional eslint cache
51-
.eslintcache
8+
# testing
9+
/coverage
5210

53-
# Optional REPL history
54-
.node_repl_history
11+
# production
12+
/build
5513

56-
# Output of 'npm pack'
57-
*.tgz
58-
59-
# Yarn Integrity file
60-
.yarn-integrity
61-
62-
# dotenv environment variables file
63-
# .env
64-
.env.test
65-
66-
# parcel-bundler cache (https://parceljs.org/)
67-
.cache
68-
69-
# next.js build output
70-
.next
71-
72-
# nuxt.js build output
73-
.nuxt
74-
75-
# vuepress build output
76-
.vuepress/dist
77-
78-
# Serverless directories
79-
.serverless/
80-
81-
# FuseBox cache
82-
.fusebox/
83-
84-
# DynamoDB Local files
85-
.dynamodb/
86-
87-
# Webpack
88-
.webpack/
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
8920

90-
# Electron-Forge
91-
out/
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
9224

93-
electron/src/env.json
9425

95-
# ts
96-
dist
26+
shared/dist
27+
shared/node_modules
28+
electron/renderer-frontend/

README.md

+102-48
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,130 @@
11
# taggr
22

3-
Rediscover your **memories** while keeping your **privacy**.
3+
> Rediscover your **memories** while keeping your **privacy**.
44
5-
Powered by machine learning.
5+
Powered by [TypeScript](https://www.typescriptlang.org/), [Electron](https://www.electronjs.org/), [React](https://reactjs.org/), [Redux](https://redux-toolkit.js.org/), [Node.js](https://nodejs.org/en/) and [TensorFlow.js](https://www.tensorflow.org/) 🚀
66

7-
## Architecture
7+
![taggr screenshot](./test-images/screenshot.png "taggr")
88

9-
`frontend` and `backend` are one.
9+
<p style="text-align: center;">👉 <a href="https://twitter.com/aperkaz">Keep up to date with my next side-projects</a> 👈</p>
1010

11-
**Modularized structure** for UI and backend, running on separated `BrowserWindow` processes: `renderer` for UI, `background` for backend.
11+
## Motivation
1212

13-
This allows to perform the long and resource intensive backend operations without blocking the UI thread (in development only). In production, the backend BrowserWindow is hidden.
13+
There is great software out there that provides image exploration capabilities using machine learning (Google Photos, iCloud), but generally is not build with privacy in mind.
1414

15-
**Message passing** interconnection betweeen modules, through [Broadcast Channel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API).
15+
At the end of the day, you have to upload your pictures to a server (which perform the machine learning operations), so you have to trust a third party with your data.
1616

17-
Since the backend executes long running tasks, sync connections are not an option. The message passing acts as a the communication interfact between modules. Each module (FE/BE) implements a `message-handler`, which deal with the incomming (`message`) on a given topic.
17+
What if we could run image classification and tagging machine learning operations 100% locally?
18+
You dont have to trust a server if there is no server 😉
1819

19-
Available messaging topics and action cretors are shared and centralized in `./shared/message-passing`.
20+
👇 _Under this premise, **taggr** was born_ 👇
2021

21-
## Environments
22+
A photo explorer, which uses offline machine learning for enriched exploration.
2223

23-
3 app environments. `DEVELOP`, `BUILD_TEST` and `BUILD_PROD`.
24+
Build with privacy in mind, all the image processing is performed locally, and no data ever leaves you computer 😊
2425

25-
Manually set the value in `src/shared/active-env.js`.
26+
## High-level architecture
2627

27-
## Publishing
28+
This is my first electron project, so I iterated multiple times until I settled on a general strucutere I was happy with (at developer experience and performance levels).
2829

29-
Run:
30+
In my case, I found the sweet spot by keeping as close to the web standard as possible, and leveraging the existing web / Node.js tooling that already exists. That mweant
3031

31-
```javascript
32-
npm run publish
33-
```
32+
**taggr** is composed by two main modules (`frontend`, `backend`), a `shared` module, and a `communication bus`.
33+
34+
The app is split into two distinct and independent processes, the `frontend` and the `backend` (mapping to the main modules), for the sake of separation of concerns. Each process runs in an [independent Electron process](https://blog.logrocket.com/advanced-electron-js-architecture/).
35+
36+
### Message bus
37+
38+
Before we cover the modules, lets discuss the communication layer.
39+
40+
The `frontend` and `backend` modules communicate through an asynchonous and bidirectional message bus.
41+
Its implemented using Electron's [IPC module](https://www.electronjs.org/docs/latest/api/ipc-main/).
42+
43+
The supported events are defined as types in the `shared` module, so type-safe handlers can be implemented in either side of the bus. For example in `frontend/src/message-bus/index.ts`.
44+
45+
Since the message bus relies on the `BrowserWindow.id`, the Electron main process keeps a heartbeat with the render process ids.
46+
47+
### Frontend → `./frontend`
48+
49+
The 'face' of the app, this module takes care of all things UI.
50+
51+
It does **not** hold business logic. It communicates with the `backend` for performing business logic operations (through the message bus).
52+
53+
**Built with Typescript + React components**, following (loosely) the [Atomic Design Principles](https://bradfrost.com/blog/post/atomic-web-design/). I used [Storybook](https://storybook.js.org/) for that.
54+
55+
The whole UI is **[controlled](https://www.robinwieruch.de/react-controlled-components)**, so it renders determinstically based on props, using [pure componets](https://www.geeksforgeeks.org/reactjs-pure-components/). Note that some state is kept local with Hooks, but thats UI state (ex. input contents before submission).
56+
57+
Uses the **'smart' and 'dumb' component** [pattern](https://jaketrent.com/post/smart-dumb-components-react), only the `Page` component have side effects, passed as props by container components. The whole UI can be tested and migrated form Redux and Electron easily. Check `frontend/src/components/pages/**/WithStore.tsx` for examples.
58+
59+
In order to deploy the app, the `frontend` gets build into static assets and copied over to the `backend` module.
60+
61+
### Backend → `./electron`
62+
63+
The 'brain' of the app, this module focuses on the business logic, processing and persistence of the data.
64+
65+
The module also contains the Electron logic for bootstraping the render processes (one for `frontend` and another for the `backend`) and for packaging the app.
3466

35-
Generated prod buil and updates the `taggr-releases` repo. Generate build in windows and update it manually. Make sure that the `taggr` version in the package.json is updated.
67+
**Written in TypeScript**, it operates as a Node.js backed. Runs withing a [Electron renderer process](https://www.electronjs.org/docs/latest/tutorial/process-model), with the Node.js APIs enabled. Source code available in `./electron/renderer-backend/src`
3668

37-
1. Execute `npm run publish`
38-
2. Increate the version in `electron/package.json`
39-
3. Build windows and upload manually.
69+
The message bus handler triggers [transactional scripts](https://martinfowler.com/eaaCatalog/transactionScript.html), which composes the functionality provided by a service layer.
4070

41-
### Releases
71+
The service layer uses dependency injection through [factory functions](https://www.javascripttutorial.net/javascript-factory-functions/), so it can be easily tested with unit tests.
72+
73+
The machine-learning uses classification and object recognition for extracting searchable tags from images, through [Tensorflow](https://github.com/tensorflow/tfjs).
74+
75+
The storage of extracted tags is managed using [electron-store](https://github.com/sindresorhus/electron-store).
76+
77+
### Shared → `./shared`
78+
79+
A type-only module, helps keep type consistency between `frontend` and `backend`.
80+
81+
It keeps shared data such as the available frontend routes, the supported message bus messages and typed representations of the shared domain entities (such as `Image`).
82+
83+
This enables compile-time checks on the touch points at the message bus level. Also, it helps keep domain entities consistently typed accross the app.
84+
85+
### Environments
86+
87+
The app can be configured to run in `development` and `production` environtments, by setting a variable in the `shared` module.
88+
89+
- `development`: the frontend runs in a separate process and is loaded into electron as a url.
90+
91+
- `production`: the frontend is loaded from static files, and the backend window is hidden. All the debugging tools and extensions are not mounted.
92+
93+
## Run it
94+
95+
Requires `"node": ">=14.0.0"` and `"yarn": "^1.22.0"`.
96+
97+
```bash
98+
# install dependencies
99+
yarn
100+
101+
# run unit test
102+
yarn test:ci
103+
104+
# start app
105+
yarn app
106+
107+
# build app
108+
yarn build
109+
```
42110

43-
https://github.com/aperkaz/taggr-releases/releases
111+
## Releases
44112

45-
## Future Features
113+
<https://github.com/aperkaz/taggr-releases/releases>
46114

47-
- Layout masonry: https://github.com/bvaughn/react-virtualized/issues/1366
48-
- Certificate trust increase: https://support.ksoftware.net/support/solutions/articles/215894-what-is-this-file-is-not-commonly-downloaded-and-could-harm-your-computer-message-smartscreen-
49-
- Add github actions build: https://github.com/malept/electron-forge-demo123/actions/runs/116519042/workflow
50-
- Some images are displayed rotated, example in thailand trip
51-
- Replace gallery view with lazy loading: https://github.com/xiaolin/react-image-gallery
52-
- Timeline with pictures https://github.com/rmariuzzo/react-chronos
53-
- Timeline display of images per day http://tany.kim/quantify-your-year/#/
54-
- Add more ML: look into tensorflow alternatives: evaluate performance: with article https://learn.ml5js.org/docs/#/reference/face-api?id=demo
55-
- Speed up app by paralelization. Example: https://github.com/aperkaz/tensorflow-playground
56-
- Food classification: https://github.com/stratospark/food-101-keras/issues/14
57-
- File sharing options:
58-
https://share.storewise.tech/upload
59-
https://safenote.co/upload-file ??
115+
## Future
60116

61-
### Not so relevant
117+
**taggr** has been a great side project for the past year, I learned plenty about how Electron works internally, how to structure controlled frontends and had lots of fun 🎉
62118

63-
- micro animations: https://www.joshwcomeau.com/react/boop/
64-
- Add node_modules migration, to fix the known issues.
65-
- Image editor: https://ui.toast.com/tui-image-editor/
119+
I have other ideas I want to develop, so I dont plan on working on taggr any time soon.
66120

67-
## Known Issues
121+
Feel free to **fork** or open PRs!!
68122

69-
- **Windows / Mac build**: the tfjs bindings for windows are not located properly, they are built into `napi-v6`, it should be renamed to `napi-v5`. In `electron/node_modules/@tensorflow/tfjs-node/lib/napi-v6`, rename.
123+
## Credit
70124

71-
## Resources of interes
125+
Here are some of the great resources I have leveraged to build **taggr**, in no particular order:
72126

73-
- Modern electron apps: https://github.com/jlongster/electron-with-server-example
74-
- High-level project structure: https://blog.axosoft.com/electron-things-to-know/
75-
- Window builds fail randomly due to problems with the cache. Try to clean cache and delete package-lock as in: https://github.com/cncjs/cncjs/issues/172
76-
- EU vat (local VAT up to 10.000E a year): https://europa.eu/youreurope/business/selling-in-eu/selling-goods-services/provide-services-abroad/index_es.htm#rules-annual-turnovers
127+
- [Great electron boilerplate](https://github.com/sindresorhus/electron-boilerplate)
128+
- [Modern electron apps](https://archive.jlongster.com/secret-of-good-electron-apps)
129+
- [Loading the Frontend from a separate process](https://medium.com/@kitze/%EF%B8%8F-from-react-to-an-electron-app-ready-for-production-a0468ecb1da3?p=a0468ecb1da3)
130+
- [awesome-electron](https://github.com/sindresorhus/awesome-electron)

electron/.editorconfig

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
indent_style = tab
5+
end_of_line = lf
6+
charset = utf-8
7+
trim_trailing_whitespace = true
8+
insert_final_newline = true
9+
10+
[*.yml]
11+
indent_style = space
12+
indent_size = 2

electron/.eslintrc.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
es2021: true,
5+
},
6+
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
7+
parser: "@typescript-eslint/parser",
8+
parserOptions: {
9+
ecmaVersion: 13,
10+
sourceType: "module",
11+
},
12+
plugins: ["@typescript-eslint"],
13+
rules: {},
14+
excludes: "/*.js",
15+
};

electron/.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

electron/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
yarn.lock
3+
/dist
4+
/renderer-backend/transpiled/**
5+
/renderer-frontend/**
6+
noise.png

electron/build/background.png

914 Bytes
Loading

electron/build/background@2x.png

2.02 KB
Loading

electron/build/icon.png

1.33 MB
Loading

0 commit comments

Comments
 (0)