electron 第三方资源问题 node-notifier

1,269 阅读2分钟

问题处理过程

  • 使用 node-notifier 文档配置,一直不生效;
  • 可能是 vue-cli-plugin-electron-builder 的问题,在 vue.config.js
    • 配置 asarUnpack 无效;
  • 所以使用自定义 customPath,但是打包后发现app下的node_modules不存在node-notifier
    • 写一个 webpack插件 手动复制 vendor 到构建输出目录下新建目录node-notifier,应用打包时会被复制到app根目录
    • 注意不要将 vendor 复制到构建输出的 node_modules 下,应用打包会忽略的

【注意】:需要设置 asar: false !!!

background.js

动态设置自定义 customPath,开发启动与构建的vendor路径有区别

  • vendorPath 设置
const vendorPath = isDevelopment ? './node_modules/node-notifier' : 'node-notifier';
  • customPath 代码

这里只设置了 Windows+MacOS 两个平台,其他的根据需要可以看下 node-notifier 文件结构获取

import path from "path";
import os from 'os';
import { Notification } from "node-notifier";

const isDevelopment = process.env.NODE_ENV !== "production";

const basePath = isDevelopment ? process.cwd() : __static;
const vendorPath = isDevelopment ? './node_modules/node-notifier' : 'node-notifier';
const customPathMap: Record<string, string> = {
  Darwin: path.join(basePath, vendorPath, 'vendor/mac.noindex/terminal-notifier.app/Contents/MacOS/terminal-notifier'),
  Windows_NT: path.join(basePath, vendorPath, `vendor/snoreToast/snoretoast-x86.exe`),
};
const notifier = new Notification({
  withFallback: true,
  customPath: customPathMap[os.type()] || undefined
});

electron-builder

需要配置 asar: false

如下在 vue-cli 项目使用 vue-cli-plugin-electron-builder,在 vue-config.js 中配置

  pluginOptions: {
    electronBuilder: {
      builderOptions: {
        asar: false,
      },
    },
  },

webpack 插件

写一个插件,复制需要的东西到指定路径

CopySourceWebpackPlugin

const { exec } = require('child_process');
const { existsSync } = require('fs');

module.exports = class CopySourceWebpackPlugin {
  /**
   * @param {{from: string; to: string}[]} source
   */
  constructor(source) {
    this.name = 'CopySourceWebpackPlugin';
    this.source = source;
  }

  /** @param {import('webpack').Compiler} compiler */
  apply(compiler) {
    compiler.hooks.done.tap(this.name, () => {
      this.handleCopy();
    });
  }

  handleCopy() {
    if (!Array.isArray(this.source)) return;
    this.source.forEach(({from, to}) => {
      if (!existsSync(from)) {
        console.log(from, '不存在!');
        return;
      }
      if (!existsSync(to)) exec(`mkdir -p ${to}`);
      exec(`cp -r ${from} ${to}`, err => {
        if (err) throw (`复制${from}出错!`, err);
      });
    });
  }
}

插件使用

  • 注意不要直接复制到 node_modules 下,打包应用时会被忽略
  • 此时输出的 node-notifier/vendor 目录是在应用资源包 app 路径下的根目录,如MacOS打包后的路径:dist_electron/mac/{app name}.app/Contents/Resources/app

如下在 vue.config.js 中配置

{
  configureWebpack: config => {
    const source = [{
      from: path.resolve(__dirname, 'node_modules/node-notifier/vendor/'),
      to: path.resolve(__dirname, 'dist_electron/bundled/node-notifier')
    }];
    config.plugins.push(new CopySourceWebpackPlugin(source));
  },
}

打包后debug

可以使用 electron-log 这个包输出日志,如 MacOS 查看 ~/Library/Logs/{app name}/main.log 文件

const log = require('electron-log');

log.info('aa');
log.debug('debug');