Electron
Welcome, here is what you will be doing in the next two weeks:
- Brush up on your Electron and React skills and read through the materials provided by DECODE.
- Develop an app which fetches posts from Tumblr API and present them nicely on the screen. Tumblr documentation: Tumblr
- As you progress, make a new commit every time you finish implementing something (so we can track your progress and give you some useful feedback as you progress). For example:
- When you finish setting up your project, make a new commit.
- When you finish with the main screen, make a new commit.
- ... and so on
- Use Git Flow.
Suggested "commit" points are marked as little code blocks like this -> Commit Point.
This way, somebody can take a look and monitor your progress on your feature branch.
Each task is started on its own feature branch.
-
After the task is done and when you see a Merge Request annotation, make a merge request from your feature branch to the master branch for somebody to take a final look. Assign it to someone who is assigned to you as your onboarding buddy.
-
Please add comments or suggestions to this document using the "add comment" feature visible at the right side of the document. Add a comment or suggestion for everything that is not explained enough or is misleading to you.
-
You should have enough time to finish this project in 10 days, so take it slowly to learn as much as you can.
Before you start
- Get familiar with the Electron official documentation since we are using it for building this app.
- Also, get familiar with official React docs. We're using it for building views.
- We're going to keep it simple and use a
webpack
for the project setup. If you want to explore more, check out the webpack documentation. - If you're not familiar with TypeScript, you should check out their official documentation and find out why it's so popular.
- If you're unfamiliar or have never worked with Git, read up on the basic commands. Also, some of us use SourceTree GUI, which provides a nice user interface for all Git-related actions. Check out Git - Book Sourcetree | Free Git GUI for Mac and Windows Git-FER.
- In this onboarding, we're using Yarn as the package manager, but of course, if you want to use npm, that's also fine. Here are the yarn docs if you want more info.
- For styling our app we’re going to be using SASS(SCSS) extension language. If you’re not familiar with it go scroll through the docs.
- For data, we will be using the Tumblr API, so you can also check out the docs. Since we're using JavaScript in this onboarding, we've used a library called tumblr.js for easier data fetching.
Estimate 2 days
Let's start
Follow these steps to set up your machine for Electron and React
- We recommend downloading and installing Visual Studio Code to use as your IDE so you can take advantage of all the benefits it provides. If you prefer using other IDE, that’s perfectly fine.
- If you want to keep track with your commits and be able to resolve conflicts as easy as cutting butter we suggest to explore a tool named Sublime Merge. If you know something better that’s also cool, but we would
Debugger
If you are using Visual Studio Code you can configure your launch.json
file and use its embedded debugger. If you want to know more info about the debugger checkout the official documentation.
First you need to install Debugger for Chrome as an extension for your VSCode. Second thing you need to do is open the command pallet (cmd + p
- for macOS) and find the command Debug: Open launch.json
Inside launch.json
you can configure the debugger by the project needs but in the next lines of we will provide launch.json
configuration for your onboarding project. If you want to setup your debugger you can paste the following code.
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "node",
"request": "launch",
"program": "${workspaceRoot}/electron/main.ts",
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}",
"preLaunchTask": null,
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"runtimeArgs": [".", "--enable-logging"],
"env": {},
"console": "internalConsole",
"sourceMaps": false
},
{
"name": "Attach",
"type": "node",
"request": "attach",
"port": 5858,
"address": "localhost",
"restart": false,
"sourceMaps": false,
"localRoot": "${workspaceRoot}",
"remoteRoot": null
}
]
}
Setting up the project
1. Electron development is essentially Node.js development. So if you don’t have it on your machine go to official docs and install it. Then, in your root directory run yarn init
command to initialize your package.json
file.
IMPORTANT:
When you come to the main
part of the init setup input the following text:
"main": "./dist/main.js"
2. Install Electron, webpack and babel with commands:
yarn add -D electron --dev --exact \
webpack webpack-cli@3.3.12 webpack-dev-server \
babel-loader @babel/core @babel/preset-env \
@babel/preset-react @babel/preset-typescript
Note: This onboarding is currently working only with specific version webpack-cli@3.3.12
. If you put the latest version you will get an error. (Keep up with the fixes)
3. We’re going to create a tsconfig.json
file in root of our project:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": [
"dom",
"es2015",
"es2016",
"es2017"
],
"allowJs": true,
"jsx": "react",
"sourceMap": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
}
}
4. Add babel configuration in babel.config.js
which is also in root of your file:
module.exports = {
plugins: ["@babel/plugin-transform-async-to-generator"],
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript'
]
}
5. In root of your project add index.html
for a view entry point of our application:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>New Electron App</title>
</head>
<body></body>
</html>
6. Next, we’re creating a simple webpack.config.js
for electron
(Also in the root of your project). This is normal webpack configuration, target
is the specific environment that webpack will compile for. In this case it’s electron-main
.
const path = require('path');
module.exports = {
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
devtool: 'source-map',
entry: './electron/main.ts',
target: 'electron-main',
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js',
},
};
7. Create an electron
folder in root of the project, then inside, create a main.ts
file with the code:
import { app, BrowserWindow } from 'electron';
import * as path from 'path';
import * as url from 'url';
let mainWindow: Electron.BrowserWindow | null;
function createWindow() {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
},
});
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools();
mainWindow.loadURL(`http://localhost:4000`);
} else {
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, '../index.html'),
protocol: 'file:',
slashes: true
})
);
}
mainWindow.on('closed', () => {
mainWindow = null;
});
}
app.on('ready', createWindow);
app.allowRendererProcessReuse = true;
Take a look at line 17 where we use the openDevTools()
function to use chromium dev tools.
Chrome plugins
If you ever want to install a chrome plugin in your electron app there is an interesting library to do that. For example if you want react development tools in this project you can add them by installing the plugin extension using the said library. First, let’s install the package
yarn add electron-devtools-installer
Next, we will add an import of react dev tools in our electron/main.ts
import installExtension, {
REACT_DEVELOPER_TOOLS,
} from "electron-devtools-installer";
After the import we add the extension in our electron app using the whenReady()
function:
app.whenReady().then(() => {
installExtension(REACT_DEVELOPER_TOOLS)
.then((name: string) => console.log(Added Extension: ${name}))
.catch((err: string) => console.log("An error occurred: ", err));
});
8. In our package.json
add the scripts
as following
"scripts": {
"dev:electron": "NODE_ENV=development webpack --config webpack.electron.config.js --mode development && electron ."
},
9. Next we'll install React
yarn add react react-dom @types/react @types/react-dom
yarn add -D html-webpack-plugin
10. Then next to electron webpack config we will create webpack.react.config.js
with file content as:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
resolve: {
extensions: ['.tsx', '.ts', '.js'],
mainFields: ['main', 'module', 'browser'],
},
entry: './src/index.tsx',
target: 'electron-renderer',
devtool: 'source-map',
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
devServer: {
contentBase: path.join(__dirname, '../dist/renderer'),
historyApiFallback: true,
compress: true,
hot: true,
port: 4000,
publicPath: '/',
},
output: {
path: path.resolve(__dirname, '../dist/renderer'),
filename: 'js/[name].js',
publicPath: './',
},
plugins: [
new HtmlWebpackPlugin(),
],
};
11. Also, we're adding a new script command:
"scripts": {
....
"dev:react": "NODE_ENV=development webpack-dev-server --config webpack.react.config.js --mode development"
},
12. In order to run this app we need the view part. We’re going to create a src
folder with an index.tsx
file inside:
import React from "react";
import ReactDom from "react-dom";
const mainElement = document.createElement("main");
document.body.appendChild(mainElement);
const App = () => {
return (
<section>
<h1>Hi from a react app</h1>
</section>
);
};
ReactDom.render(<App />, mainElement);
Finishing up
Last thing that we’re going to do is style our app. First we need to install the packages
yarn add -D sass-loader sass css-loader style-loader resolve-url-loader
Then add a new rule (module
→ rules
) into our webpack.react.config.js
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
"style-loader",
// Translates CSS into CommonJS
"css-loader",
// Nedded package for resolving relative paths in url()
// needs to be before sass-loader in loading chain
// more info on https://github.com/webpack-contrib/sass-loader#problems-with-url
"resolve-url-loader",
// Compiles Sass to CSS
"sass-loader",
],
},
Next we'll create our styling folder structure in src
scss
├── base
│ ├── _colors.scss
│ ├── _index.scss
│ └── _typography.scss
└── main.scss
The goal is to change the color of h1 to gray and test that our installed packages are working well and that babel compiles it correctly. Add the following code to files respectively:
// colors.scss
$gray: #888ea7;
// typography.scss
h1 {
color: $gray;
}
// index.scss
@import "colors";
@import "typography";
// main.sccs
@import "base/index";
Lastly we’re going to import our main.scss
styling file in index.tsx
import "./scss/main.scss";
Run the project with your scripts in terminal in two different sessions and check out the results. Try to change colors and see if the whole thing is working.
yarn dev:react
yarn dev:electron
1st Commit point
We’ve finished the part of setting up our project. Now you can commit your changes and push it as an initial commit to your onboarding repo. If you have found a bug or of course a better way to implement something please share your knowledge with us. We will gladly accept your suggestions that benefit this onboarding! 🙌
Estimate 1 day
Create your App
Start a new branch named feature/app-base
. The goal of this task is to use your imagination and create styling and functionality for your app. Since you are using React with Typescript use your skills or help yourself going through documentation.
First part
We are going to be super simple. We will create only one initial page on which we will display liked photo posts from tumblr. In src
create pages
folder and add PostsPage
. If you want to play around and create more pages use react-router-dom
to navigate through your pages.
yarn add react-router-dom
For page styling in scss
also create pages
folder and follow the file structure as previous example. Fell free to add any other details to styling if you want (custom fonts, svgs, logos, animations, etc..).
Below is file structure example of described task for your reference:
src
├── index.tsx
├── pages
│ ├── PostDetailPage.tsx
│ └── PostsPage.tsx
└── scss
├── base
│ ├── _colors.scss
│ ├── _index.scss
│ └── _typography.scss
├── main.scss
└── pages
├── _index.scss
├── _post-detail-page.scss
└── _posts-page.scss
Second part
We will need real data from the tumblr API so we can create our posts list and single post. First we’ll need to register on tumblr API:
-
Create a tumblr account and verify your email
-
Go to app registration
-
Once the app is registered click on it and copy OAuth consumer key and OAuth consumer secret to tumblr console.
When successful the console will show a javascript method example for creating a tumblr client with whom we will fetch the data from the api. We are lucky that for javascript there exists a lib which we will need to install. The lib is called tumbrl.js
→ package.
yarn add tumblr.js
It’s totally up to you on how you want to fetch the data from the tumblr service. If you feel you need Redux you can. If you want to use Reacts own Context API or for example react-query you are free to do. For your reference and guide we will provide a simple service example that we’ve used here as a solution.
We’ve created a services
folder in src
named TumblrService.ts
which we will use for data fetching.
const tumblr = require("tumblr.js");
export default class TumblrService {
private client: any;
constructor() {
this.client = tumblr.createClient({
credentials: {
consumer_key: "<your_consumer_key>",
consumer_secret: "<your_consumer_secret>",
token: "<your_token>",
token_secret: "<your_token_secret>",
},
returnPromises: true,
});
}
async getUserInfo() {
try {
const response = await this.client.userInfo();
return response.user;
} catch (error) {
console.error(error);
}
}
async getUserLikes() {
try {
const response = await this.client.userLikes();
return response;
} catch (error) {
console.error(error);
}
}
}
Since we’re going simple we’re fetching only user info and user posts that were liked. So if you don’t have any posts liked on your account go on tumblr and click on few. We’re only going to focus on photos so please choose posts that are photos only. If you want to do extra fun stuff create your initial page that supports all types of posts (videos, gifs, …). Try to make it when clicked on liked post, its details must open in a popup window of the desktop app.
2nd Commit point
When you’ve finished all of the work create a pull request for base of your app. Assign the PR to someone who’s your buddy on our onboarding process.
Estimate 2 days
Have fun with Electron
In this part of the onboarding process we want to better our skill and explore the Electron API. We want to see how can we use electron API to better our current project.
Create custom toolbar (i.e. Slack toolbar) (history, user profile….)
In this task we’re going to try and recreate the slack toolbar. Create a new branch called feature/custom-toolbar
and let’s start.
As we can see we have 4 parts in our toolbar example. Open your slack window and explore the UX
- Native window behaviour
- History
- Search
- User profile
What we want in our toolbar is to keep it simple and implement custom features. Use your imagination and create the toolbar design as you wish.
- Try and find out how we can create a window with custom toolbar that keeps the native functionalities of closing, minimising and maximizing.
- With history we have 2 features. First we need to make our app to be able to browse through routes with arrows and second we want a dropdown to see our recent history.
- When clicked on search part a dropdown window opens in which we search for items regarding on the page the user is currently on. If there is nothing on a page to filter with search we simply hide it.
- Last part is the user profile icon which also opens as dropdown where we can put a variety of actions, but for now we will put only an Edit profile action which opens a new window for user profile editing.
3rd Commit point
When you’ve implemented all changes create a PR on your repo and contact your onboarding buddy.
Estimate 2 days
Create user dashboard for post like and following management
For this section we will open a new branch called feature/user-dashboard
.
Continuing on the last section , we’re going to create a new electron window in which we will present current user info about post following and likes. Also, in that window user must see his/her current user info. Furthermore, there has to be an ability to unfollow or unlike a post. If a user wants to like new posts, there has to be a link that directs the user to official tumblr page to do that. If you want to add something extra to your dashboard, take a look at the Tumblr API docs in the User methods
section and create your feature.
Regarding the design, you are free to use your imagination and create the design as you wish.
4th Commit point
As usual, commit your changes, make a PR on your repo and contact your onboarding buddy.
Estimate 1 day
Custom native dock, toolbar actions and notifications for macOs
To explore what are our native options of our electron API we are going to create native actions for our dock. Use your imagination and think of some actions in dock that would benefit our user. The same thing goes for toolbar actions. Think of actions that can be put in the native toolbar of the window and broad the UX of our app. Last thing that we need to do is implement notifications. Try to combine the tumblr API and native notifications and display useful notifications to our user.
5th Commit point
This will be your last commit if you don’t want to do extra stuff. So make a PR and contact your onboarding buddy. :thumbsup: Your onboarding is finished !! 🙌
Estimate 1 day
Extras - (if you want)
We guess you’ve made your own service for data fetching and persisting, but if you want to explore more libraries there is an interesting library called react-query. It’s an opinionated lightweight data fetching library which uses Context API. It comes with out of the box fetching, caching, synchronizing and updating server state. It really comes in handy on smaller projects where you don’t want to introduce redux and its complex logic. Read the official docs and try and wrap up your services with that lib.
As a conclusion think of what are pros and cons of using that kind of lib.
6th Commit point (optional)
If you decided to do some extra stuff make your PR and give it to your onboarding buddy for reviewing
Estimate 1 day