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