Seperate electron and web target building

This commit is contained in:
Farkas József
2017-01-20 02:03:27 +01:00
committed by József Farkas
parent 517aed1b1c
commit 983eb72892
276 changed files with 2154 additions and 95 deletions

1
electron/src/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
shared

166
electron/src/app.module.ts Normal file
View File

@@ -0,0 +1,166 @@
import { NgModule, ReflectiveInjector } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { StoreLogMonitorModule, useLogMonitor } from '@ngrx/store-log-monitor';
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
import { Select2Module } from 'ng2-select2/ng2-select2';
import { AddOnComponent } from './shared/components/add-on';
import { KeyboardSliderComponent } from './shared/components/keyboard/slider';
import { KeymapAddComponent, KeymapHeaderComponent } from './shared/components/keymap';
import { KeymapEditComponent } from './components/keymap/edit';
import { LayersComponent } from './shared/components/layers';
import {
MacroActionEditorComponent,
MacroDelayTabComponent,
MacroEditComponent,
MacroHeaderComponent,
MacroItemComponent,
MacroKeyTabComponent,
MacroListComponent,
MacroMouseTabComponent,
MacroNotFoundComponent,
MacroTextTabComponent
} from './shared/components/macro';
import { NotificationComponent } from './shared/components/notification';
import { PopoverComponent } from './shared/components/popover';
import {
KeymapTabComponent,
KeypressTabComponent,
LayerTabComponent,
MacroTabComponent,
MouseTabComponent,
NoneTabComponent
} from './shared/components/popover/tab';
import { CaptureKeystrokeButtonComponent } from './shared/components/popover/widgets/capture-keystroke';
import { IconComponent } from './shared/components/popover/widgets/icon';
import { SettingsComponent } from './shared/components/settings';
import { SideMenuComponent } from './shared/components/side-menu';
import { SvgKeyboardComponent } from './shared/components/svg/keyboard';
import {
SvgIconTextKeyComponent,
SvgKeyboardKeyComponent,
SvgKeystrokeKeyComponent,
SvgMouseClickKeyComponent,
SvgMouseKeyComponent,
SvgMouseMoveKeyComponent,
SvgMouseScrollKeyComponent,
SvgMouseSpeedKeyComponent,
SvgOneLineTextKeyComponent,
SvgSingleIconKeyComponent,
SvgSwitchKeymapKeyComponent,
SvgTextIconKeyComponent,
SvgTwoLineTextKeyComponent
} from './shared/components/svg/keys';
import { SvgModuleComponent } from './shared/components/svg/module';
import { SvgKeyboardWrapComponent } from './shared/components/svg/wrap';
import { MainAppComponent, appRoutingProviders, routing } from './main-app';
import { CancelableDirective } from './shared/directives';
import { CaptureService } from './shared/services/capture.service';
import { MapperService } from './shared/services/mapper.service';
import { UhkDeviceService } from './services/uhk-device.service';
import { KeymapEffects, MacroEffects } from './shared/store/effects';
import { keymapReducer, macroReducer, presetReducer } from './shared/store/reducers';
import { DataStorage } from './shared/store/storage';
import { KeymapEditGuard } from './shared/components/keymap/edit';
import { MacroNotFoundGuard } from './shared/components/macro/not-found';
// Create DataStorage dependency injection
const storageProvider = ReflectiveInjector.resolve([DataStorage]);
const storageInjector = ReflectiveInjector.fromResolvedProviders(storageProvider);
const storageService: DataStorage = storageInjector.get(DataStorage);
// All reducers that are used in application
const storeConfig = {
keymaps: storageService.saveState(keymapReducer),
macros: storageService.saveState(macroReducer),
presetKeymaps: presetReducer
};
@NgModule({
declarations: [
MainAppComponent,
KeymapEditComponent,
KeymapHeaderComponent,
NotificationComponent,
SvgIconTextKeyComponent,
SvgKeyboardKeyComponent,
SvgKeystrokeKeyComponent,
SvgMouseKeyComponent,
SvgMouseClickKeyComponent,
SvgMouseMoveKeyComponent,
SvgMouseScrollKeyComponent,
SvgMouseSpeedKeyComponent,
SvgOneLineTextKeyComponent,
SvgSingleIconKeyComponent,
SvgSwitchKeymapKeyComponent,
SvgTextIconKeyComponent,
SvgTwoLineTextKeyComponent,
SvgKeyboardKeyComponent,
SvgKeyboardWrapComponent,
SvgKeyboardComponent,
SvgModuleComponent,
LayersComponent,
PopoverComponent,
KeymapAddComponent,
SideMenuComponent,
KeypressTabComponent,
KeymapTabComponent,
LayerTabComponent,
MacroTabComponent,
MouseTabComponent,
NoneTabComponent,
CaptureKeystrokeButtonComponent,
IconComponent,
MacroEditComponent,
MacroListComponent,
MacroHeaderComponent,
MacroItemComponent,
MacroActionEditorComponent,
MacroDelayTabComponent,
MacroKeyTabComponent,
MacroMouseTabComponent,
MacroTextTabComponent,
MacroNotFoundComponent,
AddOnComponent,
SettingsComponent,
KeyboardSliderComponent,
CancelableDirective
],
imports: [
BrowserModule,
FormsModule,
DragulaModule,
routing,
StoreModule.provideStore(storeConfig, storageService.initialState()),
StoreDevtoolsModule.instrumentStore({
monitor: useLogMonitor({
visible: false,
position: 'right'
})
}),
StoreLogMonitorModule,
Select2Module,
EffectsModule.runAfterBootstrap(KeymapEffects),
EffectsModule.runAfterBootstrap(MacroEffects)
],
providers: [
MapperService,
appRoutingProviders,
KeymapEditGuard,
MacroNotFoundGuard,
CaptureService,
UhkDeviceService
],
bootstrap: [MainAppComponent]
})
export class AppModule { }

