electron 快速打包 vue 项目

主要记录我是如何快速将 vue 项目打包成安装包并安装在 windows、mac、以及 Linux 的,通过本文,你能了解到将一个 vue 项目打包成安装包的具体步骤。Electron 允许你使用 JavaScript, HTML 和 CSS 等 Web 技术创建原生程序,关于它的介绍,这里不赘述了。

首先,建议你使用 node js v11.10.0 版本,因为打包时用到的 docker 容器用的是 v11.10.0 版本,跨版本需要重新安装依赖,不方便。下面进入主题:

1、安装必要的依赖

npm install --save-dev cross-env
npm install --save-dev electron-builder
npm install --save-dev electron

2、在 package.json 的 scripts 节点里加入:

"electron": "cross-env NODE_ENV=dev node_modules/.bin/electron pack/electron",
"pack:prepare": "npm run build && cp -r pack/electron/* dist/",
"pack:win": "node_modules/.bin/electron-builder --project=dist -w -p never",
"pack:mac": "node_modules/.bin/electron-builder --project=dist -m -p never",
"pack:linux": "node_modules/.bin/electron-builder --project=dist -l -p never",
"build": "node build/build.js"

3、在 package.json 同级目录下,新建 pack 目录,在 pack 目录下新建 electron,在 electron 下新建 icons 目录, 将 软件桌面图标放置在 icons 下面,命名为:icon.png,尺寸得大于 512x512

4、在 electron 目录下 新建文件 electron-main.js,内容如下:

// Modules to control application life and create native browser window
const {
  app,
  BrowserWindow,
  Menu
} = require('electron');
const winState = require('./win-state');

global.APP_ENV = (process.env.NODE_ENV === 'dev') ? 'dev' : 'production';

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
  // get last win stage
  const lastWinStage = winState.getLastState();
  Menu.setApplicationMenu(null);
  // Create the browser window.
  mainWindow = new BrowserWindow({
    x: !isNaN(lastWinStage.x) ? lastWinStage.x : null,
    y: !isNaN(lastWinStage.y) ? lastWinStage.y : null,
    width: lastWinStage.width ? lastWinStage.width : 1100,
    height: lastWinStage.height ? lastWinStage.height : 728,
    icon: `${__dirname}/icons/icon.png`,
    useContentSize: true,
    center: true
  });

  winState.watchClose(mainWindow);

  // and load the index.html of the app.
  if (APP_ENV === 'production') {
    // mainWindow.loadFile('index.html');
    mainWindow.loadURL(`file://${__dirname}/index.html?version=${app.getVersion()}`);
  } else {
    mainWindow.loadURL(`http://localhost:9988/?version=${app.getVersion()}`);
  }

  // Open the DevTools.
  // mainWindow.webContents.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });

  // const contents = mainWindow.webContents;
  // // contents.openFindWindow();
  // contents.findInPage('133');
}

// 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', createWindow);

// 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 (mainWindow === null) {
    createWindow();
  }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.

注意,如果你的 vue 程序不是运行在 9988 端口,你需要将这里的 9988 改为你 vue 的运行端口,不然调试时加载不了,调试时等于从 url 加载内容,而正式发布后,从文件加载,所以这里有个坑,那就是 cookie 用不了,可以用 localstorage 替代。

5、在 electron 目录下新建 package.json,内容如下:

{
  "name": "xxxx",
  "version": "1.0.0",
  "description": "xxxx",
  "private": true,
  "author": "xxx <xxx@163.com>",
  "homepage": "http://www.tdkjbj.com",
  "main": "electron-main.js",
  "build": {
    "appId": "xxx",
    "productName": "xxx.xxx",
    "artifactName": "${productName}.${version}.${ext}",
    "copyright": "Copyright © 2019 tdkjbj.com",
    "asar": true,
    "directories": {
      "output": "build-apps",
      "buildResources": "./"
    },
    "electronVersion": "7.1.4",
    "files": [
      "!static/js/*.map",
      "!static/css/*.map"
    ],
    "win": {
      "icon": "icons/icon.png",
      "target": [
        "nsis"
      ]
    },
    "nsis": {
      "allowToChangeInstallationDirectory": true,
      "oneClick": false,
      "menuCategory": true,
      "allowElevation": false
    },
    "linux": {
      "icon": "icons/",
      "category": "Utility",
      "target": [{
        "target": "pacman"
      }]
    },
    "mac": {
      "icon": "icons/icon.png",
      "type": "development",
      "category": "public.app-category.developer-tools",
      "target": [
        "dmg"
      ]
    }
  }
}

