Skip to content

Commit 706554b

Browse files
committed
rewite some stuff, add some more guides
1 parent 4350fec commit 706554b

File tree

6 files changed

+162
-114
lines changed

6 files changed

+162
-114
lines changed

SUMMARY.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@
3838
* [Troubleshooting](integrating/troubleshooting-guide.md)
3939
* [Contributor guide](developing/README.md)
4040
* [How you can help](developing/help.md)
41-
* [Getting started with the codebase](developing/getting-started.md)
42-
* [Unit Tests](developing/unit-tests.md)
43-
* [Integration Tests](developing/integration-tests.md)
44-
* [Environment variables](developing/environment-variables.md)
45-
* [Performance hacking](developing/performance.md)
46-
* [Behind the scenes](developing/behind-the-scenes.md)
47-
* [Continuous deployment](developing/continuous-deployment.md)
48-
* [Dependencies \(broth\)](installing/dependencies.md)
41+
* [Getting started with the codebase](developing/getting-started.md)
42+
* [Unit Tests](developing/unit-tests.md)
43+
* [Integration Tests](developing/integration-tests.md)
44+
* [Environment variables](developing/environment-variables.md)
45+
* [Performance hacking](developing/performance.md)
46+
* [Continuous deployment](developing/continuous-deployment.md)
47+
* [Butler TypeScript typings](developing/butler-typings.md)
48+
* [Syncing translations](developing/i18n-sync.md)
49+
* [Dependencies \(broth\)](installing/dependencies.md)
4950
* [Appendix](appendix/README.md)
5051
* [Acknowledgements](appendix/acknowledgements.md)
5152
* [Building Linux software into a prefix](appendix/building-into-a-prefix.md)

