Vue electron自动更新/ electron手动更新

Vue electron自动更新 /electron手动更新

Uncaught TypeError: fs.existsSync is not a function

所有的帖子都是一样的,都不去试一下 ,这偏文章我把坑都走了一遍。
直接上代码

最主要的就是这个问题 const electron = require(‘electron’).ipcRenderer 能不用引用
这个问题解决了 后面的就简单了
这么多帖子 居然没有一个说这个问题
代码在gitee上 地址在最下面
在这里插入图片描述

直接引用就会报错
#Uncaught TypeError: fs.existsSync is not a function
在这里插入图片描述

产生问题的原因:

首先在渲染进程属于浏览器端,没有集成Node的环境,所以类似 fs 这样的Node的基础包是不可以使用。

因为没有Node环境,所以require关键词是不可以使用的。

这个 stackoverflow 上找的方法
新建一个 preload.js

const electron = require('electron');
window.ipcRenderer = require('electron').ipcRenderer;   //  直接吧 electron.ipcRenderer 方法挂载在windows上面
window.remote = require('electron').remote;

在main.js文件中的 webPreferen中设置预加载preload:

  const win = new BrowserWindow({
    width: 1920,
    height: 1040,
    frame:true,
    webPreferences: {
      nodeIntegration:true,
      contextIsolation:false,
      webSecurity: false,
      preload:__dirname+'\\preload.js' ,
    }
  })

在这里插入图片描述

这个重点提一下preload.js 存放位置 位置真的很重要 不然就 undefined

本地的 preload.js 放在 打包之后的位置

在这里插入图片描述

打包之后的 preload.js 放在 public 下 和index.html 同目录

在这里插入图片描述

放了两个 我之前就是 只放了一个 所有 本地运行没问题 打包之后就报错了
真特么坑 居然没有一个帖子说这个问题 也有可能只有我遇见了这个问题
不然就是这样 找不到
在这里插入图片描述

下面开始 安装 electron-updater
// 推荐yarn
yarn add electron-updater --save-dev  

// *不推荐 npm  反正我是一次都没装成功过  
**npm i electron-updater --save-dev

这个必须有 不然打包不会生成 latest.yml 文件

每次更新把 yml 和 exe 丢给后端就行了

//这个必须有  不然打包不会生成 latest.yml 文件
 publish:[
      {
     "provider":"generic", 
       url: "http://192.168.0.191/electron/" // 更新文件服务器地址
      }
    ],

新建updata.js

import {
    autoUpdater
} from 'electron-updater'
 
import {
    ipcMain
} from 'electron'
let mainWindow = null;
autoUpdater.autoDownload = false;
let canQuit = false;
export function updateHandle(window, feedUrl) {
    mainWindow = window;
    let message = {
        error: '检查更新出错',
        checking: '正在检查更新……',
        updateAva: '检测到新版本,正在下载……',
        updateNotAva: '现在使用的就是最新版本,不用更新',
    };
    //设置更新包的地址
    autoUpdater.setFeedURL(feedUrl);
    //监听升级失败事件
    autoUpdater.on('error', function (error) {
        sendUpdateMessage({
            cmd: 'error',
            message: error
        })
    });

    //监听开始检测更新事件
    autoUpdater.on('checking-for-update', function (message) {
        sendUpdateMessage({
            cmd: 'checking-for-update',
            message: message
        })
    });
    //监听发现可用更新事件
    autoUpdater.on('update-available', function (message) {
        sendUpdateMessage({
            cmd: 'update-available',
            message: message
        })
    });
    //监听没有可用更新事件
    autoUpdater.on('update-not-available', function (message) {
        sendUpdateMessage({
            cmd: 'update-not-available',
            message: message
        })
    });
 
    // 更新下载进度事件
    autoUpdater.on('download-progress', function (progressObj) {
        sendUpdateMessage({
            cmd: 'download-progress',
            message: progressObj
        })
    });

    autoUpdater.on('close', (event) => {
        if (!canQuit) {
            mainWindow.hide();
            mainWindow.setSkipTaskbar(true);
            event.preventDefault();
        }
    });

    //监听下载完成事件
    autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl) {
        sendUpdateMessage({
            cmd: 'update-downloaded',
            message: {
                releaseNotes,
                releaseName,
                releaseDate,
                updateUrl
            }
        })
        //退出并安装更新包
        if (process.platform !== 'darwin') {
            canQuit = true;
            autoUpdater.quitAndInstall();
        }
        // autoUpdater.quitAndInstall();
    });
 
    //接收渲染进程消息,开始检查更新
    ipcMain.on("checkForUpdate", (e, arg) => {

        //执行自动更新检查

        // sendUpdateMessage({cmd:'checkForUpdate',message:arg})
        if(arg){
            autoUpdater.autoDownload = true;
        }
        autoUpdater.checkForUpdates();
    })
}
//给渲染进程发送消息
function sendUpdateMessage(text) {
    mainWindow.webContents.send('message', text)
}

