伴随着
vue3
的发布,vue 全家桶又添新成成员 ——vite
脚手架工具;相比@vue/cli
基于浏览器内置的 ES module 极快的冷启动速度、基于Rollup
打包的配置更简单(确实简单);
vite
底层原理网上已有好多文章,本文主要讲使用公司的项目用的整合方案是
umi
+electron
,umi 是我用过目前最傻瓜化的框架了,你能想到的她都做了而且还是自动化的
唯一一点不大好的 umi 的构建速度较慢;
vite 冷启动速度确实让人眼前一亮,索性拿来和 electron 集成一波;算是一个技术备选方案^_^
毕竟 ****尤大出品,必是精品**** 定律嘛!
完整代码 https://github.com/caoxiemeihao/electron-vue-vite
喜欢的(づ ̄3 ̄)づ╭❤~给点个start哦~
划重点 (踩坑记录)
- import { write } from 'fs' 的这种形式会被 vite 编译成 /@modules/fs?import
- const { write } = require('fs') 这种形式就能用了
- const { ipcRenderer } = require('electron') 同理
- 虽然开发期可以用 require 避开 vite 的编译问题,但是打包时候 rollup 那边又出了问题;
- 拿 require('electron-store') 举例,在 vite.config.ts 中通过
自定义 rollup-plugin
转换成 EMS 形式即可-
const Store = require('electron-store')
>>import Store from 'electron-store'
-
- 拿 require('electron-store') 举例,在 vite.config.ts 中通过
准备材料
vue3
-
vite
vue3 脚手架 electron
-
electron-builder
electron 构建工具 -
electron-connect
主进程代码修改热重启 -
rollup
之前写过一个偏文章 Electron、webpack、react、typescript 从零开始搭积木- 一来能少装个包,vite 用的也是 rollup —— 入乡随俗
- 二来 rollup 的配置比 webpack 简单又专注于 js 的打包;只是用来打包 electron 主进程代码确实方便
-
concurrently
同时启动 vite(渲染进程)、electron(主进程) -
wait-on
用于监听 vite 启动,随后拉起 electron 启动 -
chalk
命令行文字颜色、背景色 -
ora
命令行友好提示 -
minimist
命令行参数解析 -
dotenv
解析 .env 文件
先用创建一个 vite 工程
- 官方命令: https://github.com/vitejs/vite#getting-started
yarn create vite-app
然后调整目录结构
.
├─dist 打包后的文件夹
├─screenshot
├─script
│ ├─build.js 主进程构建文件
│ └─rollup.config.js 主进程构建配置
└─src
├─main
│ └─index.ts 主进程入口文件
└─render
├─assets
├─components
├─dist vue 打包后目录
│ _assets
├─public
├─App.vue
├─index.css
├─index.html
└─main.js 渲染进程入口文件
└─.env 配置文件
主进程构建配置
script/rollup.config.js
-
@rollup/plugin-node-resolve
支持引入node_modules
模块 -
@rollup/plugin-commonjs
支持require
、module.exports
写法 -
@rollup/plugin-typescript
支持typescript
const path = require('path');
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const commonjs = require('@rollup/plugin-commonjs');
const typescript = require('@rollup/plugin-typescript');
module.exports = (env = 'production') => {
return {
input: path.join(__dirname, '../src/main/index.ts'), // 入口文件
output: {
file: path.join(__dirname, '../src/main/_.js'), // 输出目标
format: 'cjs', // CommonJs 格式
name: 'ElectronMainBundle', // 模块名称(可选)
sourcemap: true,
},
plugins: [
nodeResolve({ jsnext: true, preferBuiltins: true, browser: true }), // 支持引入 node_modules 模块
commonjs(), // 支持 CommonJs 规范
typescript(), // 支持 TypeScript
],
external: [
// 告诉 rollup 碰到下面模块时候不要去打包
'fs',
'path',
'http',
'https',
'child_process',
'os',
'electron',
],
}
};
主进程构建脚本
script/build.js
- 实现思路: 使用
wait-on
监听vite
启动,然后拉起electron
打开渲染进程加载 vue 应用 -
rollup
使用比较简单- 如果是开发模式用
rollup.watch(options)
会监听文件变化,文件改变自动重新编译 - 如果只是构建使用
rollup.rollup(options)
只会执行一次构建
- 如果是开发模式用
/**
* electron 打包
*/
const path = require('path');
const rollup = require('rollup');
const argv = require('minimist')(process.argv.slice(2));
const chalk = require('chalk');
const ora = require('ora');
const waitOn = require('wait-on');
const electron = require('electron-connect').server.create({ stopOnClose: true }); // 表示要操作主进程端(对应的还是渲染进程端;渲染进程用的 vite 热更新)
require('dotenv').config({ path: path.join(__dirname, '../.env') }); // 解析项目根目录下的 .env 文件
const options = require('./rollup.config'); // 引入 rollup 配置
const opt = options(argv.env);
const TAG = '[script/build.js]';
const spinner = ora(`${TAG} Electron build...`);
if (argv.watch) { // 开发模式 (命令行传入 --watch 标识)
waitOn({
resources: [`http://localhost:${process.env.PORT}`], // 等待 vite 服务器启动,然后拉起 electron
log: false,
}, err => {
if (err) {
console.log(err);
process.exit(1);
}
// once here, all resources are available
const watcher = rollup.watch(opt);
watcher.on('change', filename => {
const log = chalk.green(`change -- ${filename}`);
console.log(TAG, log);
});
watcher.on('event', ev => {
if (ev.code === 'END') {
// init-未启动、started-第一次启动、restarted-重新启动
electron.electronState === 'init' ? electron.start() : electron.restart();
}
});
});
} else { // 构建模式
spinner.start();
rollup.rollup(opt)
.then(build => {
spinner.stop();
console.log(TAG, chalk.green('Electron build successed.'));
build.write(opt.output);
})
.catch(error => {
spinner.stop();
console.log(`\n${TAG} ${chalk.red('构建报错')}\n`, error, '\n');
});
}
渲染进程 vite 配置
vite.config.ts
- 需要改变
vite
的构建路径,因为 vue 代码移动到了src/render
下 - 通过
.env
配置启动端口,配合主进程监听端口启动
/**
* 参考链接: https://github.com/vitejs/vite/blob/master/src/node/config.ts
*/
import { join } from 'path'
import { UserConfig } from 'vite'
import dotenv from 'dotenv'
dotenv.config({ path: join(__dirname, '.env') })
const root = join(__dirname, 'src/render')
const config: UserConfig = {
root,
port: +process.env.PORT,
base: './',
outDir: join(__dirname, 'dist/render'),
alias: {
// 别名必须以 / 开头、结尾
// '/@/': root, -- vite 内部在用,这里不能用了
// '/root/': __dirname, -- vite 内部在用,这里不能用了
'/assets/': join(__dirname, 'src/render/assets'),
'/components/': join(__dirname, 'src/render/components'),
'/lib/': join(__dirname, 'src/render/lib'),
'/utils/': join(__dirname, 'src/render/utils'),
'/views/': join(__dirname, 'src/render/views'),
},
optimizeDeps: {
// 这里不加也没事,用 require 的形式就能避开 import 被编译成 /@modules/fs?import
// allowNodeBuiltins: ['electron-is-dev', 'electron-store', 'electron']
},
rollupInputOptions: {
external: [
'crypto',
'assert',
'fs',
'util',
'os',
'events',
'child_process',
'http',
'https',
'path',
'electron',
],
plugins: [
{
name: '@rollup/plugin-cjs2esm',
transform(code, filename) {
if (filename.includes('/node_modules/')) {
return code
}
const cjsRegexp = /(const|let|var)[\n\s]+(\w+)[\n\s]*=[\n\s]*require\(["|'](.+)["|']\)/g
const res = code.match(cjsRegexp)
if (res) {
// const Store = require('electron-store') -> import Store from 'electron-store'
code = code.replace(cjsRegexp, `import $2 from '$3'`)
}
return code
},
}
],
},
rollupOutputOptions: {
format: 'commonjs',
},
}
export default config
启动脚本配置
{
"main": "src/main/_.js",
"scripts": {
"dev": "npm run dev:all",
"dev:all": "concurrently -n=vue,ele -c=green,blue \"npm run dev:vue\" \"npm run dev:ele\"",
"dev:vue": "vite",
"dev:ele": "node script/build --env=development --watch",
"build:vue": "vite build",
"build:ele": "node script/build --env=production",
"build": "npm run build:vue && npm run build:ele && electron-builder"
}
}
- main
electron
启动后会加载 main 配置的文件 - dev:all 使用
concurrently
同时启动dev:vue
、dev:ele
- dev:ele
electron
开发模式脚本,通过传入--watch
表示 rollup 监听主进程变化自动编译 - build 使用
electron-builder
打包
启动一下试试
$ yarn dev
yarn run v1.22.4
$ npm run dev:all
> [email protected] dev:all D:\github\electron-vue-vite
> concurrently -n=vue,ele -c=green,blue "npm run dev:vue" "npm run dev:ele"
[ele]
[ele] > [email protected] dev:ele D:\github\electron-vue-vite
[ele] > node script/build --env=development --watch
[ele]
[vue]
[vue] > [email protected] dev:vue D:\github\electron-vue-vite
[vue] > vite
[vue]
[vue] vite v1.0.0-rc.4
[vue]
[vue] Dev server running at:
[vue] > Network: http://192.168.1.9:3344/
[vue] > Network: http://192.168.119.1:3344/
[vue] > Network: http://10.0.60.32:3344/
[vue] > Local: http://localhost:3344/
[vue]
[ele] [2020-08-17T08:57:11.850Z] [electron-connect] [server] started electron process: 1488
[ele] [2020-08-17T08:57:11.851Z] [electron-connect] [server] server created and listening on 30080
[ele]
尾巴
- 2019 款 13 寸 mac-pro 启动速度 4秒 左右
- 奔腾 G4560 台机 CUP 神舟笔记本启动速度 6 秒左右
- 毋庸置疑 vite 的方案比起 @vue/cli、umi、create-react-app 这类基于 webpack 的脚手架启动这块的优势大的多滴多
- 技术总是飞快的迭代、进步,目的都是解决一些已经存在、或即将到来的问题;继续治疗、学习起来、加油哇~