View File

@@ -0,0 +1 @@
export { KeymapEditComponent } from './keymap-edit.component';

View File

@@ -0,0 +1,93 @@
import { Component, HostListener, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import '@ngrx/core/add/operator/select';
import { Store } from '@ngrx/store';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import { Keymap } from '../../../shared/config-serializer/config-items/Keymap';
import { UhkBuffer } from '../../../shared/config-serializer/UhkBuffer';
import { AppState } from '../../../shared/store';
import { SvgKeyboardWrapComponent } from '../../../shared/components/svg/wrap';
import { KeymapEditComponent as SharedKeymapEditComponent } from '../../../shared/components/keymap/edit';
import { UhkDeviceService } from '../../../services/uhk-device.service';
@Component({
selector: 'keymap-edit',
template: require('../../../shared/components/keymap/edit/keymap-edit.component.html'),
styles: [require('../../../shared/components/keymap/edit/keymap-edit.component.scss')],
host: {
'class': 'container-fluid'
}
})
export class KeymapEditComponent extends SharedKeymapEditComponent {
@ViewChild(SvgKeyboardWrapComponent) wrap: SvgKeyboardWrapComponent;
constructor(
store: Store<AppState>,
route: ActivatedRoute,
private uhkDevice: UhkDeviceService
) {
super(store, route);
}
@HostListener('window:keydown.control.u', ['$event'])
onCtrlU(event: KeyboardEvent): void {
console.log('ctrl + u pressed');
event.preventDefault();
event.stopPropagation();
this.sendLayer();
}
@HostListener('window:keydown.control.i', ['$event'])
onCtrlI(event: KeyboardEvent): void {
console.log('ctrl + i pressed');
event.preventDefault();
event.stopPropagation();
this.sendKeymap();
}
private sendLayer(): void {
const currentLayer: number = this.wrap.getSelectedLayer();
this.keymap$
.first()
.map(keymap => keymap.layers[currentLayer])
.map(layer => {
const uhkBuffer = new UhkBuffer();
layer.toBinary(uhkBuffer);
return uhkBuffer.getBufferContent();
})
.switchMap((buffer: Buffer) => this.uhkDevice.sendConfig(buffer))
.do(response => console.log('Sending layer finished', response))
.switchMap(() => this.uhkDevice.applyConfig())
.subscribe(
(response) => console.log('Applying layer finished', response),
error => console.error('Error during uploading layer', error),
() => console.log('Layer has been sucessfully uploaded')
);
}
private sendKeymap(): void {
this.keymap$
.first()
.map(keymap => {
const uhkBuffer = new UhkBuffer();
keymap.toBinary(uhkBuffer);
return uhkBuffer.getBufferContent();
})
.switchMap((buffer: Buffer) => this.uhkDevice.sendConfig(buffer))
.do(response => console.log('Sending keymap finished', response))
.switchMap(() => this.uhkDevice.applyConfig())
.subscribe(
(response) => console.log('Applying keymap finished', response),
error => console.error('Error during uploading keymap', error),
() => console.log('Keymap has been sucessfully uploaded')
);
}
}

View File

@@ -0,0 +1 @@
export * from './keymap.routes';

View File

@@ -0,0 +1,26 @@
import { Routes } from '@angular/router';
import { KeymapAddComponent } from '../../shared/components/keymap/add/keymap-add.component';
import { KeymapEditComponent } from './edit';
import { KeymapEditGuard } from '../../shared/components/keymap/edit';
export const keymapRoutes: Routes = [
{
path: '',
redirectTo: '/keymap',
pathMatch: 'full'
},
{
path: 'keymap',
component: KeymapEditComponent,
canActivate: [KeymapEditGuard]
},
{
path: 'keymap/add',
component: KeymapAddComponent
},
{
path: 'keymap/:abbr',
component: KeymapEditComponent
}
];

View File

@@ -0,0 +1,55 @@
import { BrowserWindow, app } from 'electron';
import * as path from 'path';
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win: Electron.BrowserWindow;
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 1024,
height: 768,
webPreferences: {
nodeIntegration: true
}
});
win.maximize();
const indexPath = path.resolve(__dirname, './index.html');
// and load the index.html of the app.
win.loadURL(`file://${indexPath}`);
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here