backgrounnd.ts 我用的ts 这个和你们main.js 是一样


import { app, protocol, BrowserWindow,Menu } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
// import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'

// 自动更新    引入上面创建的 updater.js 
import {updateHandle} from './updater.js' ;  

const isDevelopment = process.env.NODE_ENV !== 'production'

// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
  { scheme: 'app', privileges: { secure: true, standard: true } }
])

async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 1920,
    height: 1040,
    frame:true,
    webPreferences: {

      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      // nodeIntegration: (process.env
      //     .ELECTRON_NODE_INTEGRATION as unknown) as boolean,
      // contextIsolation: !(process.env
      //     .ELECTRON_NODE_INTEGRATION as unknown) as boolean,
      nodeIntegration:true,
      contextIsolation:false,
      webSecurity: false,
      // preload:'./src/preload.js' ,
      preload:__dirname+'\\preload.js' ,   这里是重点  //  这里引入 preload.js
    }
  })
  Menu.setApplicationMenu(null)

  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
   
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
    win.webContents.openDevTools()
    // win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string)
  }
  updateHandle(win, 'http://192.168.0.191/electron/');
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) createWindow()
})

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
  // if (isDevelopment && !process.env.IS_TEST) {
  //   // Install Vue Devtools
  //   try {
  //     await installExtension(VUEJS_DEVTOOLS)
  //   } catch (e) {
  //     console.error('Vue Devtools failed to install:', e.toString())
  //   }
  // }
  createWindow()
})

// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
  if (process.platform === 'win32') {
    process.on('message', (data) => {
      if (data === 'graceful-exit') {
        app.quit()
      }
    })
  } else {
    process.on('SIGTERM', () => {
      app.quit()
    })
  }
}

如果 updater.js 引用错误

在这里插入图片描述

在同目录 把updater.js copy 一份 吧名字改成 updater.ts 就好了

在这里插入图片描述

app.vue 设置更新页面

这个页面包含手动更新 和自动更新

<template>
    <div id="app">
        <a-config-provider :locale="zh_CN">
            <router-view />
        </a-config-provider>

        <a-modal v-model="modalVisible" width="300PX" :footer="null" :closable="false" :keyboard="false"
            :maskClosable="false" wrapClassName="supplement-detail-modal" :title="isUpdatte?'检查到新版本...':'系统正在更新...'">
            <div style="width:120px;margin:30px auto;" v-if="isUpdatte">
                <a-progress type="circle" :percent="percent" :format="percent => `${percent} %`" />
            </div>
            <div style="display:flex;justify-content: space-between;" v-if="!isUpdatte">
                <a-button type="primary" @click="isUpdatte=true" style="margin:30px auto;">
                    更新新版本
                </a-button>
            </div>
        </a-modal>
    </div>

