Unverified Commit 00435e19 authored by Tasso Evangelista's avatar Tasso Evangelista Committed by GitHub
Browse files

perf! TypeScript, IPC through Redux actions and more (#1684)

* Decide when to run RocketChat preload routines

* Split some preload routines

* Move server title change handling to the main process

* Move server favicon change handling to the main process

* Move more preload routines to the main process

* Move more preload routines to the main process

* Move more preload routines to the main process

* Move more preload routines to the main process

* Remove obsolete handling of links

* Simplify Jitsi integration

* Remove the last references to remote module in preload script

* Delegate webview configuration to the main process

* Create browserViews module

* Move root window renderer modules

* Fix root window state

* Use IPC constants

* Remove unused handler

* Rename IPC constants

* Remove tests that will break

* Remove electron store initialization from sagas

* Link main process and preload scripts via IPC only

* Remove remaining direct reference...
parent 0ff7e539
......@@ -8,10 +8,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{js,html}]
indent_style = tab
[*.json]
[*.{js,json,ts,html}]
indent_style = space
indent_size = 2
......
{
"extends": [
"@rocket.chat/eslint-config"
],
"plugins": ["react", "react-hooks"],
"parser": "babel-eslint",
"rules": {
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/jsx-no-undef": "error",
"react/jsx-fragments": ["error", "syntax"],
"react/react-in-jsx-scope": "error",
"jsx-quotes": ["error", "prefer-single"],
"generator-star-spacing": ["error", "before"],
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": ["warn", {
"additionalHooks": "(useSaga|useCallableSaga)"
}]
},
"settings": {
"react": {
"version": "detect"
}
},
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true,
"jest": true
}
}
module.exports = {
extends: [
'@rocket.chat/eslint-config',
],
plugins: ['react', 'react-hooks'],
parser: 'babel-eslint',
rules: {
'generator-star-spacing': ['error', 'before'],
'import/order': ['error', {
'newlines-between': 'always',
groups: ['builtin', 'external', 'internal', ['parent', 'sibling', 'index']],
alphabetize: {
order: 'asc',
},
}],
indent: ['error', 2, {
SwitchCase: 1,
}],
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-fragments': ['error', 'syntax'],
'react/react-in-jsx-scope': 'error',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'jsx-quotes': ['error', 'prefer-single'],
},
settings: {
'import/resolver': {
node: {
extensions: [
'.js',
'.ts',
'.tsx',
],
},
},
react: {
version: 'detect',
},
},
env: {
browser: true,
commonjs: true,
es6: true,
node: true,
jest: true,
},
overrides: [
{
files: [
'**/*.ts',
'**/*.tsx',
],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'@rocket.chat/eslint-config',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 2018,
warnOnUnsupportedTypeScriptVersion: false,
ecmaFeatures: {
experimentalObjectRestSpread: true,
legacyDecorators: true,
},
},
plugins: [
'react',
'react-hooks',
'@typescript-eslint',
],
rules: {
'func-call-spacing': 'off',
'generator-star-spacing': ['error', 'before'],
indent: 'off',
'import/order': ['error', {
'newlines-between': 'always',
groups: ['builtin', 'external', 'internal', ['parent', 'sibling', 'index']],
alphabetize: {
order: 'asc',
},
}],
'jsx-quotes': ['error', 'prefer-single'],
'no-empty-function': 'off',
'no-extra-parens': 'off',
'no-spaced-func': 'off',
'no-unused-vars': 'off',
'no-useless-constructor': 'off',
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-fragments': ['error', 'syntax'],
'react/react-in-jsx-scope': 'error',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/func-call-spacing': 'error',
'@typescript-eslint/indent': ['error', 2, {
SwitchCase: 1,
}],
'@typescript-eslint/no-extra-parens': ['error', 'all', {
conditionalAssign: true,
nestedBinaryExpressions: false,
returnAssign: true,
ignoreJSX: 'all',
enforceForArrowConditionals: false,
}],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': ['warn', {
allowExpressions: true,
}],
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars-experimental': 'warn',
},
env: {
browser: true,
commonjs: true,
es6: true,
node: true,
},
settings: {
'import/resolver': {
node: {
extensions: [
'.js',
'.ts',
'.tsx',
],
},
},
react: {
version: 'detect',
},
},
},
],
};
language: node_js
node_js: 10
node_js: 12
os: linux
cache:
yarn: true
......
The MIT License (MIT)
Copyright (c) 2015-2016 Rocket.Chat Technologies Corp.
Copyright (c) 2015-2020 Rocket.Chat Technologies Corp.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
......
# Rocket.Chat Desktop App
[![Build Status](https://img.shields.io/travis/RocketChat/Rocket.Chat.Electron/master.svg?logo=travis)](https://travis-ci.org/RocketChat/Rocket.Chat.Electron)
[![Build status](https://img.shields.io/appveyor/ci/RocketChat/rocket-chat-electron/master.svg?logo=appveyor)](https://ci.appveyor.com/project/RocketChat/rocket-chat-electron)
[![Travis CI Build Status](https://img.shields.io/travis/RocketChat/Rocket.Chat.Electron/master.svg?logo=travis)](https://travis-ci.org/RocketChat/Rocket.Chat.Electron)
[![AppVeyor Build Status](https://img.shields.io/appveyor/ci/RocketChat/rocket-chat-electron/master.svg?logo=appveyor)](https://ci.appveyor.com/project/RocketChat/rocket-chat-electron)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/3a87141c0a4442809d9a2bff455e3102)](https://www.codacy.com/app/tassoevan/Rocket.Chat.Electron?utm_source=github.com&utm_medium=referral&utm_content=RocketChat/Rocket.Chat.Electron&utm_campaign=Badge_Grade)
[![Project Dependencies](https://david-dm.org/RocketChat/Rocket.Chat.Electron.svg)](https://david-dm.org/RocketChat/Rocket.Chat.Electron)
[![GitHub All Releases](https://img.shields.io/github/downloads/RocketChat/Rocket.Chat.Electron/total.svg)](https://github.com/RocketChat/Rocket.Chat.Electron/releases/latest)
![GitHub](https://img.shields.io/github/license/RocketChat/Rocket.Chat.Electron.svg)
Desktop application for [Rocket.Chat] available for macOS, Windows and Linux
using [Electron].
Desktop application for [Rocket.Chat][] available for macOS, Windows and Linux
using [Electron][].
[Rocket.Chat]: https://github.com/RocketChat/Rocket.Chat
[Electron]: https://electronjs.org/
![Rocket.Chat Desktop App](https://user-images.githubusercontent.com/2263066/91490997-c0bd0c80-e889-11ea-92c7-2cbcc3aabc98.png)
## Download
---
You can download the latest version from the [Releases] page.
## Engage with us
[Releases]: https://github.com/RocketChat/Rocket.Chat.Electron/releases/latest
### Share your story
We’d love to hear about [your experience][] and potentially feature it on our
[Blog][].
### Subscribe for Updates
Once a month our marketing team releases an email update with news about product
releases, company related topics, events and use cases. [Sign Up!][]
---
## Download
You can download the latest version from the [Releases][] page.
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/rocketchat-desktop)
......@@ -32,9 +43,8 @@ add the options below:
- `/S` - Silent install
- `/allusers` - Install for all users (requires admin)
- `/currentuser` - Install for current user only (default)
- `/disableAutoUpdates` - Disable autoupdates (Application will not update
automatically / User can't update via dialog)
- `/currentuser` - Install only the for current user (default)
- `/disableAutoUpdates` - Disable automatic updates
## Development
......@@ -65,52 +75,36 @@ The build process compiles all stuff from the `src` folder and puts it into the
`app` folder, so after the build has finished, your `app` folder contains the
full, runnable application.
### The build pipeline
The build process is founded upon [gulp] task runner and [rollup] bundler. There are
two entry files for your code: `src/main.js` and `src/app.js`. Rollup will
follow all `import` statements starting from those files and compile code of the
whole dependency tree into one `.js` file for each entry point.
### TypeScript
[gulp]: https://github.com/gulpjs/gulp
[rollup]: https://github.com/rollup/rollup
#### Adding node modules
Following the [ongoing changes in Rocket.Chat codebase][], the app was
rewritten in TypeScript 4 to address issues regarding maintainability.
Remember to respect the split between `dependencies` and `devDependencies` in
`package.json` file. Only modules listed in `dependencies` will be included into
distributable app.
#### Working with modules
### The build pipeline
Thanks to [rollup] you can (and should) use ES6 modules for most code in `src`
folder.
The build process is founded upon [rollup][] bundler. There are three entry files
for your code:
[rollup]: https://github.com/rollup/rollup
- `src/main.ts`, the script running at the main Electron process, orchestrating
the whole application;
Use ES6 syntax in the `src` folder like this:
- `src/rootWindow.ts`, the script that renders the UI of the *root window*, the
app's main window;
```js
import myStuff from './my_lib/my_stuff';
```
- and `src/preload.ts`, which runs in a privileged mode to connect the app and
the webviews rendering Rocket.Chat's web client.
The exception is in `src/public`. ES6 will work inside this folder, but it is
limited to what Electron/Chromium supports. The key thing to note is that you
cannot use `import` and `export` statements. Imports and exports need to be done
using CommonJS syntax:
#### Adding Node.js modules
```js
const myStuff = require('./my_lib/my_stuff');
const { myFunction } = require('./App');
```
Remember to respect the split between `dependencies` and `devDependencies` in
`package.json` file. Only modules listed in `dependencies` will be included into
distributable app.
### Troubleshooting
#### node-gyp
Follow the installation instruction on [node-gyp readme].
[node-gyp readme]: https://github.com/nodejs/node-gyp#installation
Follow the installation instruction on [node-gyp readme][].
#### Ubuntu
......@@ -137,8 +131,6 @@ gcc-c++
On Windows 7 you may have to follow option 2 of the [node-gyp install guide]
and install Visual Studio.
[node-gyp install guide]: https://github.com/nodejs/node-gyp#installation
### Testing
#### Unit tests
......@@ -147,11 +139,9 @@ and install Visual Studio.
yarn test
```
Using [electron-mocha] test runner with the [chai] assertion library. This task
searches for all files in `src` directory which respect pattern `*.spec.js`.
[electron-mocha]: https://github.com/jprichardson/electron-mocha
[chai]: http://chaijs.com/api/assert/
We use [Jest][] testing framwork with the [Jest electron runner][]. It searches
for all files in `src` directory that match the glob pattern
`*.(spec|test).{js,ts,tsx}`.
### Making a release
......@@ -164,11 +154,8 @@ yarn release
It will start the packaging process for operating system you are running this
command on. Ready for distribution file will be outputted to `dist` directory.
All packaging actions are handled by [electron-builder]. It has a lot of
[customization options].
[electron-builder]: https://github.com/electron-userland/electron-builder
[customization options]: https://github.com/electron-userland/electron-builder/wiki/Options
All packaging actions are handled by [electron-builder][]. It has a lot of
[customization options][].
## Default servers
......@@ -226,17 +213,37 @@ Released under the MIT license.
- German: [GPL-2.0 OR GPL-3.0](https://github.com/wooorm/dictionaries/blob/master/dictionaries/de/license)
- English (United Kingdom): [MIT AND BSD](https://github.com/wooorm/dictionaries/blob/master/dictionaries/en-GB/license)
- English (United States): [MIT AND BSD](https://github.com/wooorm/dictionaries/blob/master/dictionaries/en-US/license)
- Spanish (or Castilian; Spain): [GPL-3.0 OR LGPL-3.0 OR MPL-1.1](https://github.com/wooorm/dictionaries/blob/master/dictionaries/es-ES/license)
- English (United States): [MIT AND BSD](https://github.com/wooorm/dictionaries/blob/main/dictionaries/en/license)
- Spanish (or Castilian; Spain): [GPL-3.0 OR LGPL-3.0 OR MPL-1.1](https://github.com/wooorm/dictionaries/blob/main/dictionaries/es/license)
- French: [MPL-2.0](https://github.com/wooorm/dictionaries/blob/master/dictionaries/fr/license)
- Portuguese (Brazil): [LGPL-3.0 OR MPL-2.0](https://github.com/wooorm/dictionaries/blob/master/dictionaries/pt-BR/license)
- Portuguese (Brazil): [LGPL-3.0 OR MPL-2.0](https://github.com/wooorm/dictionaries/blob/main/dictionaries/pt/license)
- Russian: [LGPL-3.0](https://github.com/wooorm/dictionaries/blob/master/dictionaries/ru/license)
- Turkish: [MIT](https://github.com/wooorm/dictionaries/blob/master/dictionaries/tr/license)
[Rocket.Chat]: https://rocket.chat
[Electron]: https://electronjs.org/
[your experience]: https://survey.zohopublic.com/zs/e4BUFG
[Blog]: https://rocket.chat/case-studies/?utm_source=github&utm_medium=readme&utm_campaign=community
[Sign Up!]: https://rocket.chat/newsletter/?utm_source=github&utm_medium=readme&utm_campaign=community
[Releases]: https://github.com/RocketChat/Rocket.Chat.Electron/releases/latest
[ongoing changes in Rocket.Chat codebase]: https://forums.rocket.chat/t/moving-away-from-meteor-and-beyond/3270
[rollup]: https://github.com/rollup/rollup
[node-gyp readme]: https://github.com/nodejs/node-gyp#installation
# Engage with us
## Share your story
We’d love to hear about [your experience](https://survey.zohopublic.com/zs/e4BUFG) and potentially feature it on our [Blog](https://rocket.chat/case-studies/?utm_source=github&utm_medium=readme&utm_campaign=community).
[Jest]: https://jestjs.io/
## Subscribe for Updates
Once a month our marketing team releases an email update with news about product releases, company related topics, events and use cases. [Sign Up!](https://rocket.chat/newsletter/?utm_source=github&utm_medium=readme&utm_campaign=community)
[Jest electron runner]: https://github.com/facebook-atom/jest-electron-runner
[electron-builder]: https://github.com/electron-userland/electron-builder
[customization options]: https://github.com/electron-userland/electron-builder/wiki/Options
[node-gyp install guide]: https://github.com/nodejs/node-gyp#installation
image: Visual Studio 2017
environment:
nodejs_version: "10"
nodejs_version: "12"
platform:
- x64
skip_tags: true
......
module.exports = {
exclude: 'node_modules/**',
presets: [
[
'@babel/preset-env',
{
targets: {
electron: 7,
},
},
],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-proposal-function-bind',
'@babel/plugin-proposal-class-properties',
],
exclude: 'node_modules/**',
presets: [
[
'@babel/preset-env',
{
targets: {
electron: 7,
},
},
],
'@babel/preset-react',
],
plugins: [
'@babel/plugin-proposal-function-bind',
'@babel/plugin-proposal-class-properties',
],
};
......@@ -2,10 +2,13 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.inherit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.disable-library-validation</key><true/>
<key>com.apple.security.temporary-exception.apple-events</key><true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.inherit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
......@@ -2,19 +2,31 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key><true/>
<key>com.apple.security.files.downloads.read-write</key><true/>
<key>com.apple.security.automation.apple-events</key><true/>
<key>com.apple.security.cs.allow-jit</key><true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<key>com.apple.security.cs.disable-library-validation</key><true/>
<key>com.apple.security.device.audio-input</key><true/>
<key>com.apple.security.device.bluetooth</key><true/>
<key>com.apple.security.device.camera</key><true/>
<key>com.apple.security.device.microphone</key><true/>
<key>com.apple.security.files.user-selected.read-only</key><true/>
<key>com.apple.security.files.user-selected.read-write</key><true/>
<key>com.apple.security.network.client</key><true/>
<key>com.apple.security.network.server</key><true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.downloads.read-write</key>
<true/>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.device.microphone</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>
const { notarize } = require('electron-notarize');
exports.default = function notarizing(context) {
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName !== 'darwin' || process.env.TRAVIS_PULL_REQUEST !== 'false') {
return;
}
const { electronPlatformName, appOutDir } = context;
if (electronPlatformName !== 'darwin' || process.env.TRAVIS_PULL_REQUEST !== 'false') {
return;
}
const appName = context.packager.appInfo.productFilename;
const appName = context.packager.appInfo.productFilename;
process.stdout.write('Notarizing...');
return new Promise((resolve, reject) => {
const timer = setInterval(() => {
process.stdout.write('.');
}, 15000);
process.stdout.write('Notarizing...');
return new Promise((resolve, reject) => {
const timer = setInterval(() => {
process.stdout.write('.');
}, 15000);
notarize({
appBundleId: 'chat.rocket',
appPath: `${ appOutDir }/${ appName }.app`,
appleId: process.env.APPLEID,
appleIdPassword: process.env.APPLEIDPASS,
ascProvider: 'S6UPZG7ZR3',
})
.then(() => {
clearTimeout(timer);
console.log();
resolve();
})
.catch((error) => {
clearTimeout(timer);
console.log();
reject(error);
});
});
notarize({
appBundleId: 'chat.rocket',
appPath: `${ appOutDir }/${ appName }.app`,
appleId: process.env.APPLEID,
appleIdPassword: process.env.APPLEIDPASS,
ascProvider: 'S6UPZG7ZR3',
})
.then(() => {
clearTimeout(timer);
console.log();
resolve();
})
.catch((error) => {
clearTimeout(timer);
console.log();
reject(error);
});
});
};
......@@ -3,181 +3,181 @@ const { promisify } = require('util');
const { convert: convertToIcns } = require('@fiahfy/icns-convert');
const { createConverter } = require('convert-svg-to-png');
const toIco = require('to-ico');
const rimraf = require('rimraf');
const toIco = require('to-ico');
let deferredConverter = Promise.resolve(createConverter());
const convertSvgToPng = (...args) => new Promise((resolve) => {
deferredConverter = deferredConverter.then(async (converter) => {
const buffer = await converter.convert(...args);
resolve(buffer);
return converter;
});
deferredConverter = deferredConverter.then(async (converter) => {
const buffer = await converter.convert(...args);
resolve(buffer);
return converter;
});
});
const readSvg = (name) => fs.promises.readFile(`src/icons/${ name }.svg`, 'utf8');
const readSvg = (name) => fs.promises.readFile(`src/ui/icons/${ name }.svg`, 'utf8');
const writeTrayIcon = (name, data) => {
console.log({ name });
return fs.promises.writeFile(`src/public/images/tray/${ name }`, data);
console.log({ name });
return fs.promises.writeFile(`src/public/images/tray/${ name }`, data);
};
const writeAppImage = (name, data) => {
console.log({ name });
return fs.promises.writeFile(`src/public/images/${ name }`, data);
console.log({ name });
return fs.promises.writeFile(`src/public/images/${ name }`, data);
};