1.用脚手架搭建框架
参考vue-cli2的webpack模板骨架搭建的electron和Vue结合。electron-vue是vue-cli和electron结合的项目,比单独使用vue构建起的electron项目要方便很多.(需要使用node 7或者更高的版本)官方推荐yarn作为包的管理器,能更好的处理依赖关系,并使用yarn clean 帮助减少最后的文件构建。我们需要检查的第一项是 npm 的版本,并确保它是最新的。这个可以使用 npm-windows-upgrade
来完成。如果你使用 yarn
,则可以跳过此项检查。
# 安装 vue-cli 和 脚手架样板代码
npm install -g vue-cli
vue init simulatedgreg/electron-vue my-project
# 安装依赖并运行你的程序
cd my-project
yarn # 或者 npm install
yarn run dev # 或者 npm run dev
2. 完成配置
(1).在配置文件下增加muti-page.config.js
const glob = require('glob');
const path = require('path');
const PAGE_PATH = path.resolve(__dirname, '../src/renderer');
const HtmlWebpackPlugin = require('html-webpack-plugin');
exports.entries = function () {
/*用于匹配 pages 下一级文件夹中的 index.js 文件 */
var entryFiles = glob.sync(PAGE_PATH + '/*/main.js')
var map = {}
entryFiles.forEach((filePath) => {
/* 下述两句代码用于取出 pages 下一级文件夹的名称 */
var entryPath = path.dirname(filePath)
var filename = entryPath.substring(entryPath.lastIndexOf('\/') + 1)
/* 生成对应的键值对 */
map[filename] = filePath
})
return map
}
exports.htmlPlugin = function () {
let entryHtml = glob.sync(PAGE_PATH + '/*/index.ejs')
let arr = []
entryHtml.forEach((filePath) => {
var entryPath = path.dirname(filePath)
var filename = entryPath.substring(entryPath.lastIndexOf('\/') + 1)
let conf = {
template: filePath,
filename: filename + `/index.html`,
chunks: ['manifest', 'vendor', filename],
inject: true,
nodeModules: path.resolve(__dirname, '../node_modules')
}
if (process.env.NODE_ENV === 'production') {
let productionConfig = {
minify: {
removeComments: true, // 移除注释
collapseWhitespace: true, // 删除空白符和换行符
removeAttributeQuotes: true // 移除属性引号
},
chunksSortMode: 'dependency' // 对引入的chunk模块进行排序
}
conf = {...conf, ...productionConfig} //合并基础配置和生产环境专属配置
}
arr.push(new HtmlWebpackPlugin(conf))
})
return arr
}
(2)在.electron-vue文件夹下的 webpack.renderer.config.js修改,修改后如下:
'use strict'
process.env.BABEL_ENV = 'renderer'
const path = require('path')
const { dependencies } = require('../package.json')
const webpack = require('webpack')
const BabiliWebpackPlugin = require('babili-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const {entries, htmlPlugin} = require('./muti-page.config')
/**
* List of node_modules to include in webpack bundle
*
* Required for specific packages like Vue UI libraries
* that provide pure *.vue files that need compiling
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
*/
let whiteListedModules = ['vue']
console.log()
let rendererConfig = {
devtool: '#cheap-module-eval-source-map',
// entry: {
// renderer: path.join(__dirname, '../src/renderer/main.js')
// },
entry: entries,
externals: [
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
],
module: {
rules: [
// {
// test: /\.(js|vue)$/,
// enforce: 'pre',
// exclude: /node_modules/,
// use: {
// loader: 'eslint-loader',
// options: {
// formatter: require('eslint-friendly-formatter')
// }
// }
// },
{
test: /\.scss$/,
use: ['vue-style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.sass$/,
use: ['vue-style-loader', 'css-loader', 'sass-loader?indentedSyntax']
},
{
test: /\.less$/,
use: ['vue-style-loader', 'css-loader', 'less-loader']
},
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
},
{
test: /\.html$/,
use: 'vue-html-loader'
},
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.node$/,
use: 'node-loader'
},
{
test: /\.vue$/,
use: {
loader: 'vue-loader',
options: {
extractCSS: process.env.NODE_ENV === 'production',
loaders: {
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
scss: 'vue-style-loader!css-loader!sass-loader',
less: 'vue-style-loader!css-loader!less-loader'
}
}
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'imgs/[name]--[folder].[ext]',
fallback: 'file-loader',
outputPath: './',
publicPath: '../'
}
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'media/[name]--[folder].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: {
loader: 'url-loader',
query: {
limit: 10000,
name: 'fonts/[name]--[folder].[ext]'
}
}
}
]
},
node: {
__dirname: process.env.NODE_ENV !== 'production',
__filename: process.env.NODE_ENV !== 'production'
},
plugins: [
new VueLoaderPlugin(),
new webpack.ProvidePlugin({
$:'jquery',
jQuery: 'jquery'
}),
new MiniCssExtractPlugin({filename: 'styles.css'}),
// new HtmlWebpackPlugin({
// filename: 'index.html',
// template: path.resolve(__dirname, '../src/index.ejs'),
// minify: {
// collapseWhitespace: true,
// removeAttributeQuotes: true,
// removeComments: true
// },
// nodeModules: process.env.NODE_ENV !== 'production'
// ? path.resolve(__dirname, '../node_modules')
// : false
// }),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
// 注释原来的HtmlWebpackPlugin插件代码,在数组后添加.concat(htmlPlugin())
].concat(htmlPlugin()),
output: {
// filename: '[name].js',修改filename的[name].js 为[name]/index.js,1、是为了将js文件和html文件归类在一起;2、[name].js时html访问的是绝对路径
filename: '[name]/index.js',
libraryTarget: 'commonjs2',
path: path.join(__dirname, '../dist/electron')
},
resolve: {
alias: {
'@': path.join(__dirname, '../src/renderer'),
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['.js', '.vue', '.json', '.css', '.node']
},
target: 'electron-renderer'
}
/**
* Adjust rendererConfig for development settings
*/
if (process.env.NODE_ENV !== 'production') {
rendererConfig.plugins.push(
new webpack.DefinePlugin({
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
})
)
}
/**
* Adjust rendererConfig for production settings
*/
if (process.env.NODE_ENV === 'production') {
rendererConfig.devtool = ''
rendererConfig.plugins.push(
new BabiliWebpackPlugin(),
new CopyWebpackPlugin([
{
from: path.join(__dirname, '../static'),
to: path.join(__dirname, '../dist/electron/static'),
ignore: ['.*']
}
]),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
)
}
module.exports = rendererConfig
(3)在src文件下增加渲染进程窗口的配置newPage.js
import { BrowserWindow, ipcMain, screen } from 'electron';
let win = null;
const winURL = process.env.NODE_ENV === 'development' ? 'http://localhost:9080/newPage' : `file://${__dirname}/newPage/index.html`;
function createNewPageWindow() {
const size = screen.getPrimaryDisplay().workAreaSize; // 获取显示器的宽高
// const winSize = win.getSize(); // 获取窗口宽高
win = new BrowserWindow({
width: size.width,
height: size.height,
minWidth: 500,
minHeight: 130,
type: 'toolbar', // 创建的窗口类型为工具栏窗口
frame: true, // 要创建无边框窗口
movable: true, // 窗口是否可以移动
show: true, // 先不让窗口显示
webPreferences: {
devTools: true, // 关闭调试工具
webSecurity: true
},
useContentSize: true
});
// 设置窗口的位置 注意x轴要桌面的宽度 - 窗口的宽度
win.loadURL(winURL);
// win.setPosition((size.width - winSize[0]) / 2, 350);
// 监听渲染完成
if (process.env.NODE_ENV === 'development') {
win.webContents.on('did-frame-finish-load', () => {
win.webContents.once('devtools-opened', () => {
// win.focus();
});
win.webContents.openDevTools();
});
}
win.once('ready-to-show', () => {
win.show();
});
// 监听窗口关闭
win.on('close', () => {
win = null;
});
global.newPage = {
id: win.id
};
}
/**
* 监听创建新窗口
*/
ipcMain.on('showNewPageWindow', () => {
if (win) {
if (win.isVisible()) {
createNewPageWindow();
} else {
win.showInactive();
}
} else {
createNewPageWindow();
}
});
/**
* 监听隐藏新窗口
*/
ipcMain.on('hideNewPageWindow', () => {
if (win) {
win.hide();
}
});
(4)在主进程界面引入newPage.js
import { app, BrowserWindow } from 'electron' // eslint-disable-line
/**
* Set `__static` path to static files in production
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
*/
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') // eslint-disable-line
}
let mainWindow;
const winURL = process.env.NODE_ENV === 'development'
? 'http://localhost:9080/main'
: `file://${__dirname}/main/index.html`;
function createWindow() {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000,
webPreferences: {
webSecurity: false,
devTools: true
},
show: false,
title: 'vue-electron多界面',
autoHideMenuBar: true,
alwaysOnTop: true
// backgroundColor: '#2e2c29'
});
mainWindow.loadURL(winURL);
mainWindow.once('ready-to-show', () => {
mainWindow.maximize(); // 最大化
// mainWindow.show()
});
mainWindow.on('closed', () => {
mainWindow = null;
if (process.platform !== 'darwin') {
app.quit();
}
});
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.on('did-frame-finish-load', () => {
mainWindow.webContents.once('devtools-opened', () => {
// mainWindow.focus();
});
mainWindow.webContents.openDevTools();
});
}
// 引入newPage.js,负责悬浮窗口内主进程和渲染进程之间的通信
require('./newPage');
global.mainWindow = {
id: mainWindow.id
};
}
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
/**
* Auto Updater
*
* Uncomment the following code below and install `electron-updater` to
* support auto updating. Code Signing with a valid certificate is required.
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
*/
/*
import { autoUpdater } from 'electron-updater'
autoUpdater.on('update-downloaded', () => {
autoUpdater.quitAndInstall()
})
app.on('ready', () => {
if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
*/
参考自:https://blog.csdn.net/weixin_41855143/article/details/89408218