├── dist └── .gitignore ├── src ├── renderer │ ├── assets │ │ └── logo.png │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ ├── index.js │ │ │ └── Counter.js │ ├── App.vue │ ├── main.js │ ├── pages │ │ ├── element │ │ │ ├── Table.vue │ │ │ └── Form.vue │ │ ├── terminal │ │ │ ├── Cmd.vue │ │ │ ├── Ssh.vue │ │ │ ├── SerialPort.vue │ │ │ └── Telnet.vue │ │ ├── db │ │ │ └── Nedb.vue │ │ └── excel │ │ │ └── Excel.vue │ ├── router │ │ └── index.js │ └── components │ │ ├── LandingPage │ │ └── SystemInformation.vue │ │ └── LandingPage.vue ├── index.ejs └── main │ ├── index.dev.js │ └── index.js ├── .gitignore ├── README.md ├── .electron-vue ├── dev-client.js ├── webpack.main.config.js ├── build.js ├── webpack.web.config.js ├── dev-runner.js └── webpack.renderer.config.js └── package.json /dist/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/renderer/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/q809198545/electron-vue-demo/HEAD/src/renderer/assets/logo.png -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | import modules from './modules' 5 | 6 | Vue.use(Vuex) 7 | 8 | export default new Vuex.Store({ 9 | modules, 10 | strict: process.env.NODE_ENV !== 'production' 11 | }) 12 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/renderer/store/modules/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context('.', false, /\.js$/) 7 | const modules = {} 8 | 9 | files.keys().forEach(key => { 10 | if (key === './index.js') return 11 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default 12 | }) 13 | 14 | export default modules 15 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Counter.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | main: 0 3 | } 4 | 5 | const mutations = { 6 | DECREMENT_MAIN_COUNTER (state) { 7 | state.main-- 8 | }, 9 | INCREMENT_MAIN_COUNTER (state) { 10 | state.main++ 11 | } 12 | } 13 | 14 | const actions = { 15 | someAsyncTask ({ commit }) { 16 | // do something async 17 | commit('INCREMENT_MAIN_COUNTER') 18 | } 19 | } 20 | 21 | export default { 22 | state, 23 | mutations, 24 | actions 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *.log 4 | explorations 5 | TODOs.md 6 | dist/*.gz 7 | dist/*.map 8 | dist/vue.common.min.js 9 | test/e2e/reports 10 | test/e2e/screenshots 11 | coverage 12 | RELEASE_NOTE*.md 13 | dist/*.js 14 | packages/vue-server-renderer/basic.js 15 | packages/vue-server-renderer/build.js 16 | packages/vue-server-renderer/server-plugin.js 17 | packages/vue-server-renderer/client-plugin.js 18 | packages/vue-template-compiler/build.js 19 | .vscode 20 | yarn.lock -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | 4 | import App from './App' 5 | import router from './router' 6 | import store from './store' 7 | 8 | import ElementUI from 'element-ui' 9 | import 'element-ui/lib/theme-chalk/index.css' 10 | Vue.use(ElementUI); 11 | 12 | 13 | if (!process.env.IS_WEB) Vue.use(require('vue-electron')) 14 | Vue.http = Vue.prototype.$http = axios 15 | Vue.config.productionTip = false 16 | 17 | /* eslint-disable no-new */ 18 | new Vue({ 19 | components: { App }, 20 | router, 21 | store, 22 | template: '' 23 | }).$mount('#app') 24 | -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | electron-vue-demo 6 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 7 | 8 | 11 | <% } %> 12 | 13 | 14 |
15 | 16 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # electron-vue-demo 2 | 3 | > An electron-vue project 4 | 5 | #### Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | yarn install # or npm install or cnpm install 10 | 11 | # serve with hot reload at localhost:9080 12 | npm run dev 13 | 14 | # build electron application for production 15 | npm run build 16 | 17 | ``` 18 | 19 | #### yarn install 20 | 21 | ``` bash 22 | npm install -g yarn 23 | ``` 24 | 25 | #### cnpm install 26 | 27 | ``` bash 28 | npm install -g cnpm --registry=https://registry.npm.taobao.org 29 | ``` 30 | 31 | #### doc 32 | 33 | [CSDN ](http://blog.csdn.net/q809198545) 34 | 35 | --- 36 | 37 | This project was generated with [electron-vue](https://github.com/SimulatedGREG/electron-vue) using [vue-cli](https://github.com/vuejs/vue-cli). Documentation about the original structure can be found [here](https://simulatedgreg.gitbooks.io/electron-vue/content/index.html). 38 | -------------------------------------------------------------------------------- /src/main/index.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used specifically and only for development. It installs 3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to 4 | * modify this file, but it can be used to extend your development 5 | * environment. 6 | */ 7 | 8 | /* eslint-disable */ 9 | 10 | // Set environment for development 11 | process.env.NODE_ENV = 'development' 12 | 13 | // Install `electron-debug` with `devtron` 14 | require('electron-debug')({ showDevTools: true }) 15 | 16 | // Install `vue-devtools` 17 | require('electron').app.on('ready', () => { 18 | let installExtension = require('electron-devtools-installer') 19 | installExtension.default(installExtension.VUEJS_DEVTOOLS) 20 | .then(() => {}) 21 | .catch(err => { 22 | console.log('Unable to install `vue-devtools`: \n', err) 23 | }) 24 | }) 25 | 26 | // Require `main` process to boot app 27 | require('./index') 28 | -------------------------------------------------------------------------------- /.electron-vue/dev-client.js: -------------------------------------------------------------------------------- 1 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 2 | 3 | hotClient.subscribe(event => { 4 | /** 5 | * Reload browser when HTMLWebpackPlugin emits a new index.html 6 | * 7 | * Currently disabled until jantimon/html-webpack-plugin#680 is resolved. 8 | * https://github.com/SimulatedGREG/electron-vue/issues/437 9 | * https://github.com/jantimon/html-webpack-plugin/issues/680 10 | */ 11 | // if (event.action === 'reload') { 12 | // window.location.reload() 13 | // } 14 | 15 | /** 16 | * Notify `mainWindow` when `main` process is compiling, 17 | * giving notice for an expected reload of the `electron` process 18 | */ 19 | if (event.action === 'compiling') { 20 | document.body.innerHTML += ` 21 | 34 | 35 |
36 | Compiling Main Process... 37 |
38 | ` 39 | } 40 | }) 41 | -------------------------------------------------------------------------------- /src/renderer/pages/element/Table.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 24 | 25 | -------------------------------------------------------------------------------- /src/renderer/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | const { ipcRenderer } = require('electron') 6 | 7 | let router = new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | name: 'landing-page', 12 | component: require('@/components/LandingPage').default 13 | }, 14 | { 15 | path: '/element/table', 16 | name: 'element-table', 17 | component: require('@/pages/element/Table').default 18 | }, 19 | { 20 | path: '/element/form', 21 | name: 'element-form', 22 | component: require('@/pages/element/Form').default 23 | }, 24 | { 25 | path: '/excel', 26 | name: 'excel', 27 | component: require('@/pages/excel/Excel').default 28 | }, 29 | { 30 | path: '/terminal/cmd', 31 | name: 'terminal-cmd', 32 | component: require('@/pages/terminal/Cmd').default 33 | }, 34 | { 35 | path: '/terminal/telnet', 36 | name: 'terminal-telnet', 37 | component: require('@/pages/terminal/Telnet').default 38 | }, 39 | { 40 | path: '/terminal/ssh', 41 | name: 'terminal-ssh', 42 | component: require('@/pages/terminal/Ssh').default 43 | }, 44 | { 45 | path: '/terminal/serialPort', 46 | name: 'terminal-serialPort', 47 | component: require('@/pages/terminal/SerialPort').default 48 | }, 49 | { 50 | path: '/db/nedb', 51 | name: 'db-nedb', 52 | component: require('@/pages/db/Nedb').default 53 | }, 54 | { 55 | path: '*', 56 | redirect: '/' 57 | } 58 | ] 59 | }) 60 | 61 | ipcRenderer.on('href', (event, arg) => { 62 | if (arg) { 63 | router.push({ name: arg }); 64 | } 65 | }); 66 | 67 | export default router; -------------------------------------------------------------------------------- /.electron-vue/webpack.main.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'main' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 | 11 | let mainConfig = { 12 | entry: { 13 | main: path.join(__dirname, '../src/main/index.js') 14 | }, 15 | externals: [ 16 | ...Object.keys(dependencies || {}) 17 | ], 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.js$/, 22 | use: 'babel-loader', 23 | exclude: /node_modules/ 24 | }, 25 | { 26 | test: /\.node$/, 27 | use: 'node-loader' 28 | } 29 | ] 30 | }, 31 | node: { 32 | __dirname: process.env.NODE_ENV !== 'production', 33 | __filename: process.env.NODE_ENV !== 'production' 34 | }, 35 | output: { 36 | filename: '[name].js', 37 | libraryTarget: 'commonjs2', 38 | path: path.join(__dirname, '../dist/electron') 39 | }, 40 | plugins: [ 41 | new webpack.NoEmitOnErrorsPlugin() 42 | ], 43 | resolve: { 44 | extensions: ['.js', '.json', '.node'] 45 | }, 46 | target: 'electron-main' 47 | } 48 | 49 | /** 50 | * Adjust mainConfig for development settings 51 | */ 52 | if (process.env.NODE_ENV !== 'production') { 53 | mainConfig.plugins.push( 54 | new webpack.DefinePlugin({ 55 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 56 | }) 57 | ) 58 | } 59 | 60 | /** 61 | * Adjust mainConfig for production settings 62 | */ 63 | if (process.env.NODE_ENV === 'production') { 64 | mainConfig.plugins.push( 65 | new BabiliWebpackPlugin(), 66 | new webpack.DefinePlugin({ 67 | 'process.env.NODE_ENV': '"production"' 68 | }) 69 | ) 70 | } 71 | 72 | module.exports = mainConfig 73 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage/SystemInformation.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 47 | 48 | 74 | -------------------------------------------------------------------------------- /src/renderer/pages/terminal/Cmd.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/renderer/pages/terminal/Ssh.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/renderer/pages/terminal/SerialPort.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/renderer/pages/terminal/Telnet.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /src/renderer/pages/db/Nedb.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | -------------------------------------------------------------------------------- /src/renderer/pages/element/Form.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | -------------------------------------------------------------------------------- /src/renderer/pages/excel/Excel.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 45 | 46 | 129 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-vue-demo", 3 | "version": "1.0.0", 4 | "author": "hardy", 5 | "description": "An electron-vue project", 6 | "license": "https://blog.csdn.net/q809198545", 7 | "main": "./dist/electron/main.js", 8 | "scripts": { 9 | "build": "node .electron-vue/build.js && electron-builder", 10 | "build:dir": "node .electron-vue/build.js && electron-builder --dir", 11 | "build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js", 12 | "build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js", 13 | "dev": "node .electron-vue/dev-runner.js", 14 | "pack": "npm run pack:main && npm run pack:renderer", 15 | "pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js", 16 | "pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js", 17 | "postinstall": "" 18 | }, 19 | "build": { 20 | "productName": "electron-vue-demo", 21 | "appId": "com.myh.electron-vue", 22 | "directories": { 23 | "output": "build" 24 | }, 25 | "files": [ 26 | "dist/electron/**/*" 27 | ], 28 | "dmg": { 29 | "contents": [ 30 | { 31 | "x": 410, 32 | "y": 150, 33 | "type": "link", 34 | "path": "/Applications" 35 | }, 36 | { 37 | "x": 130, 38 | "y": 150, 39 | "type": "file" 40 | } 41 | ] 42 | }, 43 | "mac": { 44 | "icon": "build/icons/icon.icns" 45 | }, 46 | "win": { 47 | "icon": "build/icons/icon.ico" 48 | }, 49 | "linux": { 50 | "icon": "build/icons" 51 | } 52 | }, 53 | "dependencies": { 54 | "axios": "^0.16.1", 55 | "electron-updater": "^2.21.0", 56 | "element-ui": "^2.2.2", 57 | "lodash": "^4.17.5", 58 | "moment": "^2.21.0", 59 | "nedb": "^1.8.0", 60 | "node-cmd": "^3.0.0", 61 | "ssh2": "^0.6.0", 62 | "telnet-client": "^0.15.5", 63 | "vue": "^2.3.3", 64 | "vue-electron": "^1.0.6", 65 | "vue-router": "^2.5.3", 66 | "vuex": "^2.3.1", 67 | "xlsx": "^0.12.5" 68 | }, 69 | "devDependencies": { 70 | "babel-core": "^6.25.0", 71 | "babel-loader": "^7.1.1", 72 | "babel-plugin-transform-runtime": "^6.23.0", 73 | "babel-preset-env": "^1.6.0", 74 | "babel-preset-stage-0": "^6.24.1", 75 | "babel-register": "^6.24.1", 76 | "babili-webpack-plugin": "^0.1.2", 77 | "cfonts": "^1.1.3", 78 | "chalk": "^2.1.0", 79 | "copy-webpack-plugin": "^4.0.1", 80 | "cross-env": "^5.0.5", 81 | "css-loader": "^0.28.4", 82 | "del": "^3.0.0", 83 | "devtron": "^1.4.0", 84 | "electron": "^1.7.5", 85 | "electron-builder": "^19.19.1", 86 | "electron-debug": "^1.4.0", 87 | "electron-devtools-installer": "^2.2.0", 88 | "extract-text-webpack-plugin": "^3.0.0", 89 | "file-loader": "^0.11.2", 90 | "html-webpack-plugin": "^2.30.1", 91 | "multispinner": "^0.2.1", 92 | "node-loader": "^0.6.0", 93 | "style-loader": "^0.18.2", 94 | "url-loader": "^0.5.9", 95 | "vue-html-loader": "^1.2.4", 96 | "vue-loader": "^13.0.5", 97 | "vue-style-loader": "^3.0.1", 98 | "vue-template-compiler": "^2.4.2", 99 | "webpack": "^3.5.2", 100 | "webpack-dev-server": "^2.7.1", 101 | "webpack-hot-middleware": "^2.18.2" 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /.electron-vue/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | const { say } = require('cfonts') 6 | const chalk = require('chalk') 7 | const del = require('del') 8 | const { spawn } = require('child_process') 9 | const webpack = require('webpack') 10 | const Multispinner = require('multispinner') 11 | 12 | 13 | const mainConfig = require('./webpack.main.config') 14 | const rendererConfig = require('./webpack.renderer.config') 15 | const webConfig = require('./webpack.web.config') 16 | 17 | const doneLog = chalk.bgGreen.white(' DONE ') + ' ' 18 | const errorLog = chalk.bgRed.white(' ERROR ') + ' ' 19 | const okayLog = chalk.bgBlue.white(' OKAY ') + ' ' 20 | const isCI = process.env.CI || false 21 | 22 | if (process.env.BUILD_TARGET === 'clean') clean() 23 | else if (process.env.BUILD_TARGET === 'web') web() 24 | else build() 25 | 26 | function clean () { 27 | del.sync(['build/*', '!build/icons', '!build/icons/icon.*']) 28 | console.log(`\n${doneLog}\n`) 29 | process.exit() 30 | } 31 | 32 | function build () { 33 | greeting() 34 | 35 | del.sync(['dist/electron/*', '!.gitkeep']) 36 | 37 | const tasks = ['main', 'renderer'] 38 | const m = new Multispinner(tasks, { 39 | preText: 'building', 40 | postText: 'process' 41 | }) 42 | 43 | let results = '' 44 | 45 | m.on('success', () => { 46 | process.stdout.write('\x1B[2J\x1B[0f') 47 | console.log(`\n\n${results}`) 48 | console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`) 49 | process.exit() 50 | }) 51 | 52 | pack(mainConfig).then(result => { 53 | results += result + '\n\n' 54 | m.success('main') 55 | }).catch(err => { 56 | m.error('main') 57 | console.log(`\n ${errorLog}failed to build main process`) 58 | console.error(`\n${err}\n`) 59 | process.exit(1) 60 | }) 61 | 62 | pack(rendererConfig).then(result => { 63 | results += result + '\n\n' 64 | m.success('renderer') 65 | }).catch(err => { 66 | m.error('renderer') 67 | console.log(`\n ${errorLog}failed to build renderer process`) 68 | console.error(`\n${err}\n`) 69 | process.exit(1) 70 | }) 71 | } 72 | 73 | function pack (config) { 74 | return new Promise((resolve, reject) => { 75 | webpack(config, (err, stats) => { 76 | if (err) reject(err.stack || err) 77 | else if (stats.hasErrors()) { 78 | let err = '' 79 | 80 | stats.toString({ 81 | chunks: false, 82 | colors: true 83 | }) 84 | .split(/\r?\n/) 85 | .forEach(line => { 86 | err += ` ${line}\n` 87 | }) 88 | 89 | reject(err) 90 | } else { 91 | resolve(stats.toString({ 92 | chunks: false, 93 | colors: true 94 | })) 95 | } 96 | }) 97 | }) 98 | } 99 | 100 | function web () { 101 | del.sync(['dist/web/*', '!.gitkeep']) 102 | webpack(webConfig, (err, stats) => { 103 | if (err || stats.hasErrors()) console.log(err) 104 | 105 | console.log(stats.toString({ 106 | chunks: false, 107 | colors: true 108 | })) 109 | 110 | process.exit() 111 | }) 112 | } 113 | 114 | function greeting () { 115 | const cols = process.stdout.columns 116 | let text = '' 117 | 118 | if (cols > 85) text = 'lets-build' 119 | else if (cols > 60) text = 'lets-|build' 120 | else text = false 121 | 122 | if (text && !isCI) { 123 | say(text, { 124 | colors: ['yellow'], 125 | font: 'simple3d', 126 | space: false 127 | }) 128 | } else console.log(chalk.yellow.bold('\n lets-build')) 129 | console.log() 130 | } 131 | -------------------------------------------------------------------------------- /.electron-vue/webpack.web.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'web' 4 | 5 | const path = require('path') 6 | const webpack = require('webpack') 7 | 8 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 9 | const CopyWebpackPlugin = require('copy-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const HtmlWebpackPlugin = require('html-webpack-plugin') 12 | 13 | let webConfig = { 14 | devtool: '#cheap-module-eval-source-map', 15 | entry: { 16 | web: path.join(__dirname, '../src/renderer/main.js') 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.css$/, 22 | use: ExtractTextPlugin.extract({ 23 | fallback: 'style-loader', 24 | use: 'css-loader' 25 | }) 26 | }, 27 | { 28 | test: /\.html$/, 29 | use: 'vue-html-loader' 30 | }, 31 | { 32 | test: /\.js$/, 33 | use: 'babel-loader', 34 | include: [ path.resolve(__dirname, '../src/renderer') ], 35 | exclude: /node_modules/ 36 | }, 37 | { 38 | test: /\.vue$/, 39 | use: { 40 | loader: 'vue-loader', 41 | options: { 42 | extractCSS: true, 43 | loaders: { 44 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 45 | scss: 'vue-style-loader!css-loader!sass-loader' 46 | } 47 | } 48 | } 49 | }, 50 | { 51 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 52 | use: { 53 | loader: 'url-loader', 54 | query: { 55 | limit: 10000, 56 | name: 'imgs/[name].[ext]' 57 | } 58 | } 59 | }, 60 | { 61 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 62 | use: { 63 | loader: 'url-loader', 64 | query: { 65 | limit: 10000, 66 | name: 'fonts/[name].[ext]' 67 | } 68 | } 69 | } 70 | ] 71 | }, 72 | plugins: [ 73 | new ExtractTextPlugin('styles.css'), 74 | new HtmlWebpackPlugin({ 75 | filename: 'index.html', 76 | template: path.resolve(__dirname, '../src/index.ejs'), 77 | minify: { 78 | collapseWhitespace: true, 79 | removeAttributeQuotes: true, 80 | removeComments: true 81 | }, 82 | nodeModules: false 83 | }), 84 | new webpack.DefinePlugin({ 85 | 'process.env.IS_WEB': 'true' 86 | }), 87 | new webpack.HotModuleReplacementPlugin(), 88 | new webpack.NoEmitOnErrorsPlugin() 89 | ], 90 | output: { 91 | filename: '[name].js', 92 | path: path.join(__dirname, '../dist/web') 93 | }, 94 | resolve: { 95 | alias: { 96 | '@': path.join(__dirname, '../src/renderer'), 97 | 'vue$': 'vue/dist/vue.esm.js' 98 | }, 99 | extensions: ['.js', '.vue', '.json', '.css'] 100 | }, 101 | target: 'web' 102 | } 103 | 104 | /** 105 | * Adjust webConfig for production settings 106 | */ 107 | if (process.env.NODE_ENV === 'production') { 108 | webConfig.devtool = '' 109 | 110 | webConfig.plugins.push( 111 | new BabiliWebpackPlugin(), 112 | new CopyWebpackPlugin([ 113 | { 114 | from: path.join(__dirname, '../static'), 115 | to: path.join(__dirname, '../dist/web/static'), 116 | ignore: ['.*'] 117 | } 118 | ]), 119 | new webpack.DefinePlugin({ 120 | 'process.env.NODE_ENV': '"production"' 121 | }), 122 | new webpack.LoaderOptionsPlugin({ 123 | minimize: true 124 | }) 125 | ) 126 | } 127 | 128 | module.exports = webConfig 129 | -------------------------------------------------------------------------------- /.electron-vue/dev-runner.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const chalk = require('chalk') 4 | const electron = require('electron') 5 | const path = require('path') 6 | const { say } = require('cfonts') 7 | const { spawn } = require('child_process') 8 | const webpack = require('webpack') 9 | const WebpackDevServer = require('webpack-dev-server') 10 | const webpackHotMiddleware = require('webpack-hot-middleware') 11 | 12 | const mainConfig = require('./webpack.main.config') 13 | const rendererConfig = require('./webpack.renderer.config') 14 | 15 | let electronProcess = null 16 | let manualRestart = false 17 | let hotMiddleware 18 | 19 | function logStats (proc, data) { 20 | let log = '' 21 | 22 | log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`) 23 | log += '\n\n' 24 | 25 | if (typeof data === 'object') { 26 | data.toString({ 27 | colors: true, 28 | chunks: false 29 | }).split(/\r?\n/).forEach(line => { 30 | log += ' ' + line + '\n' 31 | }) 32 | } else { 33 | log += ` ${data}\n` 34 | } 35 | 36 | log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n' 37 | 38 | console.log(log) 39 | } 40 | 41 | function startRenderer () { 42 | return new Promise((resolve, reject) => { 43 | rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer) 44 | 45 | const compiler = webpack(rendererConfig) 46 | hotMiddleware = webpackHotMiddleware(compiler, { 47 | log: false, 48 | heartbeat: 2500 49 | }) 50 | 51 | compiler.plugin('compilation', compilation => { 52 | compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => { 53 | hotMiddleware.publish({ action: 'reload' }) 54 | cb() 55 | }) 56 | }) 57 | 58 | compiler.plugin('done', stats => { 59 | logStats('Renderer', stats) 60 | }) 61 | 62 | const server = new WebpackDevServer( 63 | compiler, 64 | { 65 | contentBase: path.join(__dirname, '../'), 66 | quiet: true, 67 | before (app, ctx) { 68 | app.use(hotMiddleware) 69 | ctx.middleware.waitUntilValid(() => { 70 | resolve() 71 | }) 72 | } 73 | } 74 | ) 75 | 76 | server.listen(9080) 77 | }) 78 | } 79 | 80 | function startMain () { 81 | return new Promise((resolve, reject) => { 82 | mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main) 83 | 84 | const compiler = webpack(mainConfig) 85 | 86 | compiler.plugin('watch-run', (compilation, done) => { 87 | logStats('Main', chalk.white.bold('compiling...')) 88 | hotMiddleware.publish({ action: 'compiling' }) 89 | done() 90 | }) 91 | 92 | compiler.watch({}, (err, stats) => { 93 | if (err) { 94 | console.log(err) 95 | return 96 | } 97 | 98 | logStats('Main', stats) 99 | 100 | if (electronProcess && electronProcess.kill) { 101 | manualRestart = true 102 | process.kill(electronProcess.pid) 103 | electronProcess = null 104 | startElectron() 105 | 106 | setTimeout(() => { 107 | manualRestart = false 108 | }, 5000) 109 | } 110 | 111 | resolve() 112 | }) 113 | }) 114 | } 115 | 116 | function startElectron () { 117 | electronProcess = spawn(electron, ['--inspect=5858', path.join(__dirname, '../dist/electron/main.js')]) 118 | 119 | electronProcess.stdout.on('data', data => { 120 | electronLog(data, 'blue') 121 | }) 122 | electronProcess.stderr.on('data', data => { 123 | electronLog(data, 'red') 124 | }) 125 | 126 | electronProcess.on('close', () => { 127 | if (!manualRestart) process.exit() 128 | }) 129 | } 130 | 131 | function electronLog (data, color) { 132 | let log = '' 133 | data = data.toString().split(/\r?\n/) 134 | data.forEach(line => { 135 | log += ` ${line}\n` 136 | }) 137 | if (/[0-9A-z]+/.test(log)) { 138 | console.log( 139 | chalk[color].bold('┏ Electron -------------------') + 140 | '\n\n' + 141 | log + 142 | chalk[color].bold('┗ ----------------------------') + 143 | '\n' 144 | ) 145 | } 146 | } 147 | 148 | function greeting () { 149 | const cols = process.stdout.columns 150 | let text = '' 151 | 152 | if (cols > 104) text = 'electron-vue' 153 | else if (cols > 76) text = 'electron-|vue' 154 | else text = false 155 | 156 | if (text) { 157 | say(text, { 158 | colors: ['yellow'], 159 | font: 'simple3d', 160 | space: false 161 | }) 162 | } else console.log(chalk.yellow.bold('\n electron-vue')) 163 | console.log(chalk.blue(' getting ready...') + '\n') 164 | } 165 | 166 | function init () { 167 | greeting() 168 | 169 | Promise.all([startRenderer(), startMain()]) 170 | .then(() => { 171 | startElectron() 172 | }) 173 | .catch(err => { 174 | console.error(err) 175 | }) 176 | } 177 | 178 | init() 179 | -------------------------------------------------------------------------------- /.electron-vue/webpack.renderer.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'renderer' 4 | 5 | const path = require('path') 6 | const { 7 | dependencies 8 | } = require('../package.json') 9 | const webpack = require('webpack') 10 | 11 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 12 | const CopyWebpackPlugin = require('copy-webpack-plugin') 13 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 14 | const HtmlWebpackPlugin = require('html-webpack-plugin') 15 | 16 | /** 17 | * List of node_modules to include in webpack bundle 18 | * 19 | * Required for specific packages like Vue UI libraries 20 | * that provide pure *.vue files that need compiling 21 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals 22 | */ 23 | let whiteListedModules = ['vue'] 24 | 25 | let rendererConfig = { 26 | devtool: '#cheap-module-eval-source-map', 27 | entry: { 28 | renderer: path.join(__dirname, '../src/renderer/main.js') 29 | }, 30 | externals: [ 31 | ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)) 32 | ], 33 | module: { 34 | rules: [{ 35 | test: /\.css$/, 36 | use: ExtractTextPlugin.extract({ 37 | fallback: 'style-loader', 38 | use: 'css-loader' 39 | }) 40 | }, 41 | { 42 | test: /\.html$/, 43 | use: 'vue-html-loader' 44 | }, 45 | { 46 | test: /\.js$/, 47 | use: 'babel-loader', 48 | exclude: /node_modules/ 49 | }, 50 | { 51 | test: /\.node$/, 52 | use: 'node-loader' 53 | }, 54 | { 55 | test: /\.vue$/, 56 | use: { 57 | loader: 'vue-loader', 58 | options: { 59 | extractCSS: process.env.NODE_ENV === 'production', 60 | loaders: { 61 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 62 | scss: 'vue-style-loader!css-loader!sass-loader' 63 | } 64 | } 65 | } 66 | }, 67 | { 68 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 69 | use: { 70 | loader: 'url-loader', 71 | query: { 72 | limit: 10000, 73 | name: 'imgs/[name]--[folder].[ext]' 74 | } 75 | } 76 | }, 77 | { 78 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 79 | loader: 'url-loader', 80 | options: { 81 | limit: 10000, 82 | name: 'media/[name]--[folder].[ext]' 83 | } 84 | }, 85 | { 86 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 87 | use: { 88 | loader: 'url-loader', 89 | query: { 90 | limit: 10000, 91 | name: 'fonts/[name]--[folder].[ext]' 92 | } 93 | } 94 | } 95 | ] 96 | }, 97 | node: { 98 | __dirname: process.env.NODE_ENV !== 'production', 99 | __filename: process.env.NODE_ENV !== 'production' 100 | }, 101 | plugins: [ 102 | new ExtractTextPlugin('styles.css'), 103 | new HtmlWebpackPlugin({ 104 | filename: 'index.html', 105 | template: path.resolve(__dirname, '../src/index.ejs'), 106 | minify: { 107 | collapseWhitespace: true, 108 | removeAttributeQuotes: true, 109 | removeComments: true 110 | }, 111 | // nodeModules: process.env.NODE_ENV !== 'production' 112 | // ? path.resolve(__dirname, '../node_modules') 113 | // : false 114 | nodeModules: path.resolve(__dirname, '../node_modules') 115 | }), 116 | new webpack.HotModuleReplacementPlugin(), 117 | new webpack.NoEmitOnErrorsPlugin() 118 | ], 119 | output: { 120 | filename: '[name].js', 121 | libraryTarget: 'commonjs2', 122 | path: path.join(__dirname, '../dist/electron') 123 | }, 124 | resolve: { 125 | alias: { 126 | '@': path.join(__dirname, '../src/renderer'), 127 | 'vue$': 'vue/dist/vue.esm.js' 128 | }, 129 | extensions: ['.js', '.vue', '.json', '.css', '.node'] 130 | }, 131 | target: 'electron-renderer' 132 | } 133 | 134 | /** 135 | * Adjust rendererConfig for development settings 136 | */ 137 | if (process.env.NODE_ENV !== 'production') { 138 | rendererConfig.plugins.push( 139 | new webpack.DefinePlugin({ 140 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 141 | }) 142 | ) 143 | } 144 | 145 | /** 146 | * Adjust rendererConfig for production settings 147 | */ 148 | if (process.env.NODE_ENV === 'production') { 149 | rendererConfig.devtool = '' 150 | 151 | rendererConfig.plugins.push( 152 | new BabiliWebpackPlugin(), 153 | new CopyWebpackPlugin([{ 154 | from: path.join(__dirname, '../static'), 155 | to: path.join(__dirname, '../dist/electron/static'), 156 | ignore: ['.*'] 157 | }]), 158 | new webpack.DefinePlugin({ 159 | 'process.env.NODE_ENV': '"production"' 160 | }), 161 | new webpack.LoaderOptionsPlugin({ 162 | minimize: true 163 | }) 164 | ) 165 | } 166 | 167 | module.exports = rendererConfig -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | app, 3 | BrowserWindow, 4 | Menu, 5 | ipcMain, 6 | shell, 7 | dialog 8 | } from 'electron' 9 | import { 10 | autoUpdater 11 | } from "electron-updater" 12 | var config = require('../../package.json'); 13 | autoUpdater.autoDownload = false; //默认true,禁止自动更新 14 | var downloading = false; 15 | 16 | /** 17 | * Set `__static` path to static files in production 18 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html 19 | */ 20 | if (process.env.NODE_ENV !== 'development') { 21 | global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') 22 | } 23 | 24 | let mainWindow 25 | const winURL = process.env.NODE_ENV === 'development' ? 26 | `http://localhost:9080` : 27 | `file://${__dirname}/index.html` 28 | 29 | function createWindow() { 30 | /** 31 | * Initial window options 32 | */ 33 | mainWindow = new BrowserWindow({ 34 | height: 563, 35 | useContentSize: true, 36 | width: 1000 37 | }) 38 | 39 | mainWindow.loadURL(winURL) 40 | 41 | mainWindow.on('closed', () => { 42 | mainWindow = null 43 | }) 44 | } 45 | 46 | app.on('ready', createWindow) 47 | 48 | app.on('window-all-closed', () => { 49 | if (process.platform !== 'darwin') { 50 | app.quit() 51 | } 52 | }) 53 | 54 | app.on('activate', () => { 55 | if (mainWindow === null) { 56 | createWindow() 57 | } 58 | }) 59 | 60 | const template = [{ 61 | label: 'landing-page', 62 | click() { 63 | mainWindow.webContents.send('href', 'landing-page'); 64 | } 65 | }, { 66 | label: 'element ui', 67 | submenu: [{ 68 | label: 'Table 表格', 69 | click() { 70 | mainWindow.webContents.send('href', 'element-table'); 71 | } 72 | }, 73 | { 74 | label: 'Form 表单', 75 | click() { 76 | mainWindow.webContents.send('href', 'element-form'); 77 | } 78 | }, 79 | { 80 | label: '更多组件', 81 | click() { 82 | shell.openExternal('http://element-cn.eleme.io/#/zh-CN/component/'); 83 | } 84 | } 85 | ] 86 | }, 87 | { 88 | label: 'Excel', 89 | click() { 90 | mainWindow.webContents.send('href', 'excel'); 91 | } 92 | }, 93 | { 94 | label: '终端', 95 | submenu: [{ 96 | label: 'cmd', 97 | click() { 98 | mainWindow.webContents.send('href', 'terminal-cmd'); 99 | } 100 | }, 101 | { 102 | label: 'telnet', 103 | click() { 104 | mainWindow.webContents.send('href', 'terminal-telnet'); 105 | } 106 | }, 107 | { 108 | label: 'ssh', 109 | click() { 110 | mainWindow.webContents.send('href', 'terminal-ssh'); 111 | } 112 | }, 113 | { 114 | label: '串口', 115 | click() { 116 | mainWindow.webContents.send('href', 'terminal-serialPort'); 117 | } 118 | } 119 | ] 120 | }, 121 | { 122 | label: '存储', 123 | submenu: [{ 124 | label: '本地存储', 125 | click() {} 126 | }, 127 | { 128 | label: '数据库nedb', 129 | click() {} 130 | } 131 | ] 132 | }, 133 | { 134 | label: '调试', 135 | submenu: [{ 136 | label: '刷新', 137 | role: 'reload' 138 | }, 139 | { 140 | label: '全屏', 141 | role: 'togglefullscreen' 142 | }, 143 | { 144 | label: '用户数据', 145 | click() { 146 | shell.showItemInFolder(app.getPath('userData')); 147 | } 148 | }, 149 | { 150 | label: '开发者工具', 151 | role: 'toggledevtools' 152 | } 153 | ] 154 | }, 155 | { 156 | label: '帮助', 157 | submenu: [{ 158 | label: '检查更新', 159 | click() { 160 | if (!downloading && process.env.NODE_ENV !== 'development') { 161 | autoUpdater.checkForUpdates(); 162 | } 163 | } 164 | }, 165 | { 166 | label: '关于', 167 | click() { 168 | let message = ' 作者:' + config.author + '\n CSDN:' + config.license + '\n 版本:' + app.getVersion(); 169 | dialog.showMessageBox({ 170 | type: 'info', 171 | title: config.description, 172 | message: message 173 | }) 174 | } 175 | } 176 | ] 177 | } 178 | ]; 179 | 180 | const menu = Menu.buildFromTemplate(template); 181 | Menu.setApplicationMenu(menu); 182 | 183 | // 检查更新 184 | function updateHandle() { 185 | // 监听检查更新出错事件 186 | autoUpdater.on('error', function (error) { 187 | sendUpdateMessage('检查更新出错'); 188 | }); 189 | // 监听正在检查更新事件 190 | autoUpdater.on('checking-for-update', function () { 191 | //sendUpdateMessage('正在检查更新……'); 192 | }); 193 | // 监听不需要更新事件 194 | autoUpdater.on('update-not-available', function (info) { 195 | sendUpdateMessage('已经是最新版本' + info.version); 196 | }); 197 | // 监听需要更新事件 198 | autoUpdater.on('update-available', function (info) { 199 | mainWindow.webContents.send('updateAvailable', '

检测到新版本' + info.version + ',需要升级?

' + info.releaseNotes); 200 | }); 201 | // 监听下载进度事件 202 | autoUpdater.on('download-progress', function (progressObj) { 203 | downloading = true; 204 | mainWindow.webContents.send('downloadProgress', progressObj); 205 | }) 206 | //监听下载完成事件 207 | autoUpdater.on('update-downloaded', function (info) { 208 | downloading = false; 209 | //监听渲染线程中用户是否应用更新 210 | ipcMain.on('isUpdateNow', () => { 211 | autoUpdater.quitAndInstall(); 212 | }); 213 | mainWindow.webContents.send('isUpdateNow'); 214 | }); 215 | //监听渲染线程中用户是否同意下载 216 | ipcMain.on("isDownload", () => { 217 | autoUpdater.downloadUpdate(); 218 | }) 219 | 220 | ipcMain.on("checkForUpdate", () => { 221 | if (process.env.NODE_ENV !== 'development') { 222 | //执行自动检查更新 223 | autoUpdater.checkForUpdates(); 224 | } 225 | }) 226 | } 227 | 228 | function sendUpdateMessage(text) { 229 | mainWindow.webContents.send('message', text); 230 | } --------------------------------------------------------------------------------