Electron + React + Webpack + ts 从0到1搭建项目

617 阅读2分钟

说明:

Electron是一个能让你使用传统前端技术(Nodejs, Javascript, HTML, CSS)开发一个跨平台桌面应用的框架。这里所说的桌面应用指的是在Windows、OSX及Linux系统上运行的程序。

基于Electron实现的软件:

Electron现已被多个开源应用软件所使用,其中被广大程序员所熟知和使用的Atom和VsCode编辑器就是基于Electron实现的。尝试打开VsCode,点击帮助菜单中的切换开发人员工具,可以在界面上看到我们熟悉的Chrome devtool,如下图

底层实现:

由于应用场景是在系统平台上开发应用,所以我们开发时需要有能调用原生系统api的能力。为了能让前端语言能跟底层可以交互,Electron集成了Nodejs+Chromium。Nodejs主要负责应用程序主线程逻辑控制、底层交互等功能,Chromium主要负责渲染线程窗口的业务逻辑。主要的架构如下图:

废话不多说,接下来开始一步一步的搭建工作。

创建项目:

mkdir electron-react-ts
cd electron-react-ts
yarn init

配置 ts,根目录下  touch tsconfig.json

{    "compilerOptions":{        "target":"es5",        "module":"commonjs",        "lib":[            "dom",            "es2015",            "es2016",            "es2017"        ],        "allowJs":true,        "jsx":"react",        "sourceMap":true,        "outDir":"./dist",        "strict":true,        "esModuleInterop":true,        "baseUrl":"./",        "paths":{            "@/*":[                "./src/*"            ]        }    }}

配置 babel,根路径下 touch babel.config.js,(正常的 babel 配置即可)。

module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
    '@babel/preset-typescript'
  ]
}

配置项目文件 根路径下 mkdir public -> cd public -> touch index.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> 
  <div id="root"></div>  
 </body>
</html>

一、配置 Electron

yarn add -D electron \
webpack webpack-cli webpack-dev-server \
babel-loader @babel/core @babel/preset-env \
@babel/preset-react @babel/preset-typescript

配置 electron webpack,根路径  touch webpack.electron.config.js

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(process.cwd(), 'dist/electron'),
        filename: '[name].js',
    },
};

配置 electron 的入口文件 main.ts ,注意和 webpack 对应,allowRendererProcessReuse 这个属性会 ts 报错,没细究是版本问题还是其他的问题。

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,    },  });  mainWindow.webContents.openDevTools()  if (process.env.NODE_ENV === 'development') {    mainWindow.loadURL(`https://juejin.cn/post/7077545184807878692`);  } else {    mainWindow.loadURL(      url.format({        pathname: path.join(__dirname, './public/index.html'),        protocol: 'file:',        slashes: true      })    );  }  mainWindow.on('closed', () => {    mainWindow = null;  });}app.on('ready', createWindow);//@ts-ignoreapp.allowRendererProcessReuse = true;

配置 package.json 中的脚本,注意 main 为 elecrton 必须属性,其文件要注意对应。

{    "name":"electron-react-ts",    "version":"1.0.0",    "main":"./dist/electron/main.js",    "scripts":{        "dev:electron":"NODE_ENV=development webpack --config webpack.electron.config.js --mode development && electron ."    }}

windows 注意配置 crossenv,这里不多述;到这里 Electron 就配置好了。

二、配置 React

yarn add react react-dom @types/react @types/react-dom 
yarn add -D html-webpack-plugin

配置 react webpack,根路径 touch webpack.react.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    resolve: {
        mainFields: ['main', 'module', 'browser'],
        extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'],
        alias: {
            '@': path.resolve(__dirname, 'src'),
        },
    },
    entry: './src/index.tsx',
    target: 'web',
    devtool: 'source-map',
    module: {
        rules: [{
            test: /\.(js|ts|tsx)$/,
            exclude: /node_modules/,
            use: {
                loader: 'babel-loader',
            },
        },
        ],
    },
    devServer: {
        headers: {
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': '*',
            'Access-Control-Allow-Headers': '*',
        },
        historyApiFallback: true,
        compress: true,
        hot: true,
        port: 4000,
    },
    output: {
        path: path.resolve(process.cwd(), 'dist/react'),
        publicPath: '/',
        filename: '[name].js',
    },
    plugins: [new HtmlWebpackPlugin({
        inject: 'body',
        template: './public/index.html',
    }), ],
};

配置 react 的入口文件,注意和 webpack 关联,根路径下 mkdir src -> cd src -> touch index.tsx app.ts

index.tsx

import React from 'react';
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './app';
const rootElement = document.getElementById('root');
const root = createRoot(rootElement!);
root.render(<StrictMode><App /></StrictMode>);

 app.tsx

import React from 'react';
function App() {  
    return <div>sssss</div>;
}
export default App;

配置 package.json 中 react 脚本

{    "name":"electron-react-ts",    "version":"1.0.0",    "main":"./dist/electron/main.js",    "scripts":{        "dev:electron":"NODE_ENV=development webpack --config webpack.electron.config.js --mode development && electron .",        "dev:react":"NODE_ENV=development webpack-dev-server --config webpack.react.config.js --mode development"    }}

模板示例