</template>
<script>
    import zh_CN from 'ant-design-vue/lib/locale-provider/zh_CN';
    import moment from 'moment';
    import 'moment/locale/zh-cn';
    import {
        ConfigProvider,
        progress,
        button
    } from 'ant-design-vue'
    // const electron = require('electron').ipcRenderer;

    const ipcRenderer = window.ipcRenderer
    moment.locale('zh-cn');
    export default {
        components: {
            AConfigProvider: ConfigProvider,
            AProgress: progress,
            AButton: button,
        },
        data() {
            return {
                zh_CN,
                modalVisible: false,
                percent: 0,
                isUpdatte: false,
            };
        },
        mounted() {
            if (ipcRenderer) {
                const _this=this
                ipcRenderer.on("message", (event, arg) => {
                    // for (var i = 0; i < arg.length; i++) {
                    console.log(arg);
                    if ("update-available" == arg.cmd) {
                        //显示升级对话框
                        _this.modalVisible = true;
                        if(!_this.isUpdatte)return;
                    } else if ("download-progress" == arg.cmd) {
                        //更新升级进度
                        /**
                         * 
                         * message{bytesPerSecond: 47673
                          delta: 48960
                          percent: 0.11438799862426002
                          total: 42801693
                          transferred: 48960
                          }
                         */
                        console.log(arg.message.percent);
                        let percent = Math.round(parseFloat(arg.message.percent));
                        _this.percent = percent;
                    } else if ("error" == arg.cmd) {
                        _this.modalVisible = false;
                        _this.$message.error("更新失败");
                    }
                    // }
                });
            }
        },
        created() {
            //间隔1小时检测一次
            alert(ipcRenderer)
            let _this=this
            window.setInterval(() => {
            	// _this.isUpdatte == true 就是自动更新 获取到新版会自动更新 重新安装程序  推荐手动更新  
            	//  _this.isUpdatte == false 就是自动更新 
                ipcRenderer.send("checkForUpdate",_this.isUpdatte);
                
            }, 10000);
        }
    };
</script>
<style lang="less">
    .ant-popover-message {
        * {
            font-size: 22px !important;
        }

        .ant-popover-buttons {
            .ant-btn {
                font-size: 22px !important;
            }
        }
    }

    @font-face {
        font-family: AGENCYB;
        src: url('./assets/AGENCYB.TTF');
    }

    @font-face {
        font-family: AGENCYR;
        src: url('./assets/AGENCYR.TTF');
    }

    html,
    body,
    #app {
        height: 100%;
        width: 100%;
        padding: 0;
        margin: 0;
    }

    div {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
    }

    .box-title {
        position: relative;
        line-height: 32px;
        height: 32px;
        font-size: 18px;
        padding-left: 15px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        font-weight: bold;

        &.border {
            border-bottom: 1px solid #A7B0C1;
        }

        &:before {
            position: absolute;
            left: 0;
            top: calc(16px - 8px);
            content: '';
            display: inline-block;
            width: 4px;
            height: 18px;
            background: #2c3e50;
        }
    }

    .box-content {
        height: calc(100% - 32px);
    }

    .second-title {
        position: relative;
        line-height: 24px;
        height: 24px;
        font-size: 16px;
        padding-left: 15px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        color: #939393;

        &:before {
            position: absolute;
            left: 0;
            /*top: calc(12px - 3px);*/
            content: '';
            display: inline-block;
            width: 6px;
            height: 6px;
            border-radius: 50%;
            background: #5190eb;
        }
    }

    .ant-modal-body {
        padding-top: 0;
    }
</style>

现在获取新版本 直接报错 cmd: “update-not-available”

死活找不到这个问题 全带全部没有问题

原来是 版本号一样 程序判断不需要更新! 明明已经有了 latest.yml 还需要版本号 真的坑

打包的时候 就改一下 package.json 里面 version 就可以了
在这里插入图片描述

到这一本就可以实现 自动更新

你以为完了

他现在是会自动 更新了 TM的 自动更新 安装会失败
原因是因为 appid 是一样
所有修改版本号的同时也要修改 appid

在这里插入图片描述

每次打包都要修改appid 和版本号 无语了

下面放打包 自动修改 version 和appid代码 我的配置在vue.config.js 里面 你也可以把代码放在 build.js 里面

 const path = require('path')
var webpack = require('webpack');
const fs = require('fs');

const demoName="app"
function resolve(dir) {
    return path.join(__dirname, dir)
}