34
electron/src/index.html Normal file
View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ultimate Hacking Keyboard Configurator</title>
<link href="vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link rel="shortcut icon" href="images/favicon.ico">
<script src="polyfills.uhk.js"></script>
<script src="vendor.uhk.js"></script>
<!--<script src="vendor/usb/usb.js"></script>-->
<script>
usb = require('usb');
</script>
</head>
<body>
<!-- Google Tag Manager -->
<noscript>
<iframe src="//www.googletagmanager.com/ns.html?id=GTM-PQLCXB" height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
<script>
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-PQLCXB');
</script>
<!-- End Google Tag Manager -->
<main-app></main-app>
<script src="app.uhk.js"></script> <!-- This should be moved to the head -->
</body>
</html>

View File

@@ -0,0 +1,2 @@
export * from './main-app.component';
export * from './main-app.routes';

View File

@@ -0,0 +1,67 @@
import { Component, ViewEncapsulation, HostListener } from '@angular/core';
// import { Observable } from 'rxjs/Observable';
// import { Store } from '@ngrx/store';
// import { AppState } from '../store';
// import { DataStorage } from '../store/storage';
// import { getKeymapEntities, getMacroEntities } from '../store/reducers';
// import { UhkBuffer } from '../config-serializer/UhkBuffer';
// import { UserConfiguration } from '../config-serializer/config-items/UserConfiguration';
// import { UhkDeviceService } from '../services/uhk-device.service';
@Component({
selector: 'main-app',
template: require('../shared/main-app/main-app.component.html'),
styles: [require('../shared/main-app/main-app.component.scss')],
encapsulation: ViewEncapsulation.None
})
export class MainAppComponent {
// private configuration$: Observable<UserConfiguration>;
constructor(
// private uhkDevice: UhkDeviceService,
// store: Store<AppState>,
// dataStorage: DataStorage
) {
// this.configuration$ = store.let(getKeymapEntities())
// .combineLatest(store.let(getMacroEntities()))
// .map((pair) => {
// const config = new UserConfiguration();
// Object.assign(config, dataStorage.getConfiguration());
// config.keymaps = pair[0];
// config.macros = pair[1];
// return config;
// });
}
@HostListener('window:keydown.control.o', ['$event'])
onCtrlO(event: KeyboardEvent): void {
console.log('ctrl + o pressed');
event.preventDefault();
event.stopPropagation();
this.sendConfiguration();
}
private sendConfiguration(): void {
// this.configuration$
// .first()
// .map(configuration => {
// const uhkBuffer = new UhkBuffer();
// configuration.toBinary(uhkBuffer);
// return uhkBuffer.getBufferContent();
// })
// .switchMap((buffer: Buffer) => this.uhkDevice.sendConfig(buffer))
// .do(response => console.log('Sending config finished', response))
// .switchMap(() => this.uhkDevice.applyConfig())
// .subscribe(
// (response) => console.log('Applying config finished', response),
// error => console.error('Error during uploading config', error),
// () => console.log('Config has been sucessfully uploaded')
// );
}
}

View File

