时间:2023-07-21 08:16:52 点击次数:14
创建一个名为my-electron-app的文件夹,会产生package.json文件夹
//尽量不要用中文,养成良好规范 { "name": "my-electron-app", "version": "1.0.0", "description": "hello world", "main": "main.js", "author": "Zhou Jing", "license": "MIT" }然后,将 electron 包安装到应用的开发依赖中。
npm install --save-dev electron接下根目录下创建一个名字为app的文件夹,然后在此文件夹下创建两个子文件夹,main和render,因为electron是分为主进程和渲染进程的,所以创建两个文件夹以区分开.
main文件夹下新建main.js作为主进程的入口,以下代码参考官网
const path = require(path) const {app ,BrowserWindow}= require(electron) function createWindow(){ const mainWindow = new BrowserWindow({ width:1200, height:800, webPreferences:{ nodeIntegration:true, contextIsolation:false },//这个是为了能在主进程中引入node模块,必须项 })//这个是创建了新窗口 mainWindow.loadFile(../render/index.html) //选择加载html文件 } app.whenReady().then( () => { createWindow() app.on(activate , () => { if(BrowserWindow.getAllWindows().length === 0)createWindow() }) })注意的点有两个
webpreferences这个选项官网上没有,这个必须写上,两个选项都是必须,否则无法在主进程使用Node模块loadFile模块加载的index.html属于渲染进程模块在render文件夹下创建index.html文件,代码如下
<!DOCTYPE html> <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>electron app</title> </head> <body> <div id="root">大家好,这是我的第一electron app</div> </body> </html>最后修改一下package.json问家中的scripts选项
"start:electron": "electron ./app/main/main.js"在根目录文件夹下,输入命令行npm run start:electron,就可以看到原始electron项目效果
react环境搭建
接着安装一下 Babel,它是 JS 编译器,能将 ES6 代码转成 ES5,让我们使用最近的语言特性,而不需要担心兼容性的问题。
npm install @babel/polyfill --save npm install @babel/core @babel/cli --save-dev npm install @babel/preset-env @babel/preset-react @babel/preset-typescript --save-dev npm install @babel/plugin-transform-runtime --save-dev npm install @babel/plugin-transform-modules-commonjs --save-dev下面分析每个模块的作用以及功能
Babel 的核心功能包含在 @babel/core 模块中。看到 core 这个词了吧,意味着核心,没有它,在 babel 的世界里注定寸步难行。不安装 @babel/core,无法使用 babel 进行编译。
它会仿效一个完整的 ES2015+ 环境,并意图运行于一个应用中而不是一个库/工具。这个 polyfill 会在使用 babel-node 时自动加载。
这意味着你可以使用新的内置对象比如 Promise 或者 WeakMap, 静态方法比如 Array.from 或者 Object.assign, 实例方法比如 Array.prototype.includes 和生成器函数(提供给你使用 regenerator 插件)。为了达到这一点, polyfill 添加到了全局范围(不是开发环境),就像原生类型比如 String 一样。
@babel/preset-env 主要作用是对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill,在不进行任何配置的情况下,@babel/preset-env 所包含的插件将支持所有最新的JS特性(ES2015,ES2016等,不包含 stage 阶段),将其转换成ES5代码。例如,如果你的代码中使用了可选链(目前,仍在 stage 阶段),那么只配置 @babel/preset-env,转换时会抛出错误,需要另外安装相应的插件。
同理@babel/preset-react 和@babel/preset-typescript类似,引入了编译react与typescript的插件
官网上有几种babel配置项选项,这里我采用babel.config.js,在根目录文件下创建Babel.config.js文件
module.exports = { presets:["@babel/preset-env" ,"@babel/react","@babel/typescript"], plugins:[ "@babel/plugin-transform-runtime", [ "@babel/plugin-transform-modules-commonjs", { allowTopLevelThis: true, loose: true, lazy: true, } ] ] }如果期望监听文件的变化,能够自动刷新网页,做到实时预览,而不是改动一个字母,一个文字都需要重新打包。业界较为成熟的解决方案是通过:webpack-dev-server 插件,OK,我们安装它。
npm install webpack-dev-server --save-dev对于主进程和渲染进程来讲,webpack的配置是会存在差异的。比如渲染进程可能需要 less-loader、htmlWebpackPlugins 等“专属”配置,而这些配置对于主进程来讲,是无用的。
存在差异的同时又会有相同点,比如 alias 别名配置等,当我们不采用 webpack-merge 时,会导致每份配置会存在重复的“配置”代码。其次在 dev 和 prod 环境下,配置会存在一些小差别,这时我们代码中会充斥着一些三元运算符来判断环境。最后的结果为每一份配置的可读性相对较差。
通过webpack-merge 插件进行处理,可以将公共配置抽离出来,然后其他部分按照自己的模块配置
npm install webpack-merge --save-dev我们不想每次打包都需要手动修改 HTML 中的文件引用,并且期望采用自己写的 HTML 文件为模版,生成打包之后的入口 HTML,为此我们采用 html-webpack-plugin 插件进行处理。
npm install html-webpack-plugin@4.3.0 --save-dev由于 Babel 用于编译,Webpack 用于打包输出,两者各司其职,我们通过 babel-loader 打通他们的联系。
npm install babel-loader --save-dev为了配置electron项目的webpack环境,在根目录下建立一个webpack文件夹,里面包含本项目的所有webpack选项
webpack.base.js:基础公共配置webpack.main.dev.js:主进程开发环境配置webpack.render.dev.js:渲染进程开发环境配置解读一下这段代码,Webpack 在启动后会从配置的入口模块出发,找到所有依赖的模块,resolve 配置 Webpack 如何寻找模块所对应的文件。我们配置了 extensions,表示在导入语句中没带文件后缀时,Webpack 会自动带上后缀去尝试访问文件是否存在。
我们配置中,配置了 extensions: [.js, .jsx, .ts, .tsx],意味着当遇到 import A from ./A 时,会先寻找 A.js、找不到就去找 A.jsx,按照规则找,最后还是找不到,就会报错。
alias 代表别名,因为我们经常写 import A from ../../../../../A这种导入路径,特别恶心,所以通过配置别名处理。关于 Loader,我们前边小节已介绍,它就是模块打包方案,上述代码即表示:当匹配到 /\.(js|jsx|ts|tsx)$/ 文件时,使用 babel-loader 去处理一下。
解读一下这段代码,我们定义入口文件为 /app/main/electron.js,并且定义打包出来的文件目录为 dist,文件名为 electron.js。
需要注意的一点是:由于 JS 的应用场景日益增长,从浏览器到 Node,运行在不同环境下的 JS 代码存在一些差异。target 配置项可以让 Webpack 构建出不同运行环境的代码
关于 target 的可选项,可从官网查阅,这里我们将其配置成 electron-main,至于主进程的 plugins,我们定义了一些构建变量。最后通过 webpack-merge 合并导出一份完整的配置。
render文件夹,负责项目的渲染模块,在 render 下创建一个 React 的 app.jsx 文件
import React from react; import ReactDOM from react-dom; import { HashRouter as Router, Route, Switch } from react-router-dom; function App() { return ( <Router> <Switch> <Route path="/"> <div>可视化简历平台</div> <div>这是 Electron + React </div> </Route> </Switch> </Router> ); } ReactDOM.render(<App />, document.getElementById(root));接下来配置webpack.render.dev.js
const path = require(path); const webpackMerge = require(webpack-merge); const baseConfig = require(./webpack.base.js); const HtmlWebpackPlugin = require(html-webpack-plugin); const devConfig = { mode: development, entry: { // 对应渲染进程的 app.jsx 入口文件 index: path.resolve(__dirname, ../app/render/app.jsx), }, output: { filename: [name].[hash].js,//生成不同文件的hash文件,避免文件名冲突 path: path.resolve(__dirname, ../dist), }, target: electron-render, devtool: inline-source-map, devServer: { contentBase: path.join(__dirname, ../dist), compress: true, host: 127.0.0.1, // webpack-dev-server启动时要指定ip,不能直接通过localhost启动,不指定会报错 port: 7001, // 启动端口为 7001 的服务 hot: true, }, plugins: [ new HtmlWebpackPlugin({ // 以此文件为模版,自动生成 Html template: path.resolve(__dirname, ../app/render/index.html), filename: path.resolve(__dirname, ../dist/index.html), chunks: [index], }), ], }; module.exports = webpackMerge.merge(baseConfig, devConfig);解读一下这段代码,以 /app/render/app.jsx 为入口,并配置了本地开发 devServer,通过 HtmlWebpackPlugin 自动生成一份以 /app/render/index.html 为模版的 HTML 文件。注意此时的 target是针对 Electron 渲染进程。最后通过 webpack-merge 合并导出一份完整配置。