developing/butler-typings.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Butler TypeScript Typings
2+
3+
The itch app communicates with [butler](https://github.com/itchio/butler) via a JSON-RPC interface. Butler's API is defined in Go, and TypeScript type definitions are generated from this specification using a tool called `generous`.
4+
5+
## How It Works
6+
7+
Butler's API messages (requests, responses, and notifications) are defined in Go structs within the butler repository. The `generous` tool reads these definitions and generates corresponding TypeScript types and request creators that work with the `@itchio/butlerd` package.
8+
9+
The generated file lives at `src/common/butlerd/messages.ts` in the itch repository.
10+
11+
## Synchronizing Typings
12+
13+
When butler's API changes, the TypeScript typings in itch need to be regenerated to match. This ensures type safety when making butler calls from the app.
14+
15+
To regenerate the typings, ensure you have the butler repository checked out alongside itch:
16+
17+
```
18+
parent/
19+
├── butler/
20+
└── itch/
21+
```
22+
23+
Then run:
24+
25+
```bash
26+
npm run sync-butler
27+
```
28+
29+
This runs the generous generator from the butler repo and outputs the updated TypeScript definitions.
30+
31+
## When to Sync
32+
33+
You should regenerate the typings when:
34+
35+
- Butler adds new API endpoints
36+
- Butler modifies existing request/response types
37+
- Butler adds or changes notifications
38+
- You're working with a newer version of butler that has API changes

developing/continuous-deployment.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ On every commit, the CI executes all unit tests, and runs the TypeScript compile
2727
The building scripts run some common steps on every platform:
2828

2929
* Compiling [TypeScript](https://www.typescriptlang.org/) code to ES2017, into several bundles
30-
* Copying some asset files \(vendor CSS/JS/images\)
30+
* Bundling static asset files
3131

3232
### Packaging
3333

developing/getting-started.md

Lines changed: 39 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,44 @@
22

33
itch is built in TypeScript and runs inside of Electron.
44

5-
To get started, install the latest [node.js](https://nodejs.org/)
5+
To get started, ensure you have a modern version of [node.js](https://nodejs.org/) installed.
66

7-
> Linux distributions tend to ship outdated node.js versions
8-
>
7+
> Linux distributions may ship outdated node.js versions
98
> Use the nodesource [binary distributions](https://github.com/nodesource/distributions/) to get an up-to-date one.
109
1110
Then, clone the [https://github.com/itchio/itch](https://github.com/itchio/itch) repository somewhere.
1211

13-
Install the javascript dependencies by running this command from within the `itch` directory you've just cloned:
12+
Install the javascript dependencies by running the following command from within the `itch` directory you've just cloned:
1413

1514
```bash
1615
$ npm install
1716
```
1817

19-
> For native modules, you'll need a compiler toolchain: Visual Studio 2015 on Windows, gcc/clang on Linux/macOS. See the [node-gyp](https://github.com/nodejs/node-gyp) page for more information on this.
18+
> For native modules, you'll need a compiler toolchain: Visual Studio 2015 on
19+
> Windows, gcc/clang on Linux/macOS. See the
20+
> [node-gyp](https://github.com/nodejs/node-gyp) page for more information on
21+
> this.
2022
2123
Finally, start the app!
2224

2325
```bash
2426
$ npm start
2527
```
2628

27-
The first run will seem slow, because the compile cache is empty. Subsequent runs will be much faster.
28-
2929
## Environment
3030

31-
There are three environments in which the app can run: `development`, `test`, and `production`.
32-
33-
`development` is what you'll be using to develop the app. It includes warnings and tools that aren't in the other environments, such as:
34-
35-
* Hot module reloading
36-
* React warnings
31+
There are three environments in which the app can run: `development`, `test`,
32+
and `production`.
3733

38-
`production` is what the app runs on when it's released as a package to end-users. It's a fast, no-nonsense environment, and it enables things like self-updates, locale updates, etc.
39-
40-
`test` looks a lot like `production` except that some things are disabled: logging, for instance, is suppressed. The app will also not exit by itself, but print a well-known string to the console, allowing the integration test runner to kill the app itself.
34+
* **`development`** is what you'll be using to develop the app. It includes warnings
35+
and tools that aren't in the other environments, such as React warnings.
36+
* **`production`** is what the app runs on when it's released as a package to
37+
end-users. It's a fast, no-nonsense environment, and it enables things like
38+
self-updates, locale updates, etc.
39+
* **`test`** looks a lot like `production` except that some things are disabled:
40+
logging, for instance, is suppressed. The app will also not exit by itself, but
41+
print a well-known string to the console, allowing the integration test runner
42+
to kill the app itself.
4143

4244
## App structure
4345

@@ -66,12 +68,10 @@ All processes have a redux store, the **main** store is the reference, and the o
6668

6769
## Chrome Developer Tools \(renderer\)
6870

69-
Press `Shift-F12` to open the Chrome Developer Tools, to inspect the DOM, run arbitrary javascript code in the **chrome** side of the app, etc.
71+
Press `Shift + F12` to open the Chrome Developer Tools, to inspect the DOM, run arbitrary javascript code in the **chrome** side of the app, etc.
7072

7173
![](/assets/react-devtools.png)
7274

73-
> The React devtools are automatically installed in the `development` environment, although you'll need to reload the page after opening the devtools to see the tab.
74-
7575
If the app crashes before it gets a chance to install the keyboard shortcut,
7676
you can `export DEVTOOLS=1` before starting the app so that they open as early as possible.
7777

@@ -99,61 +99,28 @@ Note that pausing in the developer tools will freeze the whole app, so your OS m
9999

100100
## Compiling
101101

102-
TypeScript sources and static assets live in `src`. They're compiled and bundled by [webpack](https://webpack.js.org/).
103-
104-
In development, files are recompiled automatically and the chrome side is served over HTTP.
105-
106-
* `npm start` is not black magic, it just runs `develop.js` - feel free to look into it
107-
108-
In production, they're precompiled and packaged so that a lot of development dependencies are not included in the final builds.
109-
110-
### Hot module reload
102+
TypeScript sources and static assets live in `src`. They're compiled and
103+
bundled by [esbuild](https://esbuild.github.io/).
111104

112-
When the app is started in developent, it watches for file changes, and reloads parts of itself automatically. This mostly applies to the **renderer** side of the app, React components in particular.
113-
114-
By having your code editor and the app open side to side, you can quickly iterate on the looks of a React component.
105+
In development, files are recompiled automatically, you can refresh the user
106+
interface of the app to view the latest UI. Since the redux state is unchanged
107+
on refresh you should be left off where you were. The easiest way to refresh
108+
the UI is the open the Devtools (`Shift + F12`) and hit `Ctrl + r` with the
109+
devtools focused.
115110

116111
## Code style
117112

118113
We use [prettier](https://www.npmjs.com/package/prettier) to make sure the codebase has a consistent style.
119114

120-
There's a pre-commit hook that formats staged files. It's powered by husky and [lint-staged](https://github.com/okonet/lint-staged), see the `package.json`
115+
There's a pre-commit hook that formats staged files. It's powered by husky and
116+
[lint-staged](https://github.com/okonet/lint-staged), see the `package.json`
121117
for the configuration.
122118

123-
Some text editors have plug-ins for prettier, which can help you format on save. There are workspace settings for the [Visual Studio Code prettier plug-in](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) in the repository.
124-
125-
### Asynchronous code
119+
Some text editors have plug-ins for prettier, which can help you format on
120+
save. There are workspace settings for the [Visual Studio Code prettier
121+
plug-in](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
122+
in the repository.
126123

127-
We use TypeScript's async/await support so that instead of writing this:
128-
129-
```typescript
130-
function installSoftware (name: string) {
131-
return download(name)
132-
.then(() => extract(name))
133-
.then(() => verify(name))
134-
.catch((err) => {
135-
// Uh oh, something happened
136-
});
137-
}
138-
```
139-
140-
...we can write this:
141-
142-
```typescript
143-
async function installSoftware (name: string) {
144-
try {
145-
await download(name);
146-
await extract(name);
147-
await verify(name);
148-
} catch (err) {
149-
// Uh oh, something happened
150-
}
151-
}
152-
```
153-
154-
In development, async/await code is transformed using babel to bluebird promises, which in turn uses coroutines and has long stack traces support.
155-
156-
This lets us dive into issues that involve several promises awaiting each other. In production, they're left as-is, since both Node and Chrome now support async/await.
157124

158125
### React components
159126

@@ -163,13 +130,18 @@ We have a `hook` function that allows writing fully type-checked connected compo
163130

164131
Look at `src/renderer/basics/` for simple examples.
165132

133+
> **Note:** We are in the proces of migrating to React Hooks and Functional Components. Use `React.memo` where possible.
134+
166135
### Styled components \(CSS\)
167136

168-
Most of the CSS styles in the app are handled by [styled-components](https://github.com/styled-components/styled-components).
137+
Most of the CSS styles in the app are handled by
138+
[styled-components](https://github.com/styled-components/styled-components).
169139

170140
This lets us handle theme switching, namespace and compose our styles easily.
171141

172-
Some text editor plug-ins, like [styled-components for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=jpoissonnier.vscode-styled-components) provide syntax highlighting for css blocks.
142+
Some text editor plug-ins, like [styled-components for Visual Studio
143+
Code](https://marketplace.visualstudio.com/items?itemName=jpoissonnier.vscode-styled-components)
144+
provide syntax highlighting for css blocks.
173145

174146
## Testing
175147

developing/i18n-sync.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Syncing Translations (i18n)
2+
3+
Translations for the itch app are managed in a separate repository and contributed via Weblate. To update the app with the latest translations, you need to sync from the external repo.
4+
5+
## How It Works
6+
7+
Translations are stored in the [itch-i18n](https://github.com/itchio/itch-i18n) repository. Community members contribute translations through [Weblate](https://weblate.itch.zone), which commits changes to that repo.
8+
9+
The locale files (JSON) are copied into the itch app at `src/static/locales/`.
10+
11+
## Syncing Translations
12+
13+
Ensure you have the itch-i18n repository checked out alongside itch:
14+
15+
```
16+
parent/
17+
├── itch/
18+
└── itch-i18n/
19+
```
20+
21+
Then run the import script:
22+
23+
```bash
24+
node release/import-i18n-strings.js
25+
```
26+
27+
This deletes the existing `src/static/locales/` directory and copies the latest translations from `../itch-i18n/locales/`.
28+
29+
## When to Sync
30+
31+
You should sync translations when:
32+
33+
- Preparing a new release
34+
- New translations have been added via Weblate
35+
- You want to test recent translation updates locally

developing/performance.md

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -18,53 +18,55 @@ Get to know the tools. They're good.
1818

1919
In short:
2020

21-
* Only use `React.PureComponent`, always
22-
* For connected components, use reselect \(createStructuredSelector, createSelector\) in `mapStateToProps` \(grep the codebase for examples\)
23-
* Avoid `[]` or `{}` in `mapStateToProps`, do this instead:
21+
* Use `React.memo` to wrap your functional components. It serves the same purpose as `React.PureComponent` but for functional components, preventing unnecessary re-renders by using a shallow comparison of props.
22+
23+
* For connected components, use hooks like `useSelector` from `react-redux` to listen only the least set of dependent values to avoid re-renders
2424

2525
```javascript
26-
const emptyObj = {};
27-
const emptyArr = [];
28-
29-
export default connect(SomeComponent, {
30-
state: createStructuredSelector({
31-
// Don't do this!
32-
baadValue: (state) => ((state.a || {}).b || [])[0];
33-
// Do this instead:
34-
goodValue: (state) => ((state.a || emptyObj).b || emptyArr)[0];
35-
}),
36-
})
26+
import React, { memo } from 'react';
27+
import { useAppDispatch, useAppSelector } from "renderer/hooks/redux";
28+
29+
const SomeComponent = () => {
30+
const dispatch = useAppDispatch();
31+
const appVersion = useAppSelector((rs) => rs.system.appVersion);
32+
33+
const handleButtonClick = useCallback(() => {
34+
dispatch({ type: 'DO_SOMETHING' });
35+
}, [dispatch]);
36+
37+
return <button onClick={handleButtonClick}>{appVersion}</button>;
38+
};
39+
40+
export default memo(SomeComponent);
3741
```
3842

39-
* Anonymous functions or `this.something.bind(this)` create a new value every time, and will wreck `shouldComponentUpdate`.
43+
* Avoid using anonymous functions in render when passing into sub-components so that they make take advantage of memoization. Instead, use stable references with `useCallback` which will return a memoized version of the callback that only changes if one of the dependencies has changed.
4044

4145
```javascript
42-
export BadComponent extends React.PureComponent<any, any> {
43-
doStuff () {
46+
import React, { memo, useCallback } from 'react';
47+
48+
// Bad approach
49+
const BadComponent = memo(() => {
50+
const doStuff = () => {
4451
// stuff.
45-
}
46-
47-
render () {
48-
// Don't! This generates a different closure for each render call
49-
return <div onClick={() => this.doStuff()}/>
50-
// Don't either! This also generates a different function on every render
51-
return <div onClick={this.doStuff.bind(this)}/>
52-
}
53-
}
54-
55-
// Do this!
56-
export GoodComponent extends React.PureComponent<any, any> {
57-
// In TypeScript, this is called an instance function
58-
doStuff = () => {
52+
};
53+
54+
// This will force MyComplexComponent to always re-render
55+
return <MyComplexComponent onClick={doStuff}/>;
56+
});
57+
58+
// Good practice
59+
const GoodComponent = memo(() => {
60+
const doStuff = useCallback(() => {
5961
// stuff.
60-
}
62+
}, []); // Dependencies array
6163

62-
render () {
63-
// `this.doStuff` stays the same, won't trigger unnecessary renders
64-
return <div onClick={this.doStuff}/>
65-
}
66-
}
64+
// Memoized `doStuff` won't trigger unnecessary renders when GoodComponent is re-rerendered
65+
return <div onClick={doStuff}/>;
66+
});
6767
```
6868

69-
`PureComponent` uses shallow comparison in `shouldComponentUpdate`. If you pass a new object/array/function reference on every render, the comparison will always return false and trigger unnecessary re-renders. By using stable references (module-level constants, instance methods), you let React's pure rendering optimizations work properly.
69+
By using hooks and keeping function references stable with `useCallback`, you
70+
allow React's memoization strategies to optimize your component rendering. This
71+
helps in performance gains by reducing unnecessary rendering.
7072

0 commit comments

Comments
 (0)