//------------------------ 自动修改 版本号   用版本号 做appid 
function AddZero(time){
    if(time<10){
      return "0"+time
    }else{
      return time
    }
  }
  let packageTxt=fs.readFileSync('./package.json','utf8');
  let versionData = packageTxt.split('\n');
  let packageJson = JSON.parse(packageTxt);
  let VersionArr = packageJson.version.split('.');
  let date = new Date();
  let today = date.getFullYear()+""+AddZero((date.getMonth()+1))+""+AddZero(date.getDate())
  if(today == VersionArr[1]){
    VersionArr[2] = parseInt(VersionArr[2])+1
  }else{
    VersionArr[1] = date.getFullYear()+""+AddZero((date.getMonth()+1))+""+AddZero(date.getDate())
    VersionArr[2] = 1;
  }
  let versionLine = VersionArr.join('.');
  for(let i= 0; i<versionData.length;i++){
    if(versionData[i].indexOf('"version":')!=-1){
      versionData.splice(i,1,'  "version": "'+versionLine+'",');
      break;
    }
  }
  fs.writeFileSync('./package.json',versionData.join('\n'),'utf8');
//------------------------


module.exports = {
    outputDir: 'dist',
    publicPath: './',
    productionSourceMap: false,

    // 简单配置webpack
    configureWebpack: {
        // provide the app's title in webpack's name field, so that
        // it can be accessed in index.html to inject the correct title.
        resolve: {
            alias: {
                '@': resolve('src')
            }
        },
    },
    //  更加细粒化的配置webpack
    //  取自vue-admin-template
   
    chainWebpack: config => {
        config.module
            .rule('svg')
            .exclude.add(resolve('src/svg-icon'))
            .end()
        config.module
            .rule('icons')
            .test(/\.svg$/)
            .include.add(resolve('src/svg-icon'))
            .end()
            .use('svg-sprite-loader')
            .loader('svg-sprite-loader')
            .options({
                symbolId: 'icon-[name]'
            })
            .end()

    },
    pluginOptions: {
        electronBuilder: {
            // List native deps here if they don't work
      // 原生包必须这里声明下
      externals: ["serialport"],
    //   If you are using Yarn Workspaces, you may have multiple node_modules folders
    //   List them all here so that VCP Electron Builder can find them
      nodeModulesPath: ["../../node_modules", "./node_modules"],
      nodeIntegration: true,
            // 打包配置
            builderOptions: {
                "appId": demoName+versionLine,
               
                // 发布者名称
                productName: demoName,

                // 安装包名称,可自行配置
                artifactName: demoName+'.exe',
                
                nsis: {
                    // 一键安装,如果设为true,nsis设置就无意义请直接删除 nsis 配置
                    oneClick: false,
                    // true全用户安装【目录为:C:\Program Files (x86)】,false安装到当前用户
                    perMachine: true,
                    // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
                    allowElevation: true,
                    // 允许修改安装目录
                    allowToChangeInstallationDirectory: true,
                    // 创建桌面图标
                    createDesktopShortcut: true,
                    // 创建开始菜单图标
                    createStartMenuShortcut: true,
                    // 快捷方式的名称,默认为应用程序名称
                    shortcutName: demoName,
                    // 安装图标
                    // installerIcon: "./logo.png",// 安装图标
                    // uninstallerIcon: "./logo.png",//卸载图标
                    // installerHeaderIcon: "./logo.png", // 安装时头部图标
                },
                // files: [
                //     {
                //       'filter': ['**/*']
                //     }
                //   ],
                //   extraFiles: ['./extensions/'],
                //   asar:  false,
                publish:[
                    {
                        "provider":"generic",
                        url: "http://192.168.0.191/electron/" // 更新文件服务器地址
                    }
                ],
            }
        }
    },
  
    
}

如果打包软件报错

在这里插入图片描述
这个因为electron 版本问题

yarn add   electron    //  直接yarn  在安装一遍  不要用npm  

最后放上代码

我知道你想说什么 依赖下载失败
我把 node_modules 都上传了
就问你细不细节

项目地址: vue-eletron 自动更新/手动更新 .

