Recently, I need to make a desktop application. I believe that many front-end applications will definitely choose electron to make desktop application. After checking for a long time, there is an electron vue. Developing Electron has two processes, the renderer process and the main process. First we build the main process.

The main process

Initialize folders

mkdir electron-react&&npm init --yes
Copy the code

Install dependencies

We all use TS for development, so WE have installed TS as well. The electron here may need scientific Internet connection to install normally, otherwise it may be slow to install. The version of my electron installation here is 15.1.2

yarn add electron typescript -D
Copy the code

Initialize ts after installation

tsc --init
Copy the code

This generates a tsconfig.json file, which we rename tsconfig.json to tsconfig.main.json and then we configure the following basic TS configuration items

{
  "compilerOptions": {

    "target": "esNext"./* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs"./* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "jsx": "react"./* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
    "outDir": "main-dist"./* Redirect output structure to the directory. */
    /* Strict Type-Checking Options */
    "strict": true./* Enable all strict type-checking options. */
    "noImplicitAny": true./* Raise error on expressions and declarations with an implied 'any' type. */
    "strictNullChecks": true./* Enable strict null checks. */

    "baseUrl": "."./* Base directory to resolve non-absolute module names. */
    "paths": {},                                 /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    "esModuleInterop": true./* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */

    /* Advanced Options */
    "skipLibCheck": true./* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
  },
  "include": ["./main/**/*"]."exclude": ["dist"."node_modules"]}Copy the code

The main process controls the window, and the render process is responsible for rendering. The main process creates a window that can load the URL, and it can load the local file, so we can open the local file directly. Type in the new main/index.ts file to open a window

import {BrowserWindow,app} from 'electron'
function createWindow(){
    const window:BrowserWindow=new BrowserWindow({
        height:1000.width:1000.webPreferences: {webSecurity:false.contextIsolation:false.nodeIntegration:true,}})window.loadFile('.. /main/index.html');
    return window;
}
app.on('ready'.() = >{
    process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] ='true'// Turn off the Web security warning
    createWindow();
})
Copy the code

This is to create a window and load the index.html file at the same level. To execute the main process, first we need to compile ts and write the script command in our package.json

 "scripts": {
    "start:main": "tsc --p tsconfig.main.json" //--p specifies the ts configuration file
  },
Copy the code

Do yarn start:main, we can see that there is a main-dist file in the root directory, this file is ts compiled JS file, we need to execute this js file, we are adding a command

 "scripts": {
    "build:main": "tsc --p tsconfig.main.json"."start:electron": "electron ./main-dist/index"
  },
Copy the code

To do this we need to create a main/index.html file, which is the HTML file that our window will load.

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">hello electron</div>
</body>
</html>
Copy the code

Then execute YARN Build :electron, and we’ll see that we’ve launched a window that says Hello electron. At this point, our main process is set up, and of course there will be some changes after the render process is set up. Now let’s set up the render process,

Rendering process

We will use webpack to create a React project. Before setting up the react project, we will make a copy of tsconfig.main.json and rename it to tsconfig.json

{
  "compilerOptions": {
    "target": "esNext"./* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs"./* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "jsx": "react"./* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
    "outDir": "./render/dist"./* Redirect output structure to the directory. */
    /* Strict Type-Checking Options */
    "strict": true./* Enable all strict type-checking options. */
    "noImplicitAny": true./* Raise error on expressions and declarations with an implied 'any' type. */
    "strictNullChecks": true./* Enable strict null checks. */
    "baseUrl": "."./* Base directory to resolve non-absolute module names. */
    "paths": {},                                 /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
    "esModuleInterop": true./* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    /* Advanced Options */
    "skipLibCheck": true./* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true        /* Disallow inconsistently-cased references to the same file. */
  },
  "include": ["./render/**/*"]."exclude": ["dist"."node_modules"]}Copy the code

Install dependencies

Install webPack dependencies

yarn add webpack webpack-cli webpack-dev-server webpack-merge html-webpack-plugin clean-webpack-plugin  -D
Copy the code

Install react dependencies

yarn add react react-dom react-router-dom @types/react @types/react-dom @types/react-router-dom
Copy the code

Install the loader

yarn add ts-loader style-loader url-loader file-loader css-loader less-loader -D
Copy the code

Three files in the root directory of new render/config/webpack.com mon. Js render/config/webpack. Dev. Js render/config/webpack. Prod. Js

webpack.common.js

const webpack = require("webpack");
const path = require("path");
module.exports = {
  entry: "./render/index".output: {
    filename: "[name].js".path: path.join(__dirname, ".. /dist-render"),},// target:'web',
  target: "electron-renderer".resolve: {
    extensions: [".ts".".tsx".".js".".jsx".".json"].alias: {},},module: {
    rules: [{test: [/\.js$/./\.ts$/./\.tsx$/].exclude: /node_modules/,
        use: [
          {
            loader: "ts-loader",},],}, {test: [/\.less$/./\.css$/].// exclude:/node_modules/,
        use: [
          "style-loader",
          {
            loader: "css-loader".options: {
              modules: false.sourceMap: false,}},"less-loader",]}, {test: /.(jpg|png|gif)$/,
        use: {
          loader: "file-loader".options: {
            //
            name: "[name]_[hash].[ext]",},},},],},plugins: [],};Copy the code

This article will not explain webPack configuration too much, here we use TS-Loader for TS, JS, TSX compilation, CSS, less and static files use the most common loader.

Note that since the electron side can use Node in the Web, we can’t set the target to Web and use the electron renderer instead

webpack.dev.js

const webpack = require("webpack");
const { merge } = require("webpack-merge");
const common = require("./webpack.common");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const mode = "development";
module.exports = merge(common, {
  mode: "development".devtool: "inline-source-map".devServer: {
    hot: true.static: path.join(__dirname, ".. /dist-main"),
    historyApiFallback: {
      index: "./index.html",}},plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, ".. /public/index.html"),
      filename: "index.html",}).new webpack.HotModuleReplacementPlugin(),
  ],
});
Copy the code

