This commit is contained in:
2023-06-29 11:55:02 +08:00
commit 36e95249b1
1236 changed files with 464197 additions and 0 deletions

View File

@@ -0,0 +1,250 @@
## Electron Quick Start
```
# 克隆这仓库
$ git clone https://github.com/electron/electron-quick-start
# 进入仓库
$ cd electron-quick-start
# 安装依赖库
$ npm install
# 运行应用
$ npm start
```
## 使用IPC进行GUI与原生APP进行通讯
在main.js里添加下面的代码从通道订阅消息
```
var ipc = require('ipc');
ipc.on('close-main-window', function () {
app.quit();
});
```
引入ipc模块后通过通道订阅消息就变得很简单on()方法设置订阅的通道名,定义回调函数。
渲染进程要通过通道发送消息将下面代码加入index.js
```
var ipc = require('ipc');
var closeEl = document.querySelector('.close');
closeEl.addEventListener('click', function () {
ipc.send('close-main-window');
});
```
同样我们引入ipc模块给关闭按钮的元素绑定一个click事件。当点击关闭按钮时通过「close-main-window」通道的send()方法发送消息。
## 全局快捷键
```
var globalShortcut = require('global-shortcut');
app.on('ready', function() {
... // existing code from earlier
globalShortcut.register('ctrl+shift+1', function () {
mainWindow.webContents.send('global-shortcut', 0);
});
globalShortcut.register('ctrl+shift+2', function () {
mainWindow.webContents.send('global-shortcut', 1);
});
});
```
```
ipc.on('global-shortcut', function (arg) {
var event = new MouseEvent('click');
soundButtons[arg].dispatchEvent(event);
});
```
## 保存用户配置
使用nconf模块
```
npm install --save nconf
```
```
var nconf = require('nconf').file({file: getUserHome() + '/sound-machine-config.json'});
function saveSettings(settingKey, settingValue) {
nconf.set(settingKey, settingValue);
nconf.save();
}
function readSettings(settingKey) {
nconf.load();
return nconf.get(settingKey);
}
function getUserHome() {
return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'];
}
module.exports = {
saveSettings: saveSettings,
readSettings: readSettings
};
```
## 系统托盘
```
var remote = require('remote');
var Tray = remote.require('tray');
var Menu = remote.require('menu');
var path = require('path');
var trayIcon = null;
if (process.platform === 'darwin') {
trayIcon = new Tray(path.join(__dirname, 'img/tray-iconTemplate.png'));
}
else {
trayIcon = new Tray(path.join(__dirname, 'img/tray-icon-alt.png'));
}
var trayMenuTemplate = [
{
label: 'Sound machine',
enabled: false
},
{
label: 'Settings',
click: function () {
ipc.send('open-settings-window');
}
},
{
label: 'Quit',
click: function () {
ipc.send('close-main-window');
}
}
];
var trayMenu = Menu.buildFromTemplate(trayMenuTemplate);
trayIcon.setContextMenu(trayMenu);
```
## 打包应用
>摘自https://www.jianshu.com/p/f134878af30f
安装electron-package
```
npm install electron-package --save-dev
```
添加scrip命令 ,用于打包electron app。
```
"scripts": {
"start": "electron ."
"build": "electron-packager . hello_electron --platform=darwin --arch=x64 --ignore=node_modules/electron-*",
},
```
**electron-packager命令格式**
```
electron-packager 项目目录 app名称 --platform=平台 --arch=架构 --ignore=要忽略的目录或文件
arch
ia32 x64 armv7l all
plateform
linux win32 darwin mas all
OS X (also known as darwin)
Mac App Store (also known as mas)
```
执行命令npm run build,将得到如下结果
### electron-builder与electron-packager的区别
使用electron-builder打包应用是安装包方式而不想electron-packager打包之后直接是一个可文件夹交给所有的文件暴露出来。由electron-builder打出的包更为轻量并且可以打包出不暴露源码的setup安装程序
## 压缩源码
为避免源代码泄露,可对源码进行压缩。
**安装electron-asar**
```
npm install electron-asar --save-dev
```
**添加scrip命令 ,用于压缩源代码。**
```
"scripts": {
"start": "electron ."
"build": "electron-packager . hello_electron --platform=darwin --arch=x64 --ignore=node_modules/electron-*",
"package":"asar pack hello_electron-darwin-x64/hello_electron.app/Contents/Resources/app hello_electron-darwin-x64/hello_electron.app/Contents/Resources/app.asar"
},
```
**asar 命令格式**
asar pack <dir> <output>
执行npm run package将得到app.asar文件此时可将app文件删除。
## Electron启动node.js服务器
1.直接在index.html中启动外部的node.js服务器
2.将原生的node.js服务器代码使用module.exports = () => {}导出之后在electron的main.js中直接导入
```
app.server = require(__dirname + '/app/app')();
```
## 不迁移项目就可以打包双版本的可行方案
作者并未提供web开发的支持但是提供了非常好的web打包支持。
只要写好逻辑我们可以不用迁移项目就可以打包桌面项目和web项目。
process.env.IS_WEB是暴露的一个全局变量我们可以在渲染进程中获取项目在electron环境下返回false。否则为true。于此我们可以通过设置她的值来达到web dev的效果也可以处理不同环境的不同逻辑一些示例
![image](https://upload-images.jianshu.io/upload_images/3765249-cae045ed68c41067.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image](https://upload-images.jianshu.io/upload_images/3765249-e8f7f6ac49fdf050.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image](https://upload-images.jianshu.io/upload_images/3765249-a48751e6cf2d88e3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 打开新窗口的“最佳”做法
1.使用webview allowpopups变量控制是否拦截新弹出的窗口
下面的例子是webview允许.open/.showModalDialog/.showModelessDialog的例子
electron的index.html:重点是参数allowpopups
```
<webview id="foo" src="https://newsn.net/test.html" allowpopups style="width:100%; height:360px;"></webview>
```
原文https://newsn.net/say/electron-webview-window-open.html
2.因为是webpack配置入口只有index.html ,所以打开新窗口,一般会再配置一个入口。其实还有一种更佳的做法。
```
>>> 主进程 定义好监听事件
ipc.on('newPage', function(e) {
const modalPath = process.env.NODE_ENV === 'development'
? 'http://localhost:9080/#/newPage'
: `file://${__dirname}/index.html#newPage`
let win = new BrowserWindow({
width: 1024,
height: 724,
webPreferences: {
webSecurity: false
}
})
win.on('close', function() {
win = null
})
win.loadURL(modalPath)
})
>>> router/index.js 定义路由
// import 你的新页面 .vue 文件
{
path: '/newPage',
name: 'newPage',
component: newPage,
}
》》》配置完成 任意进程调用ipc.send('newPage') 完美解决
```
3.
```
document.getElementById("youtube").onclick = function(){
youtubeWindow = new BrowserWindow ({width: 1000, height:800})
youtubeWindow.loadURL("https://youtube.com/");
youtubeWindow.on("close", function(){
youtubeWindow = null;
})
}
document.getElementById("local-list").onclick = function(){
localListWindow = new BrowserWindow ({width: 1000, height:800})
localListWindow.loadURL(`file://${__dirname}/local-list.html`);
localListWindow.on("close", function(){
localListWindow = null;
})
}
```

View File

@@ -0,0 +1,112 @@
## 移植经验
1. 使用npm下载所有在vue-cli项目所使用的模块比如element-ui、NProgress之类的。
2. 将vue-cli项目中src目录下所有文件复制到electron-vue中对应目录。不要直接覆盖main.js因为electron-vue中有一些写法不同了对于这个文件需要自己仔细移植比如 Vue.use(require('vue-electron'))就与vue-cli不同
3. 运行npm run dev解决报错问题。(主要是因为路径失效造成的问题)
## this.$router.push()报错then() undefined
这有可能是因为你使用了动态加载路由也就是在vue-router中使用了vuex,同时夹杂了Electron-vue模板里的东西。在electron-vue模板使用的store/index.js文件中调用了vuex-electron插件而这些插件貌似会与结构起冲突把这些东西删除了就好了。
```
// import { createPersistedState, createSharedMutations } from 'vuex-electron'
// plugins: [
// createPersistedState(),
// createSharedMutations()
// ],
```
我使用的动态路由是修改自
[PanJiaChen/vue-admin-template](https://note.youdao.com/)。该作者也做了个Electron的项目同样是用Electron-vue模板所以相当值得参考。
## 跨域问题
我一开始也很疑惑为啥electron-vue中为啥没有proxytable。后来发现的确没有必要。如果有只可能是因为你的需求有问题。
vue-cli项目是将打包好的js、html等文件一起放到服务端中之后通过浏览器来浏览。服务端和前端文件是放在一起的。所以为了解决前后端分离的问题才使用跨域转发的方式来解决开发模式需要跨而生成模式就不需要。而Electron开发与生成都需要跨毕竟前端和服务端不在一起。所以也就不存在跨域问题也就不需要ProxyTable了。
我的解决方法是这样:
设置一个config.js作为全局设置文件。在里面设置一个变量用于存储本地服务器ip之后在使用axios编写get与post接口的文件将服务器ip变量加到接口地址前就可以了。例如
```
export const requestLogin = params => {return axios.post(`/login`,params).then(res => res.data); };
```
=>
```
//在config.js中base为127.0.0.1:3000
import {base} from '../config';
export const requestLogin = params => {return axios.post(`${base}/login`,params).then(res => res.data); };
```
如果需要导出web版本则可以使用process.env.IS_WEB来判断是否为web模式。
## 静态文件与启动本地服务问题
之前曾想过在electron里直接导入服务端代码来运行服务器但后来发现不行。github上代码都是通过electron(Node.js)的child_process来启动外部服务器的。
这里我使用pm2来启动这样就不需要在程序关闭时关闭服务器了。child_process 老是无法关闭服务器进程,不知道为什么)
```
let exec = require('child_process').exec;
let server = exec("pm2 start ./bin/www", {cwd: process.cwd()+'/server'});
```
静态文件可以放再electron目录下的static文件夹中(之后会打包成asar文件)不过因为本人写的app需要定时更新文件且文件类型较杂所以使用本地服务端来管理静态文件。
于是对于项目中的需要显示图片或者其他文件链接就需要加入本地服务器ip地址就像上一节那样。
## 打包后静态文件失效问题
__dirname是Electron-vue中在webpack中配置的变量对应开发模式与
产品模式时的electron静态文件目录。但如果你使用了一些webpack中没有设置的文件比如字体会出一些问题请参考这个blog
https://blog.csdn.net/aa661020/article/details/79757859
## 关于自定义协议
本人写的app使用了类似QQ的自定义协议来启动自己写的外部程序并传参在electron中为了安全的问题默认把这个功能屏蔽了。electron中应该可以使用protocol来定义协议来解决问题不过我找到了另一种方法那就是直接使用child_process的exec直接用命令行的方式来启动程序。
直接在渲染进程中xxx.vue文件
```
<script>
const exec = require('child_process').exec;
export default {
methods: {
exec(row){
//s为自定义协议的字符串
let s='xxxxxx';
let url="test://"+ s;
//test为程序名注意后面有空格第二个参数中提供程序的运行位置具体的可以参考node.js文档。
exec("test "+url, {cwd: process.cwd()+'/XXXX'});
}
}
}
</script>
```
不过需要注意在中文windows系统没有修改过默认字符集的浏览器里通过自定义协议来启动程序默认传的是gbk的字符集。而不同系统win10win7字符集是不同的。所以就需要对启动程序进行修改。
## 关于多条命令启动
因为本人写的App需要更新数据库mysql数据库所以本人使用mysql的命令进行恢复数据。
奇怪的是child_process的exec竟然不支持多条语句。所以这里我就使用了child_process的spawn。
多条命令之间使用&&间隔具体的请参照cmd指南还有别的间隔符比如| &
```
let cmd='cd /d C:/Program Files/MySQL/MySQL Server 5.7/bin && mysql -uXXXXX -pXXXXX abcde </managersystem_user.sql && mysql -uXXXXX -pXXXXX abcde </abcde_xxxx.sql';
cmd+=" && mysql -uXXXXX -pXXXXX abcde < /abcde_routines.sql";
let child = spawn(cmd, {
shell: true
});
//这里还可以输入新的命令与显示cmd返回内容具体的请参考node.js文档
child.on('exit', ()=> {
});
```
## 关于启动参数
```
//在主进程中
global.sharedObject = {prop1: process.argv}
```
```
//渲染进程中
var remote = require('electron').remote,
arguments = remote.getGlobal('sharedObject').prop1;
console.log(arguments);
```
## 最后推荐一下苏南大叔的blog
里面有关electron的文章很不错
https://newsn.net

View File

@@ -0,0 +1,61 @@
## 修改electron-packager代码
首先确认electron-packager安装位置全局或者局部之后进入`node_modules\electron-packager\`路径。使用VSCode搜索`packageForPlatformAndArch`。代码如下:
```c#
packageForPlatformAndArch (downloadOpts) {
return download.downloadElectronZip(downloadOpts)
.then(zipPath => {
// Create delegated options object with specific platform and arch, for output directory naming
const comboOpts = Object.assign({}, this.opts, {
arch: downloadOpts.arch,
platform: downloadOpts.platform,
electronVersion: downloadOpts.version
})
if (!this.useTempDir) {
return this.createApp(comboOpts, zipPath)
}
if (common.isPlatformMac(comboOpts.platform)) {
/* istanbul ignore else */
if (this.canCreateSymlinks === undefined) {
return this.testSymlink(comboOpts, zipPath)
} else if (!this.canCreateSymlinks) {
return this.skipHostPlatformSansSymlinkSupport(comboOpts)
}
}
return this.checkOverwrite(comboOpts, zipPath)
})
}
```
添加逻辑:
```
let zipFile="electron-v11.2.1-win32-x64.zip";
console.log(__dirname);
let HasFile=fs.existsSync(zipFile);
if(HasFile)
{
const comboOpts = Object.assign({}, this.opts, {
arch: downloadOpts.arch,
platform: downloadOpts.platform,
electronVersion: downloadOpts.version
})
if (!this.useTempDir) {
return this.createApp(comboOpts, zipFile)
}
if (common.isPlatformMac(comboOpts.platform)) {
/* istanbul ignore else */
if (this.canCreateSymlinks === undefined) {
return this.testSymlink(comboOpts, zipFile)
} else if (!this.canCreateSymlinks) {
return this.skipHostPlatformSansSymlinkSupport(comboOpts)
}
}
return this.checkOverwrite(comboOpts, zipFile)
}
```
其中执行路径即为项目根目录直接将zip放在项目目录中即可。

View File

@@ -0,0 +1,18 @@
## H5 PPT
https://revealjs.com/
http://imakewebthings.com/deck.js/
https://github.com/briancavalier/slides?spm=a2c6h.12873639.0.0.2c404409ftv46I
https://github.com/LeaVerou/inspire.js?spm=a2c6h.12873639.0.0.2c404409ftv46I
https://github.com/impress/impress.js/
VUE PPT插件
https://github.com/faveeo/eagle.js
感觉revealjs的功能较多但好像无法直接移植进入VUE。impressJS适合做商业演示inspireJS适合比较简单的演示。
## Node.js生成pptx
https://www.npmjs.com/package/ppt-template
https://www.npmjs.com/package/nodejs-pptx
https://www.npmjs.com/package/pptxgenjs
pptxgenjs用的人最多。

View File

@@ -0,0 +1,11 @@
## word文档生成可以使用
- docx:https://www.npmjs.com/package/docx
## word模板替换
- generate-docx:https://github.com/telemark/generate-docx
- carbone:https://github.com/carboneio/carbone
- docxtemplater:https://www.npmjs.com/package/docxtemplater
- docxtemplater-image-module-free:https://www.npmjs.com/package/docxtemplater-image-module-free
## 库
FileSaver使用案例https://jsfiddle.net/dolanmiu/onadx1gu/

View File

@@ -0,0 +1,168 @@
# 以下摘自官方文档
## Escaping query values
**Caution** These methods of escaping values only works when the
[NO_BACKSLASH_ESCAPES](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_backslash_escapes)
SQL mode is disabled (which is the default state for MySQL servers).
In order to avoid SQL Injection attacks, you should always escape any user
provided data before using it inside a SQL query. You can do so using the
`mysql.escape()`, `connection.escape()` or `pool.escape()` methods:
```js
var userId = 'some user provided value';
var sql = 'SELECT * FROM users WHERE id = ' + connection.escape(userId);
connection.query(sql, function (error, results, fields) {
if (error) throw error;
// ...
});
```
Alternatively, you can use `?` characters as placeholders for values you would
like to have escaped like this:
```js
connection.query('SELECT * FROM users WHERE id = ?', [userId], function (error, results, fields) {
if (error) throw error;
// ...
});
```
Multiple placeholders are mapped to values in the same order as passed. For example,
in the following query `foo` equals `a`, `bar` equals `b`, `baz` equals `c`, and
`id` will be `userId`:
```js
connection.query('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?', ['a', 'b', 'c', userId], function (error, results, fields) {
if (error) throw error;
// ...
});
```
This looks similar to prepared statements in MySQL, however it really just uses
the same `connection.escape()` method internally.
**Caution** This also differs from prepared statements in that all `?` are
replaced, even those contained in comments and strings.
Different value types are escaped differently, here is how:
* Numbers are left untouched
* Booleans are converted to `true` / `false`
* Date objects are converted to `'YYYY-mm-dd HH:ii:ss'` strings
* Buffers are converted to hex strings, e.g. `X'0fa5'`
* Strings are safely escaped
* Arrays are turned into list, e.g. `['a', 'b']` turns into `'a', 'b'`
* Nested arrays are turned into grouped lists (for bulk inserts), e.g. `[['a',
'b'], ['c', 'd']]` turns into `('a', 'b'), ('c', 'd')`
* Objects that have a `toSqlString` method will have `.toSqlString()` called
and the returned value is used as the raw SQL.
* Objects are turned into `key = 'val'` pairs for each enumerable property on
the object. If the property's value is a function, it is skipped; if the
property's value is an object, toString() is called on it and the returned
value is used.
* `undefined` / `null` are converted to `NULL`
* `NaN` / `Infinity` are left as-is. MySQL does not support these, and trying
to insert them as values will trigger MySQL errors until they implement
support.
This escaping allows you to do neat things like this:
```js
var post = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function (error, results, fields) {
if (error) throw error;
// Neat!
});
console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
```
And the `toSqlString` method allows you to form complex queries with functions:
```js
var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } };
var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
```
To generate objects with a `toSqlString` method, the `mysql.raw()` method can
be used. This creates an object that will be left un-touched when using in a `?`
placeholder, useful for using functions as dynamic values:
**Caution** The string provided to `mysql.raw()` will skip all escaping
functions when used, so be careful when passing in unvalidated input.
```js
var CURRENT_TIMESTAMP = mysql.raw('CURRENT_TIMESTAMP()');
var sql = mysql.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
```
If you feel the need to escape queries by yourself, you can also use the escaping
function directly:
```js
var query = "SELECT * FROM posts WHERE title=" + mysql.escape("Hello MySQL");
console.log(query); // SELECT * FROM posts WHERE title='Hello MySQL'
```
## Escaping query identifiers
If you can't trust an SQL identifier (database / table / column name) because it is
provided by a user, you should escape it with `mysql.escapeId(identifier)`,
`connection.escapeId(identifier)` or `pool.escapeId(identifier)` like this:
```js
var sorter = 'date';
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter);
connection.query(sql, function (error, results, fields) {
if (error) throw error;
// ...
});
```
It also supports adding qualified identifiers. It will escape both parts.
```js
var sorter = 'date';
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId('posts.' + sorter);
// -> SELECT * FROM posts ORDER BY `posts`.`date`
```
If you do not want to treat `.` as qualified identifiers, you can set the second
argument to `true` in order to keep the string as a literal identifier:
```js
var sorter = 'date.2';
var sql = 'SELECT * FROM posts ORDER BY ' + connection.escapeId(sorter, true);
// -> SELECT * FROM posts ORDER BY `date.2`
```
Alternatively, you can use `??` characters as placeholders for identifiers you would
like to have escaped like this:
```js
var userId = 1;
var columns = ['username', 'email'];
var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function (error, results, fields) {
if (error) throw error;
// ...
});
console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1
```
**Please note that this last character sequence is experimental and syntax might change**
When you pass an Object to `.escape()` or `.query()`, `.escapeId()` is used to avoid SQL injection in object keys.
### Preparing Queries
You can use mysql.format to prepare a query with multiple insertion points, utilizing the proper escaping for ids and values. A simple example of this follows:
```js
var sql = "SELECT * FROM ?? WHERE ?? = ?";
var inserts = ['users', 'id', userId];
sql = mysql.format(sql, inserts);
```
Following this you then have a valid, escaped query that you can then send to the database safely. This is useful if you are looking to prepare the query before actually sending it to the database. As mysql.format is exposed from SqlString.format you also have the option (but are not required) to pass in stringifyObject and timezone, allowing you provide a custom means of turning objects into strings, as well as a location-specific/timezone-aware Date.

View File

@@ -0,0 +1,105 @@
## 前言
最近因为某些原因最近决定升级VUE前端以及Electron APP工程中版本其中Node.js版本从9.9.0升级到12.19.1。因为涉及较多东西,所以写此笔记。
推荐:
- 使用nvm为了保证不会耽误旧版本项目可以使用nvm对node.js版本进行管理。你只需要使用nvm use 版本号,即可切换对应版本。
- 使用版本管理,使得每一步升级都可以回滚。
## vue前端
### vue
项目用的是vue-cli生成。vue版本号需要与vue-template-compiler版本号一致。本人值从高版本一个一个往下试错最后用了个可以跑通的版本。因为用的是npm
### node-sass
如果直接使用npm install -s node-sass可能会引发node-gyp编译而造成的错误。推荐先npm uninstall node-sass将node-sass卸载干净之后再安装。这个时候就会直接下载编译好的node-sass而不是尝试编译。
**node-sass与node.js版本也有关系**,需要注意:
NodeJS | Supported node-sass version | Node Module
---|---|---
Node 15 | 5.0+ | 88
Node 14 | 4.14+ | 83
Node 13 | 4.13+, <5.0 |79
Node 12 |4.12+ | 72
Node 11 |4.10+, <5.0 | 67
Node 10 |4.9+ | 64
Node 8 |4.5.3+, <5.0 | 57
Node <8 |<5.0 | <57
### Element-ui
当低于**2.7.0**版本的Element-ui升级时需要注意要添加对**jsx**语法的支持否则会报一下错误
```
error in ./~/.2.11.1@element-ui/packages/form/src/label-wrap.vue
Syntax Error: Unexpected token (23:14)
21 | }
22 | }
> 23 | return (<div class="el-form-item__label-wrap" style={style}>
| ^
24 | { slots }
25 | </div>);
26 | } else {
@ ./~/.2.11.1@element-ui/packages/form/src/label-wrap.vue 4:2-108
```
解决
```npm
npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-env --save-dev
```
在项目目录的.babelrc中添加对jsx插件的配置
```json
{
"plugins": ["transform-vue-jsx", ...]
}
```
## Electron
对于Electron-vue项目还是推荐创建一个Electron-vue新项目之后再将代码移植过去比较好
### require/process/module is not define
因为新版本Electron中默认没有集成node
解决修改src/main/index.js,在webPreferences中加入nodeIntegration: true
```
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000,
webPreferences: {
nodeIntegration: true,
}
})
```
### can't read property 'app' of
是因为electron10后remote模块默认是关闭的,解决修改src/main/index.js,在webPreferences中加入enableRemoteModule: true
### Element-ui的el-table不显示
解决.electron-vue/webpack.renderer.config.js中的
```
let whiteListedModules = ['vue']
```
加入elementui
```
let whiteListedModules = ['vue', 'element-ui']
```
## Node.js后端sqlite3模块
这里会需要使用node-gyp进行编译这个需要安装visual studio2017因为最高版本就支持到2017不支持2019着实蛋疼即使你给2019安装了2017 版本的构建套件win10sdk与c++ ATL库node-gyp都检测到了依然还会说版本不匹配即使指定了版本为2019)。
如果你安装完2017还是不能正常编译就可以手动指定vs版本了执行
```
npm config set msvs_version 2017
```
node-gyp的具体安装步骤可以参考https://github.com/nodejs/node-gyp#on-windows
## 清除注释
### js 双斜杠
```
//(?!.*\..*\.).*\n
```
### js 多行
```
/\*(.|\r\n|\n)*?\*/
```
### HTML
```
<!--(.|[\r\n])*?-->
```

View File

@@ -0,0 +1,54 @@
> 类似的文章还是比较多的,但或多或少有一些问题没有解决,在此我将其整合并分享给大家:
## 测试环境:
- Node.js 9.9.0
- VisualStudio 2015
- "ffi": "gavignus/node-ffi#torycl/forceset-fix",
- "ref": "1.3.5"
- "ref-array": "1.2.0"
- "ref-struct": "1.1.0"
- "ffi-napi": "^2.4.3"
## 编译失败:
当前情况下编译ffi会失败所以有两种解决方法
1. 使用新的ffi-napiapi是一样的同时支持node.js新的napi
2. 使用第三方修改过的ffi在package.json中将ffi后面的版本号改成
> "ffi": "gavignus/node-ffi#torycl/forceset-fix"
## 使用:
```
var ffi = require('ffi');
//第一个形参为dll所在位置dll文件可以不用加.dll第二个为函数信息
var libm = ffi.Library(__dirname + 'dllFile', {
//函数名
'fun': ['int', ['string', 'string']]
});
//调用
var str1="a";
var str2="b";
libm.fun(str1, str2);
```
## 使用c++里的类型
ref、ref-struct、ref-array、ref-union、ref-wchar
在npm查看使用方法在此不做赘述。
## 运行时遇到的错误
1. c++代码是可以用的但是需要把代码写在extern "C"{}里,不过这个我没有亲自试过。
2. dll文件需要放到node.js 执行目录,也就是
```
//即x:\xxxxx\xx
cd /d x:\xxxxx\xx;
node xxx.js;
```
3. dll如果有互相依赖的必须放全。不然只会出现错误126而不会像一般程序那样提示缺少xxx.dll。所以报错了可以用depends看一下dll全了没。
4. dll的需要与node.js的平台相对应比如你的node.js是64位版本的那你的dll也需要使用64位编译。
错误126检查上述1、2、3步。
## 参考:
- wiki
- https://github.com/node-ffi/node-ffi/wiki/Node-FFI-Tutorial<br>
- https://www.jianshu.com/p/914103283ea0
- https://blog.csdn.net/zhulin2609/article/details/51474676