├── .gitignore ├── README.md ├── meta.js └── template ├── .gitignore ├── README.md ├── app ├── electron.js ├── icons │ ├── icon.bmp │ ├── icon.html │ ├── icon.icns │ ├── icon.ico │ └── icon.png ├── index.ejs ├── package.json ├── shell │ ├── VS2015-Init.reg │ └── powershell.reg ├── src │ ├── App.vue │ ├── components │ │ ├── mainPage.vue │ │ └── pages │ │ │ ├── assets │ │ │ ├── icons │ │ │ │ └── ic_play.svg │ │ │ └── style │ │ │ │ └── main-style.scss │ │ │ ├── fonts │ │ │ ├── font.html │ │ │ ├── icomoon.eot │ │ │ ├── icomoon.svg │ │ │ ├── icomoon.ttf │ │ │ └── icomoon.woff │ │ │ ├── helloPage.vue │ │ │ └── mixins │ │ │ └── locale.js │ ├── locale │ │ ├── format.js │ │ ├── index.js │ │ └── lang │ │ │ ├── de.js │ │ │ ├── en.js │ │ │ ├── pt.js │ │ │ └── zh-CN.js │ ├── main.js │ ├── routes.js │ ├── sections │ │ ├── forkJs.js │ │ └── helloJs.js │ └── vuex │ │ └── store.js └── update.js ├── config.js ├── package.json ├── tasks ├── install.js ├── mac │ ├── background.png │ └── installer.js ├── package.js ├── runner.js ├── util.js └── win │ ├── installer.js │ ├── issConfig.json │ └── issTemplate.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | npm-debug.log.* 4 | 5 | .DS_Store 6 | .idea 7 | thumbs.db 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | > 一个基于 webpack 的 electron 代码模板 4 | 5 | * 包含支持 vue 框架示例 6 | * 使用 webpack 打包 vue 框架文件. 7 | * 包含编译 native addons 示例 8 | * 编译采用 tasks/install.js 中执行命令行方式解决, postinstall 使用 npm i --build-from-source 参数的添加是为了解决 amazonaws 被墙从而导致 node 文件无法下载, npm 超时问题. 9 | * 包含打包 native addons 示例 10 | * webpack 的 node-loader 模块, 在代码中将 node 文件识别为绝对路径, 无法将含有 native addons 的工程正确打包为可执行程序. 本例将 app/node_modules 也打包进 app.asar 中, 并将 require 代码写在 index.ejs 中 head 代码块中以此来解决打包问题. 11 | * 包含使用 fork 函数的示例 12 | * webpack 不识别 fork 函数, 进而无法对 fork 的文件进行打包, 本例采用多目标打包配置, 解决 fork 文件打包问题. 13 | * 包含一个多国语模块 14 | * 在 app/src/locale/lang 目录下可以添加任意语言对应翻译, vue 文件中包含示例. 15 | * 包含多平台文件打包示例 16 | * win 17 | * 打包生成程序为 exe 安装文件. 18 | * 依赖 [inno setup](http://www.jrsoftware.org/isinfo.php). 19 | * mac 20 | * 打包生成程序为 dmg 安装文件. 21 | * 打包生成程序为 zip 升级文件. 22 | * 包含多平台程序升级示例 23 | * electron 自带 autoUpdater 采用 Squirrel 框架, 不太友好, 故重构了一个较为简单的升级模块. 24 | * win 25 | * 生成一个 exe 安装包, 主程序请求升级并下载该安装包, 退出后执行 'update_v1.0.1.exe /silent /mergetasks=runapp,!desktopicon,!startmenuicon', 完成升级过程. 26 | * mac 27 | * 主程序请求升级并下载解压升级程序, 将解压文件通过 bash shell 直接覆盖原程序, 完成升级过程. 28 | * 包含两种调试模式 29 | * developmentHot 模式适合前期阶段, 支持热更新, 快速开发. 30 | * developmentPack 模式适合打包前测试阶段, 模拟打包之前的程序结构, 更快定位打包后可能出现的问题. 31 | 32 | ## Installation 33 | 34 | * node 35 | * npm 36 | * vue-cli 37 | * npm i vue-cli -g 38 | 39 | 40 | ## Build Setup 41 | 42 | ``` bash 43 | # init project 44 | vue init llwslc/electron-webpack my-project 45 | 46 | # install dependencies 47 | cd my-project 48 | npm i 49 | 50 | # run your app 51 | npm run dev 52 | ``` 53 | -------------------------------------------------------------------------------- /meta.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | prompts: { 5 | name: { 6 | type: 'editor', 7 | message: 'Application Name' 8 | }, 9 | description: { 10 | type: 'editor', 11 | message: 'Project Description', 12 | default: 'An electron-webpack project' 13 | }, 14 | companyname: { 15 | type: 'editor', 16 | message: 'Company Name', 17 | }, 18 | rebuild: { 19 | type: 'confirm', 20 | message: 'Use Native Addons (rebuild flag)?', 21 | default: true 22 | }, 23 | fork: { 24 | type: 'confirm', 25 | message: 'Use child_process.fork (fork flag)?', 26 | default: true 27 | }, 28 | update: { 29 | type: 'confirm', 30 | message: 'Use update framework (update flag)?', 31 | default: true 32 | }, 33 | installer: { 34 | type: 'confirm', 35 | message: 'Make installer (installer flag)?', 36 | default: true 37 | }, 38 | }, 39 | filters: { 40 | 'tasks/install.js': 'rebuild', 41 | 'app/src/sections/forkJs.js': 'fork', 42 | 'app/update.js': 'update', 43 | 'tasks/mac/*': 'installer', 44 | 'tasks/win/*': 'installer', 45 | }, 46 | completeMessage: `--- 47 | 48 | All set. More configurations can be made at \x1b[33m{{destDirName}}/config.js\x1b[0m. 49 | 50 | Next steps: 51 | 1. 52 | \x1B[32mcd {{destDirName}}\x1b[0m 53 | 2. 54 | \x1B[32mnpm i\x1b[0m 55 | 3. 56 | If \x1B[1mrebuild\x1b[0m flag is true. Need to be modified at \x1b[33m{{destDirName}}/tasks/install.js\x1b[0m. 57 | If \x1B[1mfork\x1b[0m flag is true. Need to be modified at \x1b[33m{{destDirName}}/app/src/sections/forkJs.js\x1b[0m. 58 | If \x1B[1mupdate\x1b[0m flag is true. Need to be modified at \x1b[33m{{destDirName}}/app/electron.js:57 (update.setFeedURL)\x1b[0m. 59 | If \x1B[1minstaller\x1b[0m flag is true. Need to be modified at \x1b[33m{{destDirName}}/tasks/win/vdprojConfig.json\x1b[0m. 60 | 4. 61 | \x1B[32mnpm run dev\x1b[0m` 62 | } 63 | -------------------------------------------------------------------------------- /template/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | app/dist/* 3 | packages/* 4 | 5 | node_modules 6 | npm-debug.log 7 | npm-debug.log.* 8 | 9 | .DS_Store 10 | .idea 11 | thumbs.db 12 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # {{ name }} 2 | 3 | > {{ description }} 4 | 5 | ## Installation 6 | 7 | * node 8 | * npm 9 | {{#if rebuild}} 10 | * node-gyp 11 | * npm i node-gyp -g 12 | {{/if}} 13 | 14 | ## Build Setup 15 | 16 | ``` bash 17 | # install dependencies 18 | npm install 19 | 20 | # serve with hot reload at localhost:8080 21 | npm run dev 22 | 23 | # run packed project for development 24 | npm run pack 25 | 26 | # run electron without webpack for development 27 | npm run electron 28 | 29 | # build electron app for production 30 | npm run package 31 | 32 | # just run webpack for production 33 | npm run pack:just 34 | 35 | # just run electron packager for production 36 | npm run package:just 37 | 38 | # just run inno setup for production 39 | npm run installer:just 40 | ``` 41 | -------------------------------------------------------------------------------- /template/app/electron.js: -------------------------------------------------------------------------------- 1 | 2 | const electron = require('electron'); 3 | const path = require('path'); 4 | const app = electron.app; 5 | const dialog = electron.dialog; 6 | const BrowserWindow = electron.BrowserWindow; 7 | 8 | let mainWindow; 9 | let config = {}; 10 | 11 | if (!!process.env.NODE_ENV) 12 | { 13 | // null 14 | } 15 | else 16 | { 17 | process.env.NODE_ENV = 'production'; 18 | } 19 | 20 | if (process.env.NODE_ENV === 'developmentHot') 21 | { 22 | config = require('../config'); 23 | config.url = `http://localhost:${config.port}`; 24 | } 25 | else 26 | { 27 | config.devtron = false; 28 | config.url = `file://${__dirname}/dist/index.html`; 29 | } 30 | 31 | function createWindow() 32 | { 33 | /** 34 | * Initial window options 35 | */ 36 | mainWindow = new BrowserWindow({ 37 | minHeight: 600, 38 | minWidth: 800 39 | }); 40 | 41 | mainWindow.maximize(); 42 | 43 | if (process.env.NODE_ENV.indexOf('development') !== -1) 44 | { 45 | BrowserWindow.addDevToolsExtension(path.join(__dirname, '../node_modules/devtron')); 46 | BrowserWindow.addDevToolsExtension(path.join(__dirname, '../node_modules/vue-devtools')); 47 | 48 | mainWindow.webContents.openDevTools(); 49 | } 50 | 51 | if (process.env.NODE_ENV === 'production') 52 | { 53 | {{#if update}} 54 | const UpdateObj = require('./update'); 55 | let update = new UpdateObj(); 56 | update.setFeedURL('http://localhost'); 57 | update.checkLocalUpdates(); 58 | {{/if}} 59 | if (process.argv[1] === 'debug') 60 | { 61 | process.env.DEBUG = true; 62 | } 63 | } 64 | 65 | mainWindow.loadURL(config.url); 66 | 67 | mainWindow.on('closed', function () 68 | { 69 | mainWindow = null; 70 | }); 71 | 72 | console.log('mainWindow opened'); 73 | } 74 | 75 | app.on('open-file', (e, path) => 76 | { 77 | // dialog.showErrorBox('openFile', path); 78 | }); 79 | 80 | app.once('ready', createWindow); 81 | 82 | app.on('window-all-closed', function () 83 | { 84 | app.quit(); 85 | }); 86 | 87 | app.on('activate', function () 88 | { 89 | if (mainWindow === null) 90 | { 91 | createWindow(); 92 | } 93 | }); 94 | -------------------------------------------------------------------------------- /template/app/icons/icon.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/icons/icon.bmp -------------------------------------------------------------------------------- /template/app/icons/icon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | icon 转换 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /template/app/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/icons/icon.icns -------------------------------------------------------------------------------- /template/app/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/icons/icon.ico -------------------------------------------------------------------------------- /template/app/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/icons/icon.png -------------------------------------------------------------------------------- /template/app/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 33 | 34 | 35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /template/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ name }}", 3 | "description": "{{ description }}", 4 | "version": "0.0.0", 5 | "author": "{{ author }}", 6 | "main": "electron.js", 7 | "dependencies": { 8 | "async": "^2.1.4", 9 | "jquery": "^3.1.1", 10 | "vue": "^2.1.6", 11 | "vue-router": "^2.1.1", 12 | "vuex": "^2.1.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /template/app/shell/VS2015-Init.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/shell/VS2015-Init.reg -------------------------------------------------------------------------------- /template/app/shell/powershell.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/shell/powershell.reg -------------------------------------------------------------------------------- /template/app/src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /template/app/src/components/mainPage.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /template/app/src/components/pages/assets/icons/ic_play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /template/app/src/components/pages/assets/style/main-style.scss: -------------------------------------------------------------------------------- 1 | ////////////// 2 | // reset // 3 | ////////////// 4 | 5 | * { 6 | margin: 0; 7 | padding: 0; 8 | list-style: none; 9 | } 10 | 11 | html, 12 | body { 13 | height: 100%; 14 | background-color: #fff; 15 | overflow: hidden; 16 | } 17 | 18 | /////////////// 19 | // fonts // 20 | /////////////// 21 | 22 | body { 23 | padding-left: 36px; 24 | font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif; 25 | } 26 | 27 | @font-face { 28 | font-family: 'icomoon'; 29 | src: url('fonts/icomoon.eot'); 30 | src: url('fonts/icomoon.eot#iefix') format('embedded-opentype'), 31 | url('fonts/icomoon.ttf') format('truetype'), 32 | url('fonts/icomoon.woff') format('woff'), 33 | url('fonts/icomoon.svg#icomoon') format('svg'); 34 | font-weight: normal; 35 | font-style: normal; 36 | } 37 | 38 | [class^="icon-"], [class*=" icon-"] { 39 | /* use !important to prevent issues with browser extensions that change fonts */ 40 | font-family: 'icomoon' !important; 41 | speak: none; 42 | font-style: normal; 43 | font-weight: normal; 44 | font-variant: normal; 45 | text-transform: none; 46 | line-height: 1; 47 | font-size: 18px; 48 | 49 | /* Better Font Rendering =========== */ 50 | -webkit-font-smoothing: antialiased; 51 | -moz-osx-font-smoothing: grayscale; 52 | } 53 | 54 | .icon-mplay:before { 55 | content: "\e904"; 56 | } 57 | .icon-mstop:before { 58 | content: "\e905"; 59 | } 60 | .icon-available:before { 61 | content: "\e900"; 62 | } 63 | .icon-occupied:before { 64 | content: "\e901"; 65 | } 66 | .icon-pause:before { 67 | content: "\e902"; 68 | } 69 | .icon-play:before { 70 | content: "\e903"; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /template/app/src/components/pages/fonts/font.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | svg 转 font 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /template/app/src/components/pages/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/src/components/pages/fonts/icomoon.eot -------------------------------------------------------------------------------- /template/app/src/components/pages/fonts/icomoon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /template/app/src/components/pages/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/src/components/pages/fonts/icomoon.ttf -------------------------------------------------------------------------------- /template/app/src/components/pages/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/app/src/components/pages/fonts/icomoon.woff -------------------------------------------------------------------------------- /template/app/src/components/pages/helloPage.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 53 | 54 | 57 | -------------------------------------------------------------------------------- /template/app/src/components/pages/mixins/locale.js: -------------------------------------------------------------------------------- 1 | import { t } from '../../../locale'; 2 | 3 | export default { 4 | methods: { 5 | t(...args) { 6 | return t.apply(this, args); 7 | } 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /template/app/src/locale/format.js: -------------------------------------------------------------------------------- 1 | /** 2 | * String format template 3 | * - Inspired: 4 | * https://github.com/Matt-Esch/string-template/index.js 5 | */ 6 | 7 | const RE_NARGS = /(%|)\{([0-9a-zA-Z_]+)\}/g; 8 | 9 | export default function(Vue) { 10 | const { hasOwn } = Vue.util; 11 | 12 | /** 13 | * template 14 | * 15 | * @param {String} string 16 | * @param {Array} ...args 17 | * @return {String} 18 | */ 19 | 20 | function template(string, ...args) { 21 | if (args.length === 1 && typeof args[0] === 'object') { 22 | args = args[0]; 23 | } 24 | 25 | if (!args || !args.hasOwnProperty) { 26 | args = {}; 27 | } 28 | 29 | return string.replace(RE_NARGS, (match, prefix, i, index) => { 30 | let result; 31 | 32 | if (string[index - 1] === '{' && 33 | string[index + match.length] === '}') { 34 | return i; 35 | } else { 36 | result = hasOwn(args, i) ? args[i] : null; 37 | if (result === null || result === undefined) { 38 | return ''; 39 | } 40 | 41 | return result; 42 | } 43 | }); 44 | } 45 | 46 | return template; 47 | } 48 | -------------------------------------------------------------------------------- /template/app/src/locale/index.js: -------------------------------------------------------------------------------- 1 | 2 | let lang = 'zh-CN'; 3 | 4 | import Vue from 'vue'; 5 | import Format from './format'; 6 | 7 | const format = Format(Vue); 8 | let langObj = {}; 9 | 10 | export const t = function(path, options) { 11 | const array = path.split('.'); 12 | let current = langObj; 13 | 14 | for (var i = 0, j = array.length; i < j; i++) { 15 | var property = array[i]; 16 | var value = current[property]; 17 | if (i === j - 1) return format(value, options); 18 | if (!value) return ''; 19 | current = value; 20 | } 21 | return ''; 22 | }; 23 | 24 | export const use = function(l) { 25 | lang = l || lang; 26 | langObj = require(`./lang/${lang}`).default; 27 | }; 28 | export default { use, t }; 29 | -------------------------------------------------------------------------------- /template/app/src/locale/lang/de.js: -------------------------------------------------------------------------------- 1 | export default { 2 | el: { 3 | datepicker: { 4 | now: 'Jetzt', 5 | today: 'Heute', 6 | cancel: 'Abbrechen', 7 | clear: 'Leeren', 8 | confirm: 'OK', 9 | selectDate: 'Datum wählen', 10 | selectTime: 'Uhrzeit wählen', 11 | startDate: 'Startdatum', 12 | startTime: 'Startzeit', 13 | endDate: 'Enddatum', 14 | endTime: 'Endzeit', 15 | day: 'Tag', 16 | week: 'Woche', 17 | month: 'Monat', 18 | year: 'Jahr', 19 | month1: 'Januar', 20 | month2: 'Februar', 21 | month3: 'März', 22 | month4: 'April', 23 | month5: 'Mai', 24 | month6: 'Juni', 25 | month7: 'Juli', 26 | month8: 'August', 27 | month9: 'September', 28 | month10: 'Oktober', 29 | month11: 'November', 30 | month12: 'Dezember', 31 | weeks: { 32 | sun: 'So', 33 | mon: 'Mo', 34 | tue: 'Di', 35 | wed: 'Mi', 36 | thu: 'Do', 37 | fri: 'Fr', 38 | sat: 'Sa' 39 | }, 40 | months: { 41 | jan: 'Jan', 42 | feb: 'Feb', 43 | mar: 'Mär', 44 | apr: 'Apr', 45 | may: 'Mai', 46 | jun: 'Jun', 47 | jul: 'Jul', 48 | aug: 'Aug', 49 | sep: 'Sep', 50 | oct: 'Okt', 51 | nov: 'Nov', 52 | dec: 'Dez' 53 | } 54 | }, 55 | select: { 56 | loading: 'Lädt.', 57 | noMatch: 'Nichts gefunden.', 58 | noData: 'Keine Datei', 59 | placeholder: 'Datei wählen' 60 | }, 61 | pagination: { 62 | goto: 'Gehe zu', 63 | pagesize: 'pro Seite', 64 | total: 'Gesamt {total}', 65 | pageClassifier: '' 66 | }, 67 | messagebox: { 68 | confirm: 'OK', 69 | cancel: 'Abbrechen', 70 | error: 'Fehler' 71 | }, 72 | upload: { 73 | delete: 'Löschen', 74 | preview: 'Vorschau', 75 | continue: 'Fortsetzen' 76 | }, 77 | table: { 78 | emptyText: 'Keine Daten', 79 | confirmFilter: 'Anwenden', 80 | resetFilter: 'Zurücksetzen', 81 | clearFilter: 'Alles ' 82 | }, 83 | tree: { 84 | emptyText: 'Keine Daten' 85 | } 86 | } 87 | }; 88 | -------------------------------------------------------------------------------- /template/app/src/locale/lang/en.js: -------------------------------------------------------------------------------- 1 | export default { 2 | el: { 3 | datepicker: { 4 | now: 'Now', 5 | today: 'Today', 6 | cancel: 'Cancel', 7 | clear: 'Clear', 8 | confirm: 'OK', 9 | selectDate: 'Select date', 10 | selectTime: 'Select time', 11 | startDate: 'Start Date', 12 | startTime: 'Start Time', 13 | endDate: 'End Date', 14 | endTime: 'End Time', 15 | year: '', 16 | month1: 'January', 17 | month2: 'February', 18 | month3: 'March', 19 | month4: 'April', 20 | month5: 'May', 21 | month6: 'June', 22 | month7: 'July', 23 | month8: 'August', 24 | month9: 'September', 25 | month10: 'October', 26 | month11: 'November', 27 | month12: 'December', 28 | // week: 'week', 29 | weeks: { 30 | sun: 'Sun', 31 | mon: 'Mon', 32 | tue: 'Tue', 33 | wed: 'Wed', 34 | thu: 'Thu', 35 | fri: 'Fri', 36 | sat: 'Sat' 37 | }, 38 | months: { 39 | jan: 'Jan', 40 | feb: 'Feb', 41 | mar: 'Mar', 42 | apr: 'Apr', 43 | may: 'May', 44 | jun: 'Jun', 45 | jul: 'Jul', 46 | aug: 'Aug', 47 | sep: 'Sep', 48 | oct: 'Oct', 49 | nov: 'Nov', 50 | dec: 'Dec' 51 | } 52 | }, 53 | select: { 54 | loading: 'Loading', 55 | noMatch: 'No matching data', 56 | noData: 'No data', 57 | placeholder: 'Select' 58 | }, 59 | pagination: { 60 | goto: 'Go to', 61 | pagesize: '/page', 62 | total: 'Total {total}', 63 | pageClassifier: '' 64 | }, 65 | messagebox: { 66 | title: 'Message', 67 | confirm: 'OK', 68 | cancel: 'Cancel', 69 | error: 'Illegal input' 70 | }, 71 | upload: { 72 | delete: 'Delete', 73 | preview: 'Preview', 74 | continue: 'Continue' 75 | }, 76 | table: { 77 | emptyText: 'No Data', 78 | confirmFilter: 'Confirm', 79 | resetFilter: 'Reset', 80 | clearFilter: 'All' 81 | }, 82 | tree: { 83 | emptyText: 'No Data' 84 | } 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /template/app/src/locale/lang/pt.js: -------------------------------------------------------------------------------- 1 | export default { 2 | el: { 3 | datepicker: { 4 | now: 'Agora', 5 | today: 'Hoje', 6 | cancel: 'Cancelar', 7 | clear: 'Limpar', 8 | confirm: 'Confirmar', 9 | selectDate: 'Selecione a data', 10 | selectTime: 'Selecione a hora', 11 | startDate: 'Data de inicio', 12 | startTime: 'Hora de inicio', 13 | endDate: 'Data de fim', 14 | endTime: 'Hora de fim', 15 | year: 'Ano', 16 | month1: 'Janeiro', 17 | month2: 'Fevereiro', 18 | month3: 'Março', 19 | month4: 'Abril', 20 | month5: 'Maio', 21 | month6: 'Junho', 22 | month7: 'Julho', 23 | month8: 'Agosto', 24 | month9: 'Setembro', 25 | month10: 'Outubro', 26 | month11: 'Novembro', 27 | month12: 'Dezembro', 28 | // week: 'semana', 29 | weeks: { 30 | sun: 'Dom', 31 | mon: 'Seg', 32 | tue: 'Ter', 33 | wed: 'Qua', 34 | thu: 'Qui', 35 | fri: 'Sex', 36 | sat: 'Sab' 37 | }, 38 | months: { 39 | jan: 'Jan', 40 | feb: 'Fev', 41 | mar: 'Mar', 42 | apr: 'Abr', 43 | may: 'Mai', 44 | jun: 'Jun', 45 | jul: 'Jul', 46 | aug: 'Ago', 47 | sep: 'Set', 48 | oct: 'Out', 49 | nov: 'Nov', 50 | dec: 'Dez' 51 | } 52 | }, 53 | select: { 54 | loading: 'A carregar', 55 | noMatch: 'Sem correspondência', 56 | noData: 'Sem dados', 57 | placeholder: 'Selecione' 58 | }, 59 | pagination: { 60 | goto: 'Ir para', 61 | pagesize: '/pagina', 62 | total: 'Total {total}', 63 | pageClassifier: '' 64 | }, 65 | messagebox: { 66 | confirm: 'Confirmar', 67 | cancel: 'Cancelar', 68 | error: 'Erro!' 69 | }, 70 | upload: { 71 | delete: 'Apagar', 72 | preview: 'Previsualizar', 73 | continue: 'Continuar' 74 | }, 75 | table: { 76 | emptyText: 'Sem dados', 77 | confirmFilter: 'Confirmar', 78 | resetFilter: 'Limpar', 79 | clearFilter: 'Todos' 80 | }, 81 | tree: { 82 | emptyText: 'Sem dados' 83 | } 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /template/app/src/locale/lang/zh-CN.js: -------------------------------------------------------------------------------- 1 | export default { 2 | el: { 3 | datepicker: { 4 | now: '此刻', 5 | today: '今天', 6 | cancel: '取消', 7 | clear: '清空', 8 | confirm: '确定', 9 | selectDate: '选择日期', 10 | selectTime: '选择时间', 11 | startDate: '开始日期', 12 | startTime: '开始时间', 13 | endDate: '结束日期', 14 | endTime: '结束时间', 15 | year: '年', 16 | month1: '1 月', 17 | month2: '2 月', 18 | month3: '3 月', 19 | month4: '4 月', 20 | month5: '5 月', 21 | month6: '6 月', 22 | month7: '7 月', 23 | month8: '8 月', 24 | month9: '9 月', 25 | month10: '10 月', 26 | month11: '11 月', 27 | month12: '12 月', 28 | // week: '周次', 29 | weeks: { 30 | sun: '日', 31 | mon: '一', 32 | tue: '二', 33 | wed: '三', 34 | thu: '四', 35 | fri: '五', 36 | sat: '六' 37 | }, 38 | months: { 39 | jan: '一月', 40 | feb: '二月', 41 | mar: '三月', 42 | apr: '四月', 43 | may: '五月', 44 | jun: '六月', 45 | jul: '七月', 46 | aug: '八月', 47 | sep: '九月', 48 | oct: '十月', 49 | nov: '十一月', 50 | dec: '十二月' 51 | } 52 | }, 53 | select: { 54 | loading: '加载中', 55 | noMatch: '无匹配数据', 56 | noData: '无数据', 57 | placeholder: '请选择' 58 | }, 59 | pagination: { 60 | goto: '前往', 61 | pagesize: '条/页', 62 | total: '共 {total} 条', 63 | pageClassifier: '页' 64 | }, 65 | messagebox: { 66 | title: '提示', 67 | confirm: '确定', 68 | cancel: '取消', 69 | error: '输入的数据不合法!' 70 | }, 71 | upload: { 72 | delete: '删除', 73 | preview: '查看图片', 74 | continue: '继续上传' 75 | }, 76 | table: { 77 | emptyText: '暂无数据', 78 | confirmFilter: '筛选', 79 | resetFilter: '重置', 80 | clearFilter: '全部' 81 | }, 82 | tree: { 83 | emptyText: '暂无数据' 84 | } 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /template/app/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | 4 | import App from './App'; 5 | import routes from './routes'; 6 | import Locale from './locale'; 7 | 8 | Locale.use('zh-CN'); 9 | 10 | Vue.use(Router); 11 | Vue.config.debug = true; 12 | 13 | const router = new Router({ 14 | scrollBehavior: () => ({ y: 0 }), 15 | routes 16 | }); 17 | 18 | new Vue({ 19 | router, 20 | ...App 21 | }).$mount('#app'); 22 | -------------------------------------------------------------------------------- /template/app/src/routes.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | path: '/', 4 | name: 'main-page', 5 | component: require('./components/mainPage'), 6 | }, 7 | { 8 | path: '*', 9 | redirect: '/', 10 | }, 11 | ]; 12 | -------------------------------------------------------------------------------- /template/app/src/sections/forkJs.js: -------------------------------------------------------------------------------- 1 | 2 | global.fs = require('fs'); 3 | global.path = require('path'); 4 | global.readline = require('readline'); 5 | 6 | global.async = require('async'); 7 | 8 | if (typeof __DEFINE_NATIVE_REQUIRE__ === 'undefined') 9 | { 10 | global.__non_webpack_require__ = require; 11 | } 12 | 13 | {{#if rebuild}} 14 | global.NativeAddonObj = __non_webpack_require__('NativeAddon.node'); 15 | {{/if}} 16 | 17 | process.on("message", function (msg) 18 | { 19 | process.send(true); 20 | }); 21 | 22 | -------------------------------------------------------------------------------- /template/app/src/sections/helloJs.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = { 4 | hello: 'word' 5 | } 6 | -------------------------------------------------------------------------------- /template/app/src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | // 配置 9 | config: {}, 10 | }, 11 | mutations: { 12 | init: state => { 13 | state.config = {}; 14 | }, 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /template/app/update.js: -------------------------------------------------------------------------------- 1 | 2 | const electron = require('electron'); 3 | const app = electron.app; 4 | const dialog = electron.dialog; 5 | const http = require('http'); 6 | const fs = require('fs'); 7 | const path = require('path'); 8 | const os = require('os'); 9 | const childProcess = require('child_process'); 10 | const async = require('async'); 11 | const pkgInfo = require('./package.json'); 12 | 13 | var UpdateObj = function () 14 | { 15 | var self = this; 16 | 17 | self.name = pkgInfo.name; 18 | self.version = pkgInfo.version; 19 | self.platform = os.platform(); 20 | 21 | self.feedURL = ''; 22 | self.updateURL = ''; 23 | self.updateVer = ''; 24 | self.updateMD5 = ''; 25 | self.updatePath = ''; 26 | self.updateTmpPath = ''; 27 | 28 | self.getVerNum = function (ver) 29 | { 30 | var verArr = ver.split('.'); 31 | var num = 0; 32 | num += parseInt(verArr[0]) * 1000 * 1000; 33 | num += parseInt(verArr[1]) * 1000; 34 | num += parseInt(verArr[2]); 35 | return num; 36 | }; 37 | 38 | self.cleanup = function (ver) 39 | { 40 | var needCleanup = false; 41 | var curVer = self.getVerNum(self.version); 42 | var fileVer = self.getVerNum(ver); 43 | 44 | if (fileVer <= curVer) 45 | { 46 | needCleanup = true; 47 | } 48 | 49 | return needCleanup; 50 | }; 51 | 52 | self.updateButtons = []; 53 | self.updateMessage = '发现新版本, 点击"重启升级"后即可完成升级!'; 54 | 55 | if (self.platform === 'win32') 56 | { 57 | self.updateButtons = ['重启升级', '取消']; 58 | self.updateResponse = 0; 59 | 60 | self.appDataDir = path.join(process.env.APPDATA, pkgInfo.name); 61 | } 62 | else if (self.platform === 'darwin') 63 | { 64 | self.updateButtons = ['取消', '重启升级']; 65 | self.updateResponse = 1; 66 | 67 | self.appDataDir = path.join(process.env.HOME, '/Library/Application Support', pkgInfo.name); 68 | } 69 | else 70 | { 71 | // null 72 | } 73 | 74 | if (!fs.existsSync(self.appDataDir)) 75 | { 76 | fs.mkdirSync(self.appDataDir); 77 | } 78 | 79 | var files = fs.readdirSync(self.appDataDir); 80 | files.forEach(function (file) 81 | { 82 | var filePath = path.join(self.appDataDir, file); 83 | 84 | if (/^update_v([\d.]+)\.(exe|zip)$/.test(file)) 85 | { 86 | var exeVersion = path.basename(file, path.extname(file)).split('_v')[1]; 87 | 88 | if (self.cleanup(exeVersion)) 89 | { 90 | fs.unlink(filePath, (err) => {}); 91 | } 92 | else 93 | { 94 | self.updatePath = filePath; 95 | } 96 | } 97 | 98 | if (/^temp_v([\d.]+)\.(exe|zip)$/.test(file)) 99 | { 100 | fs.unlink(filePath, (err) => {}); 101 | } 102 | }); 103 | 104 | self.setFeedURL = function (url) 105 | { 106 | self.feedURL = url; 107 | }; 108 | 109 | self.getFeedURL = function () 110 | { 111 | return self.feedURL; 112 | }; 113 | 114 | self.checkLocalUpdates = function () 115 | { 116 | if (fs.existsSync(self.updatePath)) 117 | { 118 | dialog.showMessageBox({ 119 | type: 'none', 120 | buttons: self.updateButtons, 121 | title: '发现新版本', 122 | message: self.updateMessage, 123 | }, function (response) 124 | { 125 | if (response == self.updateResponse) 126 | { 127 | self.quitAndInstall(); 128 | } 129 | }); 130 | } 131 | else 132 | { 133 | self.checkServerUpdates(); 134 | } 135 | }; 136 | 137 | self.checkServerUpdates = function () 138 | { 139 | async.waterfall([ 140 | function (cb) 141 | { 142 | var url = `${self.feedURL}/update?`; 143 | url += `platform=${self.platform}&`; 144 | url += `version=${self.version}&`; 145 | url += `app=${self.name}`; 146 | 147 | http.get(url, function (response) 148 | { 149 | var statusCode = response.statusCode; 150 | var contentType = response.headers['content-type']; 151 | 152 | if (statusCode != 200) 153 | { 154 | cb(statusCode, null); 155 | } 156 | else 157 | { 158 | if (!/^application\/json/.test(contentType)) 159 | { 160 | cb(statusCode, null); 161 | } 162 | else 163 | { 164 | response.setEncoding('utf8'); 165 | var rawData = ''; 166 | response.on('data', (chunk) => rawData += chunk); 167 | response.on('end', function () 168 | { 169 | try 170 | { 171 | var parsedData = JSON.parse(rawData); 172 | self.updateURL = parsedData.url; 173 | self.updateVer = parsedData.version; 174 | self.updateMD5 = parsedData.md5; 175 | 176 | cb(null, null); 177 | } 178 | catch (e) 179 | { 180 | cb(statusCode, null); 181 | } 182 | }); 183 | } 184 | } 185 | }).on('error', function (err) 186 | { 187 | cb(err, null); 188 | }); 189 | }, 190 | function (res, cb) 191 | { 192 | http.get(self.updateURL, function (response) 193 | { 194 | var statusCode = response.statusCode; 195 | var contentType = response.headers['content-type']; 196 | 197 | if (statusCode != 200) 198 | { 199 | cb(statusCode, null); 200 | } 201 | else 202 | { 203 | var downloadFlag = false; 204 | if (/^application\/x-msdownload/.test(contentType)) 205 | { 206 | self.updateTmpPath = path.join(self.appDataDir, `temp_v${self.updateVer}.exe`); 207 | self.updatePath = path.join(self.appDataDir, `update_v${self.updateVer}.exe`); 208 | downloadFlag = true; 209 | } 210 | else if (/^application\/zip/.test(contentType)) 211 | { 212 | self.updateTmpPath = path.join(self.appDataDir, `temp_v${self.updateVer}.zip`); 213 | self.updatePath = path.join(self.appDataDir, `update_v${self.updateVer}.zip`); 214 | downloadFlag = true; 215 | } 216 | else 217 | { 218 | cb(statusCode, null); 219 | } 220 | 221 | if (downloadFlag) 222 | { 223 | response.pipe(fs.createWriteStream(self.updateTmpPath)); 224 | 225 | response.on('end', function () 226 | { 227 | fs.renameSync(self.updateTmpPath, self.updatePath); 228 | cb(null, null); 229 | }); 230 | } 231 | } 232 | }).on('error', function (err) 233 | { 234 | cb(err, null); 235 | }); 236 | } 237 | ], (err, res) => {}); 238 | }; 239 | 240 | self.quitAndInstall = function () 241 | { 242 | var exec = childProcess.exec; 243 | if (self.platform === 'win32') 244 | { 245 | if (fs.existsSync(self.updatePath)) 246 | { 247 | exec(`start ${self.updatePath} /silent /mergetasks=runapp,!desktopicon,!startmenuicon`, {encoding: 'binary'}); 248 | app.exit(0); 249 | } 250 | else 251 | { 252 | dialog.showErrorBox('升级失败', '升级程序已损坏,请重新下载完整程序安装'); 253 | } 254 | } 255 | else if (self.platform === 'darwin') 256 | { 257 | var unzipPath = path.join(process.argv[0], '../../..'); 258 | var unzip = exec(`unzip -o '${self.updatePath}' -d '${unzipPath}'`, {encoding: 'binary'}); 259 | unzip.on('exit', function () 260 | { 261 | exec(`rm '${self.updatePath}'`); 262 | app.relaunch({args: process.argv.slice(1).concat(['--relaunch'])}); 263 | app.exit(0); 264 | }); 265 | } 266 | else 267 | { 268 | // null 269 | } 270 | }; 271 | }; 272 | 273 | 274 | module.exports = UpdateObj; 275 | -------------------------------------------------------------------------------- /template/config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | 5 | let config = { 6 | // Name of electron app 7 | // Will be used in production builds 8 | name: '{{ name }}', 9 | 10 | // webpack-dev-server port 11 | port: 8080, 12 | 13 | // electron-packager options 14 | building: { 15 | arch: 'x64', 16 | asar: true, 17 | dir: path.join(__dirname, 'app'), 18 | icon: path.join(__dirname, 'app/icons/icon'), 19 | ignore: /^\/(shell|src|index\.ejs)/, 20 | prune: false, 21 | overwrite: true, 22 | win32metadata: { 23 | {{#if companyname}} 24 | CompanyName: '{{ companyname }}', 25 | {{/if}} 26 | FileDescription: '{{ name }}', 27 | }, 28 | platform: require('os').platform(), 29 | out: path.join(__dirname, 'packages'), 30 | extendInfo: { 31 | CFBundleDocumentTypes: [ 32 | { 33 | CFBundleTypeExtensions: ['dat'] 34 | }] 35 | }, 36 | } 37 | } 38 | 39 | config.building.name = config.name 40 | 41 | module.exports = config 42 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ name }}", 3 | "description": "{{ description }}", 4 | "version": "0.0.0", 5 | "author": "llwslc ", 6 | "scripts": { 7 | {{#if rebuild}} 8 | "postinstall": "cd app && npm i --build-from-source && node ../tasks/install.js", 9 | {{else}} 10 | "postinstall": "cd app && npm i", 11 | {{/if}} 12 | "dev": "node tasks/runner.js dev", 13 | "pack": "node tasks/runner.js pack", 14 | "electron": "node tasks/runner.js electron", 15 | "package": "node tasks/package.js", 16 | "pack:just": "node tasks/package.js pack:just", 17 | {{#if installer}} 18 | "installer:just": "node tasks/package.js installer:just", 19 | {{/if}} 20 | "package:just": "node tasks/package.js package:just" 21 | }, 22 | "devDependencies": { 23 | "async": "^2.1.4", 24 | "babel-core": "^6.21.0", 25 | "babel-loader": "^6.2.10", 26 | "babel-plugin-transform-runtime": "^6.15.0", 27 | "babel-preset-es2015": "^6.18.0", 28 | "babel-preset-stage-0": "^6.16.0", 29 | "cross-env": "^3.1.3", 30 | "css-loader": "^0.26.1", 31 | "devtron": "^1.4.0", 32 | "electron": "^1.4.13", 33 | "electron-packager": "^8.4.0", 34 | "extract-text-webpack-plugin": "^2.0.0-beta.4", 35 | "file-loader": "^0.9.0", 36 | "html-webpack-plugin": "^2.24.1", 37 | "iconv-lite": "^0.4.15", 38 | {{#if installer}} 39 | "innosetup-compiler": "^5.5.9", 40 | {{/if}} 41 | "json-loader": "^0.5.4", 42 | "node-sass": "^4.1.1", 43 | "sass-loader": "^4.1.0", 44 | "style-loader": "^0.13.1", 45 | "tree-kill": "^1.1.0", 46 | "url-loader": "^0.5.7", 47 | "vue": "^2.1.6", 48 | "vue-devtools": "^2.3.1-beta1", 49 | "vue-loader": "^10.0.2", 50 | "vue-style-loader": "^1.0.0", 51 | "vue-template-compiler": "^2.1.6", 52 | "webpack": "^2.2.0", 53 | "webpack-dev-server": "^2.2.0" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /template/tasks/install.js: -------------------------------------------------------------------------------- 1 | 2 | const exec = require('child_process').exec; 3 | const async = require('async'); 4 | const util = require('./util'); 5 | 6 | var electronVersion = ``; 7 | var buildAddons = `node-gyp rebuild --target=${electronVersion} --arch=x64 --dist-url=https://atom.io/download/atom-shell`; 8 | 9 | var npmExecAsync = function (cmd, cb) 10 | { 11 | util.execAsync('npm', cmd, util.BLUE, cb); 12 | }; 13 | 14 | async.waterfall([ 15 | function (cb) 16 | { 17 | exec(`cd .. && electron -v`, (error, stdout, stderr) => 18 | { 19 | if (error) 20 | { 21 | cb(error, null); 22 | } 23 | else 24 | { 25 | electronVersion = stdout.match(/\d+.\d+.\d+/g); 26 | buildAddons = `node-gyp rebuild --target=${electronVersion[0]} --arch=x64 --dist-url=https://atom.io/download/atom-shell`; 27 | cb(null, null); 28 | } 29 | }); 30 | }, 31 | function (res, cb) 32 | { 33 | npmExecAsync(`cd node_modules/NativeAddonPackageName && ${buildAddons}`, cb); 34 | }, 35 | function (res, cb) 36 | { 37 | npmExecAsync(`cd ../../NativeAddonProjectDir && ${buildAddons}`, cb); 38 | }, 39 | function (res, cb) 40 | { 41 | util.copyAsync(`../../NativeAddonProjectDir/build/Release/NativeAddonProject.node`, `node_modules/NativeAddonProject.node`, cb); 42 | }, 43 | ], function (err, res) 44 | { 45 | if (err) 46 | { 47 | util.colFormat(err, util.RED); 48 | } 49 | else 50 | { 51 | util.colFormat(`success install`); 52 | } 53 | }); 54 | -------------------------------------------------------------------------------- /template/tasks/mac/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/llwslc/electron-webpack/93a829abd54d1026aea8a76d7a2096e69f83654f/template/tasks/mac/background.png -------------------------------------------------------------------------------- /template/tasks/mac/installer.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require('fs'); 3 | const os = require('os'); 4 | const platform = os.platform(); 5 | const arch = os.arch(); 6 | const async = require('async'); 7 | const util = require('../util'); 8 | const pkgInfo = require('../../app/package.json'); 9 | 10 | 11 | var installer = function () 12 | { 13 | var self = this; 14 | 15 | 16 | self.appFileName = `${pkgInfo.name}-${platform}-${arch}`; 17 | self.appFilePath = `./packages/${self.appFileName}`; 18 | self.appContentsPath = `${self.appFilePath}/${pkgInfo.name}.app`; 19 | self.targetName = `${self.appFileName}-v${pkgInfo.version}`; 20 | 21 | self.createDmg = function (callback) 22 | { 23 | util.colFormat('Create dmg...\n'); 24 | 25 | var rwDmgPath = `${self.appFilePath}/../rw.dmg`; 26 | var ultDmgPath = `${self.appFilePath}/../${self.targetName}.dmg`; 27 | var volumesPath = `/Volumes/${pkgInfo.name}`; 28 | 29 | var dmgExecAsync = function (cmd, cb) 30 | { 31 | util.execAsync('dmg', cmd, util.BLUE, cb); 32 | } 33 | 34 | async.waterfall([ 35 | function (cb) 36 | { 37 | dmgExecAsync(`rm -f ${self.appFilePath}/LICENSE`, cb); 38 | }, 39 | function (res, cb) 40 | { 41 | dmgExecAsync(`rm -f ${self.appFilePath}/LICENSES.chromium.html`, cb); 42 | }, 43 | function (res, cb) 44 | { 45 | dmgExecAsync(`rm -f ${self.appFilePath}/version`, cb); 46 | }, 47 | function (res, cb) 48 | { 49 | dmgExecAsync(`rm -f ${self.appFilePath}/Applications && ln -s /Applications ${self.appFilePath}/Applications`, cb); 50 | }, 51 | function (res, cb) 52 | { 53 | if (!fs.existsSync(`${self.appFilePath}/.background`)) 54 | { 55 | fs.mkdirSync(`${self.appFilePath}/.background`); 56 | } 57 | cb (null, null); 58 | }, 59 | function (res, cb) 60 | { 61 | util.copyAsync(`./tasks/mac/background.png`, `${self.appFilePath}/.background/background.png`, cb); 62 | }, 63 | function (res, cb) 64 | { 65 | util.copyAsync(`./app/icons/icon.icns`, `${self.appFilePath}/.volumeIcon.icns`, cb); 66 | }, 67 | function (res, cb) 68 | { 69 | dmgExecAsync(`rm -f ${rwDmgPath} && rm -f ${ultDmgPath}`, cb); 70 | }, 71 | function (res, cb) 72 | { 73 | dmgExecAsync(`hdiutil create -srcfolder ${self.appFilePath} -volname ${pkgInfo.name} -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW ${rwDmgPath}`, cb); 74 | }, 75 | function (res, cb) 76 | { 77 | dmgExecAsync(`(test -d ${volumesPath} && hdiutil detach ${volumesPath}) || :`, cb); 78 | }, 79 | function (res, cb) 80 | { 81 | dmgExecAsync(`hdiutil attach -readwrite -noverify -noautoopen ${rwDmgPath}`, cb); 82 | }, 83 | function (res, cb) 84 | { 85 | dmgExecAsync(`SetFile -c icnC ${volumesPath}/.volumeIcon.icns`, cb); 86 | }, 87 | function (res, cb) 88 | { 89 | dmgExecAsync(`SetFile -a C ${volumesPath}`, cb); 90 | }, 91 | function (res, cb) 92 | { 93 | var bgWidth = 550; 94 | var bgHeigth = 310; 95 | var appX = 143; 96 | var appY = 157; 97 | var dropX = 407; 98 | var dropY = 157; 99 | var iconSize = 128; 100 | var textSize = 16; 101 | 102 | var AppleScriptStr = ` 103 | tell application "Finder" 104 | tell disk "${pkgInfo.name}" 105 | 106 | open 107 | 108 | set titleHeight to 20 109 | set windowWidth to ${bgWidth} 110 | set windowHeight to ${bgHeigth} 111 | 112 | tell container window 113 | set current view to icon view 114 | set toolbar visible to false 115 | set statusbar visible to false 116 | set the bounds to {0, 0, windowWidth, (windowHeight + titleHeight)} 117 | set position of every item to {0, windowHeight * 2} 118 | set position of item "${pkgInfo.name}.app" to {${appX}, ${appY}} 119 | set position of item "Applications" to {${dropX}, ${dropY}} 120 | end tell 121 | 122 | set opts to the icon view options of container window 123 | tell opts 124 | set icon size to ${iconSize} 125 | set text size to ${textSize} 126 | set arrangement to not arranged 127 | end tell 128 | 129 | set background picture of opts to file ".background:background.png" 130 | 131 | close 132 | 133 | --give the finder some time to write the .DS_Store file 134 | delay 3 135 | 136 | set dsStore to "${volumesPath}/.DS_STORE" 137 | set waitTime to 0 138 | set ejectMe to false 139 | repeat while ejectMe is false 140 | delay 1 141 | set waitTime to waitTime + 1 142 | 143 | if (do shell script "[ -f " & dsStore & " ]; echo $?") = "0" then set ejectMe to true 144 | end repeat 145 | log "waited " & waitTime & " seconds for .DS_STORE to be created." 146 | 147 | end tell 148 | end tell`; 149 | dmgExecAsync(`osascript -e '${AppleScriptStr}'`, cb); 150 | }, 151 | function (res, cb) 152 | { 153 | dmgExecAsync(`hdiutil detach ${volumesPath}`, cb); 154 | }, 155 | function (res, cb) 156 | { 157 | dmgExecAsync(`hdiutil convert ${rwDmgPath} -format UDZO -imagekey zlib-level=9 -o ${ultDmgPath}`, cb); 158 | }, 159 | function (res, cb) 160 | { 161 | dmgExecAsync(`rm -f ${rwDmgPath}`, cb); 162 | }, 163 | ], function (err, res) 164 | { 165 | callback(err, null); 166 | }); 167 | }; 168 | 169 | self.createZip = function (callback) 170 | { 171 | util.colFormat(''); 172 | util.colFormat('Create zip...\n'); 173 | 174 | var zipFilePath = `../../${self.targetName}-update.zip`; 175 | 176 | util.execAsync(`zip`, `cd ${self.appContentsPath} && zip -ry ${zipFilePath} *`, util.YELLOW, function (err, res) 177 | { 178 | util.colFormat(''); 179 | util.logFormat('zip', 'DONE', util.YELLOW); 180 | util.colFormat(''); 181 | 182 | callback(err, null); 183 | }); 184 | }; 185 | 186 | self.create = function () 187 | { 188 | if (process.argv[2] == 'package:just') 189 | { 190 | return; 191 | } 192 | 193 | async.waterfall([ 194 | function (cb) 195 | { 196 | self.createDmg(cb); 197 | }, 198 | function (res, cb) 199 | { 200 | self.createZip(cb); 201 | }, 202 | ], function (err, res) 203 | { 204 | if (err) 205 | { 206 | util.colFormat(err, util.RED); 207 | } 208 | else 209 | { 210 | util.colFormat(`Success create mac installer`); 211 | } 212 | }); 213 | }; 214 | }; 215 | 216 | 217 | module.exports = installer; 218 | -------------------------------------------------------------------------------- /template/tasks/package.js: -------------------------------------------------------------------------------- 1 | 2 | const exec = require('child_process').exec; 3 | const os = require('os'); 4 | const platform = os.platform(); 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | const packager = require('electron-packager'); 8 | const util = require('./util'); 9 | 10 | var delDirCmd = ''; 11 | {{#if installer}} 12 | var installer = ''; 13 | {{/if}} 14 | 15 | if (platform === 'win32') 16 | { 17 | delDirCmd = 'rmdir /s/q'; 18 | {{#if installer}} 19 | installer = require('./win/installer.js'); 20 | {{/if}} 21 | } 22 | else if (platform === 'darwin') 23 | { 24 | delDirCmd = 'rm -rf'; 25 | {{#if installer}} 26 | installer = require('./mac/installer.js'); 27 | {{/if}} 28 | } 29 | else 30 | { 31 | util.colFormat('Unable to determine the current operating system...\n', util.RED); 32 | return; 33 | } 34 | 35 | /** 36 | * Delete dir 37 | */ 38 | var del = function (mPath, cb) 39 | { 40 | mPath = path.resolve(__dirname, mPath) 41 | if (fs.existsSync(mPath)) 42 | { 43 | if (!fs.statSync(mPath).isDirectory()) 44 | { 45 | util.colFormat(`${mPath} not directiry!`, util.RED); 46 | return; 47 | } 48 | } 49 | else 50 | { 51 | cb(); 52 | return; 53 | } 54 | 55 | util.colFormat(`Delete ${mPath} dir...\n`); 56 | 57 | util.execAsync(`delDir`, `${delDirCmd} ${mPath}`, util.BLUE, function (err, res) 58 | { 59 | if (!!err) 60 | { 61 | util.colFormat(`try run!`, util.RED); 62 | return; 63 | } 64 | else 65 | { 66 | cb(); 67 | } 68 | }); 69 | }; 70 | 71 | /** 72 | * Build webpack in production 73 | */ 74 | var pack = function () 75 | { 76 | del('../app/dist', function () 77 | { 78 | util.execAsync(`webpack`, `${util.rlsEnv} webpack --progress --colors --hide-modules`, util.YELLOW, (err, res) => packageApp()); 79 | }); 80 | }; 81 | 82 | /** 83 | * Use electron-packager to package electron app 84 | */ 85 | var packageApp = function () 86 | { 87 | if (process.argv[2] == 'pack:just') 88 | { 89 | return; 90 | } 91 | 92 | exec('set ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/'); 93 | 94 | del('../packages', function () 95 | { 96 | let options = require('../config').building; 97 | 98 | util.colFormat('Building electron app...\n'); 99 | packager(options, function (err, appPaths) 100 | { 101 | if (err) 102 | { 103 | util.errFormat('electron-packager', 'Error from `electron-packager` when building app...', util.BLUE); 104 | util.errFormat('electron-packager', err, util.BLUE); 105 | } 106 | else 107 | { 108 | util.colFormat(''); 109 | util.logFormat('electron-packager', 'Build successful!', util.BLUE); 110 | util.colFormat(''); 111 | {{#if installer}} 112 | if (process.argv[2] == 'package:just') 113 | { 114 | return; 115 | } 116 | 117 | new installer().create(); 118 | {{/if}} 119 | } 120 | }); 121 | }); 122 | }; 123 | 124 | if (process.argv[2] == 'pack:just') 125 | { 126 | pack(); 127 | } 128 | else if (process.argv[2] == 'package:just') 129 | { 130 | packageApp(); 131 | } 132 | {{#if installer}} 133 | else if (process.argv[2] == 'installer:just') 134 | { 135 | new installer().create(); 136 | } 137 | {{/if}} 138 | else 139 | { 140 | pack(); 141 | } 142 | -------------------------------------------------------------------------------- /template/tasks/runner.js: -------------------------------------------------------------------------------- 1 | 2 | const config = require('../config'); 3 | const exec = require('child_process').exec; 4 | const treeKill = require('tree-kill'); 5 | const util = require('./util'); 6 | 7 | let isElectronOpen = false; 8 | 9 | let children = []; 10 | 11 | var run = function (command, color, name) 12 | { 13 | let child = exec(command); 14 | 15 | child.stdout.on('data', data => 16 | { 17 | util.logFormat(name, data, color); 18 | 19 | if (/Compiled successfully/g.test(data.toString()) && !isElectronOpen) 20 | { 21 | util.colFormat(`Starting electron...\n`, util.BLUE); 22 | run(`${util.hotEnv} electron app/electron.js`, util.BLUE, 'electron'); 23 | isElectronOpen = true; 24 | } 25 | }); 26 | 27 | child.stderr.on('data', data => util.errFormat(name, data, color)); 28 | child.on('exit', code => exit(code)); 29 | 30 | children.push(child); 31 | }; 32 | 33 | var exit = function (code) 34 | { 35 | if (process.argv[2] == 'pack') 36 | { 37 | if (!isElectronOpen) 38 | { 39 | util.colFormat(`Starting electron...\n`, util.BLUE); 40 | run(`${util.packEnv} electron app/electron.js`, util.BLUE, 'electron'); 41 | isElectronOpen = true; 42 | } 43 | else 44 | { 45 | children.forEach(child => 46 | { 47 | treeKill(child.pid); 48 | }); 49 | } 50 | } 51 | else 52 | { 53 | children.forEach(child => 54 | { 55 | treeKill(child.pid); 56 | }); 57 | } 58 | }; 59 | 60 | if (process.argv[2] == 'dev') 61 | { 62 | util.colFormat(`Starting webpack-dev-server...\n`, util.YELLOW); 63 | run(`${util.hotEnv} webpack-dev-server --inline --hot --colors --port ${config.port} --content-base app/dist`, util.YELLOW, 'webpack'); 64 | } 65 | else if (process.argv[2] == 'pack') 66 | { 67 | util.colFormat(`Starting webpack...\n`, util.YELLOW); 68 | run(`${util.packEnv} webpack --progress --colors --hide-modules`, util.YELLOW, 'webpack'); 69 | } 70 | else if (process.argv[2] == 'electron') 71 | { 72 | util.colFormat(`Starting electron...\n`, util.BLUE); 73 | run(`${util.packEnv} electron app/electron.js`, util.BLUE, 'electron'); 74 | isElectronOpen = true; 75 | } 76 | else 77 | { 78 | util.colFormat(`Nothing to do...\n`, util.YELLOW); 79 | } 80 | -------------------------------------------------------------------------------- /template/tasks/util.js: -------------------------------------------------------------------------------- 1 | 2 | const exec = require('child_process').exec; 3 | const fs = require('fs'); 4 | const platform = require('os').platform(); 5 | const iconv = require('iconv-lite'); 6 | 7 | let styles = { 8 | bold : ['\x1B[1m', '\x1B[22m'], 9 | italic : ['\x1B[3m', '\x1B[23m'], 10 | underline : ['\x1B[4m', '\x1B[24m'], 11 | inverse : ['\x1B[7m', '\x1B[27m'], 12 | black : ['\x1B[30m', '\x1B[39m'], 13 | red : ['\x1B[31m', '\x1B[39m'], 14 | green : ['\x1B[32m', '\x1B[39m'], 15 | yellow : ['\x1B[33m', '\x1B[39m'], 16 | blue : ['\x1B[34m', '\x1B[39m'], 17 | magenta : ['\x1B[35m', '\x1B[39m'], 18 | cyan : ['\x1B[36m', '\x1B[39m'], 19 | white : ['\x1B[37m', '\x1B[39m'], 20 | redBG : ['\x1B[41m', '\x1B[49m'], 21 | greenBG : ['\x1B[42m', '\x1B[49m'], 22 | yellowBG : ['\x1B[43m', '\x1B[49m'], 23 | blueBG : ['\x1B[44m', '\x1B[49m'], 24 | magentaBG : ['\x1B[45m', '\x1B[49m'], 25 | cyanBG : ['\x1B[46m', '\x1B[49m'], 26 | whiteBG : ['\x1B[47m', '\x1B[49m'], 27 | grey : ['\x1B[90m', '\x1B[39m'], 28 | end : ['\x1b[0m'] 29 | }; 30 | 31 | let RED = styles.red[0]; 32 | let YELLOW = styles.yellow[0]; 33 | let BLUE = styles.blue[0]; 34 | let RED_BG = styles.redBG[0]; 35 | let END = styles.end[0]; 36 | 37 | var Encoding = 'utf8'; 38 | if (platform === 'win32') 39 | { 40 | Encoding = 'GBK'; 41 | } 42 | 43 | let hotEnv = 'cross-env NODE_ENV=developmentHot'; 44 | let packEnv = 'cross-env NODE_ENV=developmentPack'; 45 | let rlsEnv = 'cross-env NODE_ENV=production'; 46 | 47 | var repeat = function (str, times) 48 | { 49 | return (new Array(times + 1)).join(str); 50 | }; 51 | 52 | var format = function (pre, data, col) 53 | { 54 | if (!!!col) col = YELLOW; 55 | 56 | data = data.replace(/\n$/g, ''); 57 | data = data.replace(/\x08/g, ''); 58 | data = data.replace(/^\x20+/g, ''); 59 | data = data.replace(/\n/g, '\n' + repeat(' ', pre.length + 2)); 60 | // for webpack compiling log 61 | if (new RegExp("^webpack").test(pre)) 62 | { 63 | data = data.replace(/([0-9]+%)/g, '\n' + repeat(' ', pre.length + 2) + '$1'); 64 | data = data.replace(/^\n\x20+/g, ''); 65 | } 66 | 67 | var decodedBody = iconv.decode(Buffer(data, 'binary'), Encoding); 68 | 69 | return decodedBody; 70 | }; 71 | 72 | var logFormat = function (pre, data, col) 73 | { 74 | var log = format(pre, data, col); 75 | if (!!log) 76 | { 77 | console.log(`${col}${pre}${END} ${log}`); 78 | } 79 | }; 80 | 81 | var errFormat = function (pre, data, col) 82 | { 83 | var errPre = pre + ' !!!'; 84 | var log = format(errPre, data, col); 85 | if (!!log) 86 | { 87 | console.log(`${col}${pre}${END} ${RED_BG}!!!${END} ${log}`); 88 | } 89 | }; 90 | 91 | var colFormat = function (data, col) 92 | { 93 | if (!!!col) col = END; 94 | var decodedBody = iconv.decode(Buffer(data, 'binary'), Encoding); 95 | console.log(`${col}${decodedBody}${END}`); 96 | }; 97 | 98 | var execAsync = function (pre, cmd, col, cb) 99 | { 100 | let child = exec(cmd, {encoding: 'binary'}); 101 | child.stdout.on('data', data => logFormat(pre, data, col)); 102 | child.stderr.on('data', data => errFormat(pre, data, col)); 103 | child.on('exit', code => { 104 | if (code != 0) 105 | { 106 | cb(`code : ${code}\nerror cmd: ${cmd}`, null); 107 | } 108 | else 109 | { 110 | cb(null, null); 111 | } 112 | }); 113 | }; 114 | 115 | var copyAsync = function (source, target, cb) 116 | { 117 | var writer = fs.createWriteStream(target); 118 | var reader = fs.createReadStream(source); 119 | reader.pipe(writer); 120 | writer.on(`finish`, () => { 121 | colFormat(`copy ${source} to ${target} finish`); 122 | cb(null, null); 123 | }); 124 | }; 125 | 126 | 127 | module.exports = { RED, YELLOW, BLUE, logFormat, errFormat, colFormat, execAsync, copyAsync, hotEnv, packEnv, rlsEnv }; 128 | -------------------------------------------------------------------------------- /template/tasks/win/installer.js: -------------------------------------------------------------------------------- 1 | 2 | const path = require('path'); 3 | const os = require('os'); 4 | const platform = os.platform(); 5 | const arch = os.arch(); 6 | const inno = require(`innosetup-compiler`); 7 | const issTemplate = require(`./issTemplate`); 8 | const util = require(`../util`); 9 | const pkgInfo = require('../../app/package.json'); 10 | 11 | 12 | var installer = function () 13 | { 14 | var self = this; 15 | 16 | self.appFileName = `${pkgInfo.name}-${platform}-${arch}`; 17 | self.appIssPath = `.\\packages\\${self.appFileName}.iss`; 18 | 19 | self.create = function () 20 | { 21 | util.colFormat('Create iis...\n'); 22 | new issTemplate(self.appFileName, self.appIssPath); 23 | 24 | inno(self.appIssPath, {}, function (err) 25 | { 26 | if (err) 27 | { 28 | util.colFormat(err, util.RED); 29 | } 30 | else 31 | { 32 | util.colFormat(`Success create win installer`); 33 | } 34 | }); 35 | } 36 | }; 37 | 38 | 39 | module.exports = installer; 40 | -------------------------------------------------------------------------------- /template/tasks/win/issConfig.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "AppId": "00000000-0000-0000-0000-000000000000", 4 | {{#if companyname}} 5 | "AppPublisher": "{{ companyname }}", 6 | {{else}} 7 | "AppPublisher": "Github", 8 | {{/if}} 9 | "AppSupportPhone": "010-88888888", 10 | "AppPublisherURL": "http://localhost", 11 | "AppSupportURL": "http://localhost", 12 | "AppUpdatesURL": "http://localhost" 13 | } -------------------------------------------------------------------------------- /template/tasks/win/issTemplate.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require(`fs`); 3 | const pkgInfo = require('../../app/package.json'); 4 | const issConfig = require('./issConfig.json'); 5 | 6 | issConfig.AppName = pkgInfo.name; 7 | issConfig.AppVersion = pkgInfo.version; 8 | 9 | var createIssFile = function (appFileName, appIssPath) 10 | { 11 | var self = this; 12 | 13 | var OutputDir = `..\\`; 14 | var SourceDir = `.\\${appFileName}`; 15 | var setupIco = `.\\app\\icons\\icon.ico`; 16 | var setupImg = `.\\app\\icons\\icon.bmp`; 17 | 18 | var iisStr = ` 19 | [Setup] 20 | AppId=${issConfig.AppId} 21 | AppName=${issConfig.AppName} 22 | AppVersion=${issConfig.AppVersion} 23 | AppPublisher=${issConfig.AppPublisher}, Inc. 24 | AppSupportPhone=${issConfig.AppSupportPhone} 25 | AppPublisherURL=${issConfig.AppPublisherURL} 26 | AppSupportURL=${issConfig.AppSupportURL} 27 | AppUpdatesURL=${issConfig.AppUpdatesURL} 28 | DefaultDirName={pf}\\${issConfig.AppPublisher}\\${issConfig.AppName} 29 | DefaultGroupName=${issConfig.AppPublisher} 30 | OutputBaseFilename=${appFileName}-v${issConfig.AppVersion} 31 | AppMutex=${issConfig.AppName} 32 | OutputDir=${OutputDir} 33 | SourceDir=${SourceDir} 34 | Compression=lzma2 35 | SolidCompression=yes 36 | AppVerName=${issConfig.AppName} 37 | UninstallDisplayIcon={app}\\${issConfig.AppName}.exe 38 | ${fs.existsSync(setupIco) ? `SetupIconFile=..\\..\\` + setupIco : ``} 39 | ${fs.existsSync(setupImg) ? `WizardSmallImageFile=..\\..\\` + setupImg : ``} 40 | DisableProgramGroupPage=yes 41 | ArchitecturesAllowed=x64 42 | ArchitecturesInstallIn64BitMode=x64 43 | 44 | [Tasks] 45 | Name: desktopicon; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:" 46 | Name: startmenuicon; Description: "Create a &startmenu icon"; GroupDescription: "Additional icons:" 47 | Name: runapp; Description: "no"; GroupDescription: "no"; Check: WizardSilent 48 | 49 | [Files] 50 | Source: "*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs 51 | 52 | [Icons] 53 | Name: "{commondesktop}\\${issConfig.AppName}"; Filename: "{app}\\${issConfig.AppName}.exe"; Tasks: desktopicon 54 | Name: "{commonstartmenu}\\${issConfig.AppName}"; Filename: "{app}\\${issConfig.AppName}.exe"; Tasks: startmenuicon 55 | 56 | [Run] 57 | Filename: "{app}\\${issConfig.AppName}.exe"; Description: "Launch ${issConfig.AppName}"; Tasks: runapp; Flags: nowait postinstall; Check: WizardSilent 58 | Filename: "{app}\\${issConfig.AppName}.exe"; Description: "Launch ${issConfig.AppName}"; Flags: nowait postinstall; Check: WizardNotSilent 59 | 60 | [Code] 61 | function WizardNotSilent(): Boolean; 62 | begin 63 | Result := not WizardSilent(); 64 | end; 65 | `; 66 | 67 | fs.appendFileSync(appIssPath, iisStr, {flag: `w`}); 68 | } 69 | 70 | 71 | module.exports = createIssFile; 72 | -------------------------------------------------------------------------------- /template/webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | const settings = require('./config.js') 5 | const webpack = require('webpack') 6 | 7 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | const HtmlWebpackPlugin = require('html-webpack-plugin') 9 | 10 | let indexConfig = { 11 | target: 'electron-renderer', 12 | devtool: '#eval-source-map', 13 | entry: { 14 | build: path.join(__dirname, './app/src/main.js') 15 | }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.vue$/, 20 | loader: 'vue-loader', 21 | options: { 22 | loaders: { 23 | 'scss': 'vue-style-loader!css-loader!sass-loader', 24 | 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax' 25 | } 26 | } 27 | }, 28 | { 29 | test: /\.js$/, 30 | loader: 'babel-loader', 31 | exclude: /node_modules/, 32 | options: { 33 | presets: ['es2015', 'stage-0'], 34 | plugins: ['transform-runtime'] 35 | } 36 | }, 37 | { 38 | test: /\.json$/, 39 | loader: 'json-loader' 40 | }, 41 | { 42 | test: /\.css$/, 43 | loader: ExtractTextPlugin.extract({ 44 | fallback: "style-loader", 45 | use: "css-loader" 46 | }) 47 | }, 48 | { 49 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 50 | loader: 'url-loader', 51 | options: { 52 | limit: 10000, 53 | name: 'imgs/[name].[hash:7].[ext]' 54 | } 55 | }, 56 | { 57 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 58 | loader: 'url-loader', 59 | options: { 60 | limit: 10000, 61 | name: 'fonts/[name].[hash:7].[ext]' 62 | } 63 | } 64 | ] 65 | }, 66 | plugins: [ 67 | new ExtractTextPlugin('styles.css'), 68 | new HtmlWebpackPlugin({ 69 | filename: 'index.html', 70 | template: './app/index.ejs', 71 | title: settings.name 72 | }), 73 | new webpack.ProvidePlugin({ 74 | }), 75 | new webpack.NoEmitOnErrorsPlugin() 76 | ], 77 | node: { 78 | __dirname: true 79 | }, 80 | resolve: { 81 | extensions: ['.js', '.vue'], 82 | modules: [path.resolve(__dirname, "app"), "node_modules"] 83 | }, 84 | output: { 85 | filename: '[name].js', 86 | path: path.join(__dirname, './app/dist') 87 | } 88 | } 89 | 90 | 91 | let configArr = [] 92 | configArr.push(indexConfig) 93 | 94 | {{#if fork}} 95 | let forkConfig = { 96 | target: 'electron', 97 | devtool: '#eval-source-map', 98 | entry: { 99 | fork: path.join(__dirname, './app/src/sections/forkJs.js') 100 | }, 101 | module: { 102 | rules: [ 103 | { 104 | test: /\.js$/, 105 | loader: 'babel-loader', 106 | exclude: /node_modules/, 107 | options: { 108 | presets: ['es2015', 'stage-0'], 109 | plugins: ['transform-runtime'] 110 | } 111 | } 112 | ] 113 | }, 114 | plugins: [], 115 | node: { 116 | __dirname: true 117 | }, 118 | resolve: { 119 | extensions: ['.js'], 120 | modules: [path.resolve(__dirname, "app"), "node_modules"] 121 | }, 122 | output: { 123 | filename: '[name].js', 124 | path: path.join(__dirname, './app/dist') 125 | } 126 | } 127 | 128 | if (process.env.NODE_ENV === 'production') { 129 | forkConfig.devtool = '' 130 | forkConfig.plugins.push( 131 | new webpack.LoaderOptionsPlugin({ 132 | minimize: true 133 | }) 134 | ) 135 | } 136 | 137 | if (process.env.NODE_ENV !== 'developmentHot') { 138 | forkConfig.plugins.push( 139 | new webpack.DefinePlugin({ 140 | __DEFINE_NATIVE_REQUIRE__: JSON.stringify(true) 141 | }) 142 | ) 143 | configArr.push(forkConfig) 144 | } 145 | {{/if}} 146 | 147 | 148 | if (process.env.NODE_ENV === 'production') { 149 | indexConfig.devtool = '' 150 | indexConfig.plugins.push( 151 | new webpack.LoaderOptionsPlugin({ 152 | minimize: true 153 | }) 154 | ) 155 | } 156 | 157 | 158 | module.exports = configArr 159 | --------------------------------------------------------------------------------