这里,将 xxx 改为你实际的信息即可,productName 是你软件的名称,比如 QQ、chrome 等。

6、在 electron 下新建 win-state.js,内容如下:

const { app } = require('electron');
const path = require('path');
const fs = require('fs');

const winState = {
  // {x, y, width, height}
  getLastState() {
    let data = false;

    try {
      data = fs.readFileSync(this.getStateFile());
    }
    catch (err) {}

    return this.parseJson(data);
  },

  watchClose(win) {
    win.on('close', () => {
      const winState = this.getWinState(win);

      if (!winState) {
        return;
      }

      this.saveStateToStorage(winState);
    });
  },

  getWinState(win) {
    try {
      const winBounds = win.getBounds();

      return {
        x: winBounds.x,
        y: winBounds.y,
        width: winBounds.width,
        height: winBounds.height,
      }
    }
    catch (err) {
      return false;
    }
  },

  saveStateToStorage(winState) {
    fs.writeFile(this.getStateFile(), JSON.stringify(winState), (err) => {});
  },

  getStateFile() {
    const userPath = app.getPath('userData');
    const fileName = 'ardm-win-state.json';

    return path.join(userPath, fileName);
  },

  parseJson(str) {
    let json = false;

    try {
      json = JSON.parse(str);
    }
    catch(err) {}

    return json;
  },
};

module.exports = winState;

7、打包,打包命令如下:

npm install
npm run pack:prepare
npm run pack:linux

但是,Linux 只能打包 Linux,windows 只能打包 windows,mac 只能打包 mac,你也可以使用 wine ,这样子 windows 可在 mac 或 Linux 下打包,wine 可以跑在 docker 里,这样子 Linux 可以在任意平台打包。

8、使用 docker 打包:

docker run --rm -ti \
 --env-file <(env | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS_TAG|TRAVIS|TRAVIS_REPO_|TRAVIS_BUILD_|TRAVIS_BRANCH|TRAVIS_PULL_REQUEST_|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
 --env ELECTRON_CACHE="/root/.cache/electron" \
 --env ELECTRON_BUILDER_CACHE="/root/.cache/electron-builder" \
 -v ${PWD}:/project \
 -v ${PWD##*/}-node-modules:/project/node_modules \
 -v ~/.cache/electron:/root/.cache/electron \
 -v ~/.cache/electron-builder:/root/.cache/electron-builder \
 electronuserland/builder:wine
npm install
npm run pack:prepare
npm run pack:linux
npm run pack:win

以上命令分别是安装依赖,编译 vue 文件,编译 Linux 平台软件 和 编译 windows 平台软件。你可以修改 electron 目录下的 package.json,以增加支持的 Linux 软件包格式,比如:

"linux": {
  "icon": "icons/",
  "category": "Utility",
  "target": [{
    "target": "pacman"
  },{
    "target": "deb"
  },{
    "target": "rpm"
  }]
},

这将同时打包出 deb、rpm、pacman 格式的软件,你还可以继续添加,Linux 平台支持的格式有:AppImage, snap, deb, rpm, freebsd, pacman, p5p, apk, 7z, zip, tar.xz, tar.lz, tar.gz, tar.bz2, dir. 但一般包含 deb、rpm、pacman、AppImage、snap 就足够了。

本博客若无特殊说明则由 full-stack-trip 原创发布
转载请点名出处:全栈之旅 > electron 快速打包 vue 项目
本文地址:https://www.kpromise.top/package-vue-project-with-electron/

发表评论

电子邮件地址不会被公开。 必填项已用*标注