webpack.prod.js

const webpack = require("webpack");
const  common  = require("./webpack.common");
const { merge } = require("webpack-merge");
const path=require('path')
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = merge(common, {
  mode: "production".devtool: "source-map".plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: path.join(__dirname, ".. /public/index.html"),
      filename: "index.html",})]});Copy the code

The new render/public/index. HTML

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
</body>
</html>
Copy the code

Create render/ SRC /app.tsx and initialize a root component

import { App } from "electron";
import React from "react";

export default function App() {
  return <div>hello react</div>;
}

Copy the code

The new render/index. The TSX

import React from "react";
import ReactDOM from "react-dom";
import App from "./src/app";
ReactDOM.render(<App />.document.getElementById("App"));
Copy the code

Now we can configure the renderer script command

 "scripts": {
    "start:react": "webpack serve --config render/config/webpack.dev.js"."build:react": "webpack --config render/config/webpack.prod.js"."start:main": "tsc --p tsconfig.main.json"."start:electron": "electron ./main-dist/index"
  },
Copy the code

Do yarn start:react and open port 8080

This error is normal, because the package we packaged using the electron renderer can only run in electron, so we modified our main process to load our local service, we need to install a dependency called electron IS-dev, Load the yarn Build: React package when we are not in a development environment.

yarn add electron-is-dev
Copy the code

Then modify our main/index.ts

import {BrowserWindow,app} from 'electron'
import isDev from 'electron-is-dev'
import {resolve} from 'path'
function createWindow(){
    const window:BrowserWindow=new BrowserWindow({
        height:1000.width:1000.webPreferences: {webSecurity:false.contextIsolation:false.nodeIntegration:true,}})if(isDev){
         window.webContents.openDevTools();// Open the console
        window.loadURL('http://localhost:8080')}else{
         window.loadFile(resolve(__dirname,".. /render/dist-render/index.html"));
    }
   
    return window;
}
app.on('ready'.() = >{
    process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] ='true'// Turn off the Web security warning
    createWindow();
})
Copy the code

And then we do yarn Build :main to package the main process, and every time we have to change the main process, we have to repackage the main process which is very troublesome, so we add hot update to the main process, how do we do that, it’s very simple just use Tsc-w, w stands for watch, ok

   "start:main":"tsc -w --p tsconfig.main.json".Copy the code

We can do yarn Start :main each time, and it will automatically repackage after we modify the main process file. Then we can do yarn Start :electron and we’ll see hello React, That means our entire electron application is set up.

Thermal overload

Electron thermal overload we can use the electron reloader

yarn add electron-reloader -D
Copy the code

Then add the code to main.ts

 if(isDev){
        try {
            require('electron-reloader') (module{}); }catch(_) {}window.webContents.openDevTools();
        window.loadURL('http://localhost:8080')}Copy the code

packaging

What do we do if we’re done developing and we want to pack, we need to install an electron Builder

yarn add electron-builder -D
Copy the code

Then we need to do some configuration in package.json, first specifying the project main entry and then packaging configuration

"main":"./main-dist/index.js"."build": {
    "productName": "test"."appId": "org.react.vas"."mac": {
      "icon": "assets/icon.icns"."type": "distribution"."target": [
        "dmg"."zip"]},"win": {
      "icon": "build/favicon.ico"."target": [
        "nsis"]},"nsis": {
      "oneClick": false."perMachine": true."allowToChangeInstallationDirectory": true."createDesktopShortcut": true."createStartMenuShortcut": false}},Copy the code

Here we need to pay attention to the ICNS commonly used by MAC. The generation of ICNS can refer to the ICNS icon of Quick Generation MAC App. After generating icNS, it is ok to put it in the designated folder. Then we add the package command,build: MAC is to package the MAC installation package,build: Win is to package the Windows installation package, we are the corresponding system installation package

  "build:mac": "electron-builder --mac",
  "build:win": "electron-builder --win"
Copy the code

Do yarn Build: MAC. After you wait, you will find a dist file in the root directory

Drag it in and open our test app and you’ll find that the app is empty. What’s the reason? It’s a common problem

output: {
    publicPath: '/'.filename: "[name].js".path: path.join(__dirname, ".. /dist-render"),},Copy the code

Over here the electron app we built ourselves has set up the warehouse address