github-desktop/docs/technical/placeholders.md
2018-12-27 15:38:17 -08:00

120 lines
3.4 KiB
Markdown

## Placeholders and Replacements in Source Code
As GitHub Desktop uses Webpack to transpile, minify and merge our code
into unified scripts for each configuration we define, we use some tricks
to manage complexity and enable some optimizations.
For example, you might come across this code in [`app-window.ts`](https://github.com/desktop/desktop/blob/development/app/src/main-process/app-window.ts):
```ts
if (__DARWIN__) {
windowOptions.titleBarStyle = 'hidden'
} else if (__WIN32__) {
windowOptions.frame = false
}
```
You may be inclined to refactor this to be:
```ts
if (process.platform === 'darwin') {
windowOptions.titleBarStyle = 'hidden'
} else if (process.platform === 'win32') {
windowOptions.frame = false
}
```
And while both of these are semantically the same, how we bundle Desktop means
we get significant benefits from doing it the first way.
### Replacements
The replacements defined for Desktop are found in [`app/app-info.ts`](https://github.com/desktop/desktop/blob/development/app/app-info.ts)
as a hash of key-value pairs.
```ts
function getReplacements() {
return {
__OAUTH_CLIENT_ID__: s(process.env.DESKTOP_OAUTH_CLIENT_ID || devClientId),
__OAUTH_SECRET__: s(
process.env.DESKTOP_OAUTH_CLIENT_SECRET || devClientSecret
),
__DARWIN__: process.platform === 'darwin',
__WIN32__: process.platform === 'win32',
__LINUX__: process.platform === 'linux',
__DEV__: channel === 'development',
__RELEASE_CHANNEL__: s(channel),
__UPDATES_URL__: s(distInfo.getUpdatesURL()),
__SHA__: s(gitInfo.getSHA()),
__CLI_COMMANDS__: s(getCLICommands()),
'process.platform': s(process.platform),
'process.env.NODE_ENV': s(process.env.NODE_ENV || 'development'),
'process.env.TEST_ENV': s(process.env.TEST_ENV),
}
}
```
This means we can embed values at build time based on the current platform.
Note the values we are embedding for `__DARWIN__` and `__WIN32__`:
```ts
__DARWIN__: process.platform === 'darwin',
__WIN32__: process.platform === 'win32',
```
Because we evaluate these values at build time, the original code snippet will
now look like this on macOS:
```js
if (true) {
windowOptions.titleBarStyle = 'hidden'
} else if (false) {
windowOptions.frame = false
}
```
And look like this on Windows:
```js
if (false) {
windowOptions.titleBarStyle = 'hidden'
} else if (true) {
windowOptions.frame = false
}
```
As part of Webpack's minification and bundling, the dead code paths are
eliminated, leaving this code for macOS:
```js
windowOptions.titleBarStyle = 'hidden'
```
And this code for Windows:
```js
windowOptions.frame = false
```
This means less code is emitted as part of the packaged app, and less
JavaScript is interpreted and executed at runtime.
### Placeholders
As we are working in TypeScript, we need to define these placeholders as
globals under [`app/src/lib/globals.ts`](https://github.com/desktop/desktop/blob/development/app/src/lib/globals.d.ts)
to provide the appropriate type information to the source code.
For example, the values for `__DARWIN__` and `__WIN32__` are declared as
booleans.
```ts
/** Is the app being built to run on Darwin? */
declare const __DARWIN__: boolean
/** Is the app being built to run on Win32? */
declare const __WIN32__: boolean
```
As a convention, globals which should be replaced by Webpack should be prefixed
and suffixed with two underscores, e.g. `__DEV__`.