点个赞好吗 铁子!

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
### 回答1: Vue Electron 是一个结合了Vue.jsElectron的框架,可以用于构建基于Electron的跨平台桌面应用程序。热更新是指在开发过程中,当我们修改代码后,应用程序能够自动更新,而不需要重启整个程序。 Vue Electron可以通过vue-cli-plugin-electron-builder插件实现热更新。首先,在开发环境下,我们可以使用npm run electron:serve启动一个开发服务器,并启动Electron来访问该服务器。这时,我们可以修改代码并保存,自动触发热更新,实时查看修改效果。 具体来说,当我们修改代码时,Webpack会自动重新构建我们的应用程序,并将编译后的文件保存在内存中。然后,Electron会监测到文件变化,从内存中获取最新的文件,实现热更新。这意味着,我们无需重启整个应用程序,就能够查看到我们对代码所做的修改。 这样的热更新机制可以大大提高开发效率,节约开发时间。我们可以立即看到修改的结果,并及时发现潜在的错误。而且,由于热更新只在开发过程中使用,最终的生产版本没有热更新相关的代码,因此不会影响应用程序的性能。 总而言之,Vue Electron提供了方便的热更新机制,使我们在开发过程中能够实时查看代码修改的效果,提高开发效率。 ### 回答2: Vue Electron 是将 Vue.jsElectron 框架结合起来使用的一种解决方案,它可以用来构建跨平台的桌面应用程序。而热更新指的是在应用程序运行过程中,无需重新编译和启动应用,实时地更新界面和逻辑的机制。 在 Vue Electron 中实现热更新可以通过使用 Vue Cli 3 的一些插件来完成。首先,我们需要安装 `@vue/cli-plugin-electron-builder` 插件,它可以帮助我们打包和构建 Electron 应用。 接下来,我们可以使用Vue Cli提供的热更新插件 `@vue/cli-plugin-electron-builder`,来实现热更新的功能。这个插件在开发模式下使用 `webpack-dev-server` 来启动一个本地服务器,并且监测文件的变化。当文件发生变化时,自动重新编译并实时刷新 Electron 应用的界面和逻辑。 为了使用热更新功能,我们可以在 Vue 的 `main.js` 文件中添加以下代码: ``` javascript if (process.env.WEBPACK_DEV_SERVER_URL) { // 如果是开发模式 require('electron-reload')(__dirname, { electron: require(`${__dirname}/node_modules/electron`) }) win.loadURL(process.env.WEBPACK_DEV_SERVER_URL) } else { // 如果是生产模式 win.loadURL(formatUrl({ pathname: path.join(__dirname, 'index.html'), protocol: 'file', slashes: true })) } ``` 这段代码会根据环境变量判断是开发模式还是生产模式,如果是开发模式,就使用 `webpack-dev-server` 来启动本地服务器,并且使用 `electron-reload` 插件来实现热更新的功能。 总的来说,在 Vue Electron 中实现热更新可以通过 Vue Cli 插件和一些配套的工具实现。这个功能可以提高开发效率,特别是在调试和测试阶段,能够快速反馈界面和逻辑的变化。 ### 回答3: Vue Electron 是一个结合了 Vue.jsElectron 框架的工具,允许开发者使用Vue的开发模式来构建桌面应用程序。对于热更新的支持,Vue Electron 提供了一些解决方案。 首先,Vue Electron 支持使用Vue的热更新开发模式。在开发过程中,可以通过修改代码后保存自动刷新应用程序,从而实现实时预览效果。这对于开发者来说是非常方便的,可以加快开发效率。 其次,Vue Electron 还提供了一种叫做 electron-webpack 的插件,可以帮助我们更好地实现热更新electron-webpack 提供了一种自动重启 Electron 应用程序的机制。只要我们修改了 Vue 组件中的代码,保存后即可自动重启应用程序,以加载最新的代码。这样我们就可以实时看到修改后的效果,无需手动重启应用程序。 除了上述热更新方案,Vue Electron 还支持使用 Vite,Vite 是一个基于 Rollup 的下一代前端构建工具,可以实现快速的冷启动和热模块替换。通过结合 Vue Electron 和 Vite,我们可以更高效地进行开发,并获得更好的热更新体验。 总结起来,Vue Electron 提供了几种热更新的解决方案,包括内置的热更新开发模式、electron-webpack 插件以及集成 Vite。这些方案可以帮助开发者实现快速的应用程序开发和实时预览效果,提高开发效率。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值