@@ -0,0 +1,18 @@
import { ModuleWithProviders } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { addOnRoutes } from '../shared/components/add-on';
import { keymapRoutes } from '../components/keymap';
import { macroRoutes } from '../shared/components/macro';
import { settingsRoutes } from '../shared/components/settings';
const appRoutes: Routes = [
...keymapRoutes,
...macroRoutes,
...addOnRoutes,
...settingsRoutes
];
export const appRoutingProviders: any[] = [ ];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { useHash: true });

5
electron/src/main.ts Normal file
View File

@@ -0,0 +1,5 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@@ -0,0 +1,162 @@
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Observer } from 'rxjs/Observer';
import { ConnectableObservable } from 'rxjs/observable/ConnectableObservable';
import { Subject } from 'rxjs/Subject';
import { Subscriber } from 'rxjs/Subscriber';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/concat';
import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/publish';
import { Device, Interface, InEndpoint, OutEndpoint, findByIds } from 'usb';
import { Layer } from '../shared/config-serializer/config-items/Layer';
import { UhkBuffer } from '../shared/config-serializer/UhkBuffer';
const vendorId = 0x16d3;
const productId = 0x05ea;
const MAX_PAYLOAD_SIZE = 64;
enum Command {
UploadConfig = 8,
ApplyConfig = 9
};
interface SenderMessage {
buffer: Buffer;
observer: Observer<any>;
};
@Injectable()
export class UhkDeviceService {
private device: Device;
private connected: boolean;
private messageIn$: Observable<Buffer>;
private messageOut$: Subject<SenderMessage>;
private outSubscription: Subscription;
constructor() {
this.messageOut$ = new Subject<SenderMessage>();
this.connect();
}
connect(): void {
if (this.connected) {
return;
}
this.device = findByIds(vendorId, productId);
if (!this.device) {
throw new Error('UhkDevice not found.');
}
this.device.open();
const usbInterface: Interface = this.device.interface(0);
// https://github.com/tessel/node-usb/issues/147
// The function 'isKernelDriverActive' is not available on Windows and not even needed.
if (process.platform !== 'win32' && usbInterface.isKernelDriverActive()) {
usbInterface.detachKernelDriver();
}
usbInterface.claim();
this.messageIn$ = Observable.create((subscriber: Subscriber<Buffer>) => {
const inEndPoint: InEndpoint = <InEndpoint>usbInterface.endpoints[0];
console.log('Try to read');
inEndPoint.transfer(MAX_PAYLOAD_SIZE, (error: string, receivedBuffer: Buffer) => {
if (error) {
console.error('reading error', error);
subscriber.error(error);
} else {
console.log('read data', receivedBuffer);
subscriber.next(receivedBuffer);
subscriber.complete();
}
});
});
const outEndPoint: OutEndpoint = <OutEndpoint>usbInterface.endpoints[1];
const outSending = this.messageOut$.concatMap(senderPackage => {
return (<Observable<void>>Observable.create((subscriber: Subscriber<void>) => {
console.log('transfering', senderPackage.buffer);
outEndPoint.transfer(senderPackage.buffer, (error) => {
if (error) {
console.error('transfering errored', error);
subscriber.error(error);
} else {
console.log('transfering finished');
subscriber.complete();
}
});
})).concat(this.messageIn$)
.do(buffer => senderPackage.observer.next(buffer) && senderPackage.observer.complete())
.catch((error: string) => {
senderPackage.observer.error(error);
return Observable.empty<void>();
});
}).publish();
this.outSubscription = outSending.connect();
this.connected = true;
}
disconnect() {
if (!this.connected) {
return;
}
this.outSubscription.unsubscribe();
this.messageIn$ = undefined;
this.device.interface(0).release();
this.device.close();
this.connected = false;
}
sendConfig(configBuffer: Buffer): Observable<Buffer> {
return Observable.create((subscriber: Subscriber<Buffer>) => {
console.log('Sending...', configBuffer);
const fragments: Buffer[] = [];
const MAX_SENDING_PAYLOAD_SIZE = MAX_PAYLOAD_SIZE - 4;
for (let offset = 0; offset < configBuffer.length; offset += MAX_SENDING_PAYLOAD_SIZE) {
const length = offset + MAX_SENDING_PAYLOAD_SIZE < configBuffer.length
? MAX_SENDING_PAYLOAD_SIZE
: configBuffer.length - offset;
const header = new Buffer([Command.UploadConfig, length, offset & 0xFF, offset >> 8]);
fragments.push(Buffer.concat([header, configBuffer.slice(offset, offset + length)]));
}
const buffers: Buffer[] = [];
const observer: Observer<Buffer> = {
next: (buffer: Buffer) => buffers.push(buffer),
error: error => subscriber.error(error),
complete: () => {
if (buffers.length === fragments.length) {
subscriber.next(Buffer.concat(buffers));
subscriber.complete();
console.log('Sending finished');
}
}
};
fragments
.map<SenderMessage>(fragment => ({ buffer: fragment, observer }))
.forEach(senderPackage => this.messageOut$.next(senderPackage));
});
}
applyConfig(): Observable<Buffer> {
return Observable.create((subscriber: Subscriber<Buffer>) => {
console.log('Applying configuration');
this.messageOut$.next({
buffer: new Buffer([Command.ApplyConfig]),
observer: subscriber
});
});
}
}

View File

@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"../../node_modules/@types"
],
"types": [
"electron"
]
},
"files": [
"electron-main.ts"
]
}

View File

@@ -0,0 +1,29 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"typeRoots": [
"../../node_modules/@types"
],
"types": [
"node",
"jquery",
"core-js",
"select2",
"electron",
"usb"
]
},
"exclude": [
"../dist",
"electron-main.ts",
"webpack.config.*"
]
}

View File

@@ -0,0 +1,32 @@
//var webpack = require("webpack");
var webpackFailPlugin = require('webpack-fail-plugin');
var path = require('path');
var rootDir = path.resolve(__dirname, '../');
module.exports = {
entry: [ path.resolve(rootDir, 'src/electron-main.ts')],
output: {
path: rootDir + "/dist",
filename: "electron-main.js"
},
target: 'electron-main',
devtool: 'source-map',
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'],
modules: [path.join(rootDir, "node_modules")]
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader?' + JSON.stringify({ configFileName: 'tsconfig-electron-main.json' }), exclude: /node_modules/ },
]},
plugins: [
// new webpack.optimize.UglifyJsPlugin({ minimize: true })
webpackFailPlugin
],
node: {
__dirname: false,
__filename: false
}
}

View File

@@ -0,0 +1,94 @@
var webpack = require("webpack");
var SvgStore = require('webpack-svgstore-plugin');
var webpackFailPlugin = require('webpack-fail-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var path = require('path');
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
var rootDir = path.resolve(__dirname, '../');
module.exports = {
entry: {
polyfills: path.resolve(rootDir, 'src/shared/polyfills.ts'),
vendor: path.resolve(rootDir, 'src/shared/vendor.ts'),
app: path.resolve(rootDir, 'src/main.ts')
},
output: {
path: rootDir + "/dist",
filename: "[name].uhk.js"
},
target: 'electron-renderer',
externals: {
usb: 'usb'
},
devtool: 'source-map',
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'],
modules: [path.join(rootDir, "node_modules")],
alias: {
jquery: 'jquery/dist/jquery.min.js',
select2: 'select2/dist/js/select2.full.min.js'
}
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader', exclude: /node_modules/ },
{ test: /\.html$/, loader: 'html-loader?attrs=false' },
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: ['raw-loader', 'sass-loader']
},
{ test: /jquery/, loader: 'expose?$!expose?jQuery' },
{ test: require.resolve("usb"), loader: "expose?usb" }
]
},
plugins: [
// new webpack.optimize.UglifyJsPlugin({ minimize: true })
new SvgStore({
svgoOptions: {
plugins: [
{ removeTitle: true }
]
}
}),
webpackFailPlugin,
new CopyWebpackPlugin(
[
{ from: './electron/src/**/*.html', flatten: true },
{ from: './electron/src/**/*.js', flatten: true },
{
from: 'node_modules/font-awesome/css/font-awesome.min.css',
to: 'vendor/font-awesome/css/font-awesome.min.css'
},
{
from: 'node_modules/font-awesome/fonts',
to: 'vendor/font-awesome/fonts'
},
{
from: 'node_modules/bootstrap/dist/',
to: 'vendor/bootstrap'
},
{
from: 'images',
to: 'images'
},
{
from: 'node_modules/usb',
to: 'vendor/usb'
}
],
{
ignore: ['*.config.js']
}
),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
}),
new CommonsChunkPlugin({
name: ['app', 'vendor', 'polyfills']
})
]
}