Commit ccd794d5 by Johannes Edmeier

Add ui-hystrix module

By using the netflix/hystrix-dashboard this module allows you to view the metrics from hystrix/turbine in the spring boot admin server. This module needs to be added explicitly. closes #147
parent a7bcfb9b
......@@ -19,6 +19,7 @@
<main.basedir>${basedir}</main.basedir>
<spring-boot.version>1.4.0.RELEASE</spring-boot.version>
<spring-cloud.version>Brixton.SR5</spring-cloud.version>
<hystrix-dashboard.version>1.5.5</hystrix-dashboard.version>
<build-plugin.jacoco.version>0.7.7.201606060606</build-plugin.jacoco.version>
<build-plugin.coveralls.version>4.2.0</build-plugin.coveralls.version>
<build-plugin.gpg.version>1.6</build-plugin.gpg.version>
......@@ -30,6 +31,7 @@
<module>spring-boot-admin-server</module>
<module>spring-boot-admin-server-ui</module>
<module>spring-boot-admin-server-ui-activiti</module>
<module>spring-boot-admin-server-ui-hystrix</module>
<module>spring-boot-admin-samples</module>
<module>spring-boot-admin-starter-client</module>
<module>spring-boot-admin-docs</module>
......@@ -231,6 +233,11 @@
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui-hystrix</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${project.version}</version>
</dependency>
......@@ -240,6 +247,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-dashboard</artifactId>
<version>${hystrix-dashboard.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
......
......@@ -18,6 +18,10 @@
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
......
......@@ -11,3 +11,5 @@ eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring.boot.admin.routes.endpoints: env,metrics,trace,dump,jolokia,info,configprops,trace,activiti,logfile,refresh,flyway,liquibase,heapdump,hystrix.stream
env:
browser: true
commonjs: true
extends: 'eslint:recommended'
rules:
indent:
- error
- 2
- SwitchCase: 1
linebreak-style:
- error
- unix
quotes:
- error
- single
semi:
- error
- always
{
"name": "spring-boot-admin-server-ui-hystrix",
"version": "1.4.1",
"scripts": {
"build": "npm run build:js",
"build:js": "webpack -p",
"watch:js": "webpack -d --watch",
"dev-server": "webpack-dev-server --port 9000"
},
"dependencies": {
"d3": "^3.5.17",
"jquery": "^3.1.0",
"microtemplates": "^0.1.0"
},
"devDependencies": {
"clean-webpack-plugin": "^0.1.10",
"copy-webpack-plugin": "^3.0.1",
"css-loader": "^0.23.1",
"eslint": "^2.13.1",
"eslint-loader": "^1.5.0",
"exports-loader": "^0.6.3",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"glob": "^7.0.6",
"imports-loader": "^0.6.5",
"ng-annotate": "^1.2.1",
"ng-annotate-loader": "^0.1.1",
"ng-annotate-webpack-plugin": "^0.1.3",
"raw-loader": "^0.5.1",
"regexp-replace-loader": "0.0.1",
"style-loader": "^0.13.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.15.0",
"webpack-sources": "^0.1.2",
"yargs": "^4.8.1"
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin</artifactId>
<version>1.4.2-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>spring-boot-admin-server-ui-hystrix</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-dashboard</artifactId>
<version>${hystrix-dashboard.version}</version>
<type>war</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/hystrix-dashboard</outputDirectory>
<excludes>WEB-INF/**,META-INF/**</excludes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>npm-install</id>
<phase>validate</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argument>install</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm-build</id>
<phase>generate-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>npm</executable>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>npm-test</id>
<phase>test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<skip>true</skip>
<executable>npm</executable>
<arguments>
<argument>run</argument>
<argument>test</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>target/dist</directory>
<targetPath>META-INF/spring-boot-admin-server-ui</targetPath>
</resource>
</resources>
</build>
</project>
.hystrix-container {
padding: 15px;
line-height: 1;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
border-radius: 0 0 4px 4px;
background-color: white;
}
.hystrix-container .tooltip {
/*Reset all values from Bootstrap */
position: inherit;
z-index: inherit;
display: inherit;
font-size: inherit;
line-height: inherit;
opacity: inherit;
}
.spacer {
width: 100%;
margin: 0 auto;
padding-top:4px;
clear:both;
}
.last {
margin-right: 0px;
}
.success {
color: green;
}
.shortCircuited {
color: blue;
}
.timeout {
color: #FF9900; /* shade of orange */
}
.failure {
color: red;
}
.rejected {
color: purple;
}
.exceptionsThrown {
color: brown;
}
.badRequest {
color: lightSeaGreen;
}
\ No newline at end of file
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var id = 0;
require('./hystrix.css');
require('hystrix/hystrixCommand.css');
var HystrixCommandMonitor = require('hystrix/hystrixCommand');
module.exports = {
bindings: {
source: '<eventSource'
},
controller: function () {
var ctrl = this;
ctrl.$onInit = function () {
ctrl.id = id++;
ctrl.monitor = new HystrixCommandMonitor(0, 'hystrix-command-' + ctrl.id, { includeDetailIcon: false });
ctrl.monitor.sortByErrorThenVolume();
ctrl.source.addEventListener('message', ctrl.monitor.eventSourceMessageListener, false);
};
},
template: require('./hystrixCommand.tpl.html')
};
<div class="hystrix-container">
Sort by
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByErrorThenVolume()">Error then Volume</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortAlphabetically()">Alphabetical</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByVolume()">Volume</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByError()">Error</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByLatencyMean()">Mean</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByLatencyMedian()">Median</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByLatency90()">90th</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByLatency99()">99th</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByLatency995()">99.5th</button>
<div id="hystrix-command-{{$ctrl.id}}" class="hystrix-row dependencies">
<span class="loading">Loading ...</span>
</div>
<div class="spacer"></div>
<div style="padding-top: 4px;">
<span class="success">Success</span>
<span class="shortCircuited">Short-Circuited</span>
<span class="badRequest"> Bad Request</span>
<span class="timeout">Timeout</span>
<span class="rejected">Rejected</span>
<span class="failure">Failure</span>
<span class="errorPercentage">Error %</span>
</div>
</div>
/*
* Copyright 2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var id = 0;
require('./hystrix.css');
require('hystrix/hystrixThreadPool.css');
var HystrixThreadPoolMonitor = require('hystrix/hystrixThreadPool');
module.exports = {
bindings: {
source: '<eventSource'
},
controller: function () {
var ctrl = this;
ctrl.$onInit = function () {
ctrl.id = id++;
ctrl.monitor = new HystrixThreadPoolMonitor(0, 'hystrix-thread-pools-' + ctrl.id);
ctrl.monitor.sortByVolume();
ctrl.source.addEventListener('message', ctrl.monitor.eventSourceMessageListener, false);
};
},
template: require('./hystrixThreadPool.tpl.html')
};
<div class="hystrix-container">
Sort by
<button class="btn btn-link" ng-click="$ctrl.monitor.sortAlphabetically()">Alphabetical</button>
<button class="btn btn-link" ng-click="$ctrl.monitor.sortByVolume()">Volume</button>
<div id="hystrix-thread-pools-{{$ctrl.id}}" class="hystrix-row dependencyThreadPools"><span class="loading">Loading ...</span></div>
<div class="spacer"></div>
</div>
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
module.exports = function (path) {
return function ($scope, application) {
'ngInject';
$scope.error = null;
$scope.streamUrl = 'api/applications/' + application.id + '/' + path;
$scope.hystrixStream = new EventSource($scope.streamUrl);
$scope.hystrixStream.addEventListener('message', function () {
if ($scope.error) {
$scope.error = null;
$scope.$apply();
}
}, false);
$scope.hystrixStream.addEventListener('error', function (e) {
$scope.error = e;
$scope.$apply();
}, false);
$scope.$on('$destroy', function () {
$scope.hystrixStream.close();
});
};
};
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var angular = require('angular');
require('hystrix/hystrixThreadPool.css');
var module = angular.module('sba-applications-hystrix', ['sba-applications']);
global.sbaModules.push(module.name);
module.component('sbaHystrixCommand', require('./components/hystrixCommand.js'));
module.component('sbaHystrixThreadPool', require('./components/hystrixThreadPool.js'));
module.controller('hystrixCtrl', require('./controllers/hystrixCtrl.js')('hystrix.stream'));
module.controller('turbineCtrl', require('./controllers/hystrixCtrl.js')('turbine.stream'));
module.config(function ($stateProvider) {
$stateProvider.state('applications.hystrix', {
url: '/hystrix',
templateUrl: 'applications-hystrix/views/hystrix.html',
controller: 'hystrixCtrl'
});
$stateProvider.state('applications.turbine', {
url: '/turbine',
templateUrl: 'applications-hystrix/views/hystrix.html',
controller: 'turbineCtrl'
});
});
module.run(function (ApplicationViews, $sce, $q) {
var isEventSourceAvailable = function (url) {
var deferred = $q.defer();
var source = new EventSource(url);
source.addEventListener('message', function () {
source.close();
deferred.resolve(true);
}, false);
source.addEventListener('error', function () {
source.close();
deferred.resolve(false);
}, false);
return deferred.promise;
};
ApplicationViews.register({
order: 150,
title: $sce.trustAsHtml('<i class="fa fa-gear fa-fw"></i>Hystrix'),
state: 'applications.hystrix',
show: function (application) {
if (!application.managementUrl || !application.statusInfo.status || application.statusInfo.status === 'OFFLINE') {
return false;
}
return isEventSourceAvailable('api/applications/' + application.id + '/hystrix.stream');
}
});
ApplicationViews.register({
order: 155,
title: $sce.trustAsHtml('<i class="fa fa-gear fa-fw"></i>Turbine'),
state: 'applications.turbine',
show: function (application) {
if (!application.managementUrl || !application.statusInfo.status || application.statusInfo.status === 'OFFLINE') {
return false;
}
return isEventSourceAvailable('api/applications/' + application.id + '/turbine.stream');
}
});
});
<div class="alert alert-error" ng-if="error">
Unable to connect to Command Metric Stream '{{streamUrl}}'.<br>
<b>Error:</b> {{ error }}
</div>
<sba-info-panel panel-title="Cuircuit Breakers">
<sba-hystrix-command event-source="hystrixStream"></sba-hystrix-command>
</sba-info-panel>
<sba-info-panel panel-title="Thread Pools">
<sba-hystrix-thread-pool event-source="hystrixStream"></sba-hystrix-thread-pool>
</sba-info-panel>
\ No newline at end of file
'use strict';
var Webpack = require('webpack'),
NgAnnotatePlugin = require('ng-annotate-webpack-plugin'),
CopyWebpackPlugin = require('copy-webpack-plugin'),
CleanWebpackPlugin = require('clean-webpack-plugin'),
ExtractTextPlugin = require('extract-text-webpack-plugin'),
path = require('path');
var DIST = path.resolve(__dirname, 'target/dist');
var ROOT = __dirname;
var isDevServer = path.basename(require.main.filename) === 'webpack-dev-server.js';
module.exports = {
context: ROOT,
entry: { 'applications-hystrix': './src/module.js' },
output: {
path: DIST,
filename: '[name]/module.js'
},
externals: ['angular'],
resolve: {
alias: {
'hystrix/hystrixCommand': path.resolve(ROOT, 'target/hystrix-dashboard/components/hystrixCommand/hystrixCommand.js'),
'hystrix/hystrixCommand.css': path.resolve(ROOT, 'target/hystrix-dashboard/components/hystrixCommand/hystrixCommand.css'),
'hystrix/hystrixThreadPool': path.resolve(ROOT, 'target/hystrix-dashboard/components/hystrixThreadPool/hystrixThreadPool.js'),
'hystrix/hystrixThreadPool.css': path.resolve(ROOT, 'target/hystrix-dashboard/components/hystrixThreadPool/hystrixThreadPool.css'),
'tsort' : path.resolve(ROOT, 'target/hystrix-dashboard/js/jquery.tinysort.min.js'),
}
},
module: {
preLoaders: [{
test: /\.js$/,
loader: 'eslint',
exclude: [/node_modules/, /target\/hystrix-dashboard/]
}],
loaders: [
{
test: /hystrix-dashboard\/js\/jquery\.tinysort\.min\.js$/,
loader: 'imports?jQuery=jquery',
},{
test: /hystrix-dashboard\/components\/hystrixCommand\/hystrixCommand\.js$/,
loaders: [
'imports?this=>global&jQuery=jquery&$=jquery&d3&tmpl=microtemplates&tsort',
'exports?window.HystrixCommandMonitor',
'regexp-replace?{"match": { "pattern": "\.\./components/hystrixCommand", "flags": "g" }, "replaceWith": "applications-hystrix/components/hystrixCommand"}'
],
}, {
test: /hystrix-dashboard\/components\/hystrixThreadPool\/hystrixThreadPool\.js$/,
loaders: [
'imports?this=>global&jQuery=jquery&$=jquery&d3&tmpl=microtemplates&tsort',
'exports?HystrixThreadPoolMonitor',
'regexp-replace?{"match": { "pattern": "\.\./components/hystrixThreadPool", "flags": "g" }, "replaceWith": "applications-hystrix/components/hystrixThreadPool"}'
],
}, {
test: /\.js$/,
exclude: [/node_modules/],
loader: 'ng-annotate'
}, {
test: /\.tpl\.html$/,
loader: 'raw'
}, {
test: /\.css(\?.*)?$/,
loader: ExtractTextPlugin.extract('style', 'css?-minimize')
}
]
},
plugins: [
new CleanWebpackPlugin([DIST]),
new ExtractTextPlugin('[name]/module.css'),
new NgAnnotatePlugin({ add: true }),
new CopyWebpackPlugin([{
from: '**/*.html',
to: 'applications-hystrix',
context: 'src/'
}, {
from: '**/*.html',
to: 'applications-hystrix/components',
context: 'target/hystrix-dashboard/components'
}, {
from: '**/*.png',
to: 'applications-hystrix/components',
context: 'target/hystrix-dashboard/components'
}
], { ignore: ['*.tpl.html'] })
],
devServer: {
proxy: [
{
context: '/',
target: 'http://localhost:8080',
secure: false,
onProxyRes: function (proxyRes, req, res) {
/* Append the applications-hystrix/module.js to the all-modules.js */
if (req.path === '/all-modules.js') {
delete proxyRes.headers['content-length'];
proxyRes.headers['transfer-encoding'] = 'chunked';
proxyRes.__pipe = proxyRes.pipe;
proxyRes.pipe = function (sink, options) {
var opts = options || {};
opts.end = false;
proxyRes.__pipe(sink, opts);
};
var suffix_module = ";\n"
require('http').get('http://localhost:9000/applications-hystrix/module.js', function (r) {
r.on('data', function (chunk) {
suffix_module += chunk;
});
r.on('end', function () {
res.end(suffix_module);
});
});
}
if (req.path === '/all-modules.css') {
delete proxyRes.headers['content-length'];
proxyRes.headers['transfer-encoding'] = 'chunked';
proxyRes.__pipe = proxyRes.pipe;
proxyRes.pipe = function (sink, options) {
var opts = options || {};
opts.end = false;
proxyRes.__pipe(sink, opts);
};
var suffix_module = "\n"
require('http').get('http://localhost:9000/applications-hystrix/module.css', function (r) {
r.on('data', function (chunk) {
suffix_module += chunk;
});
r.on('end', function () {
res.end(suffix_module);
});
});
}
}
}
]
},
node: {
fs: 'empty'
}
};
......@@ -7,13 +7,15 @@ body {
margin-left: auto;
margin-right: auto;
}
a {
color: #5fa134;
}
.btn-link,
.btn-link:hover,
.btn-link:active,
a,
a:hover,
a:active {
color: #5fa134;
}
pre {
white-space: pre;
}
......
......@@ -13,14 +13,6 @@
</head>
<body>
<script type="text/javascript">
// Work around Google font rendering issues in webkit browsers on Windows 7
if (navigator.userAgent.indexOf("NT 6.1") != -1) {
document.body.style.WebkitTextStroke = "0.5px";
}
</script>
<header class="navbar header--navbar desktop-only">
<div class="navbar-inner">
<div class="container-fluid">
......
......@@ -95,8 +95,12 @@ module.run(function ($rootScope, $state, Notification, Application, ApplicationG
});
// setups up the sse-reciever
var journalEventSource = new EventSource('api/journal?stream');
journalEventSource.onmessage = function (message) {
$rootScope.journalEventSource = new EventSource('api/journal?stream');
$rootScope.$on('$destroy', function () {
$rootScope.journalEventSource.close();
});
$rootScope.journalEventSource.addEventListener('message', function (message) {
var event = JSON.parse(message.data);
Object.setPrototypeOf(event.application, Application.prototype);
......@@ -131,5 +135,5 @@ module.run(function ($rootScope, $state, Notification, Application, ApplicationG
$rootScope.$apply();
Notification.notify(title, options);
};
});
});
......@@ -41,9 +41,9 @@
<div class="pull-right">
<div class="btn-group">
<a ng-if="views.length > 0" ng-href="{{views[0].href}}" target="{{views[0].target}}" class="btn btn-success" ng-bind-html="views[0].title"></a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="views.length > 1">
<button class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="views.length > 1">
<i class="fa fa-caret-down"></i>
</a>
</button>
<ul class="dropdown-menu">
<li ng-repeat="view in views.slice(1)">
<a ng-href="{{view.href}}" target="{{view.target}}" ng-bind-html="view.title"></a>
......
......@@ -21,29 +21,29 @@
"linkifyjs": "^2.0.3"
},
"devDependencies": {
"clean-webpack-plugin": "^0.1.9",
"copy-webpack-plugin": "^3.0.0",
"clean-webpack-plugin": "^0.1.10",
"copy-webpack-plugin": "^3.0.1",
"css-loader": "^0.23.1",
"eslint": "^2.10.2",
"eslint-loader": "^1.3.0",
"eslint": "^2.13.1",
"eslint-loader": "^1.5.0",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"glob": "^7.0.3",
"glob": "^7.0.6",
"jasmine-core": "^2.4.1",
"karma": "^0.13.22",
"karma-chrome-launcher": "^1.0.1",
"karma-jasmine": "^1.0.2",
"karma-phantomjs-launcher": "^1.0.0",
"karma-webpack": "^1.7.0",
"karma-phantomjs-launcher": "^1.0.1",
"karma-webpack": "^1.8.0",
"ng-annotate": "^1.2.1",
"ng-annotate-loader": "^0.1.0",
"ng-annotate-webpack-plugin": "^0.1.2",
"phantomjs-prebuilt": "^2.1.7",
"ng-annotate-loader": "^0.1.1",
"ng-annotate-webpack-plugin": "^0.1.3",
"phantomjs-prebuilt": "^2.1.12",
"raw-loader": "^0.5.1",
"style-loader": "^0.13.1",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1",
"webpack": "^1.13.2",
"webpack-dev-server": "^1.15.0",
"webpack-sources": "^0.1.2",
"yargs": "^4.7.1"
"yargs": "^4.8.1"
}
}
......@@ -144,12 +144,11 @@ module.exports = {
}
])),
devServer: {
proxy: {
'/api*': {
proxy: [{
context: '/api',
target: 'http://localhost:8080',
secure: false
}
}
}]
},
node: {
fs: 'empty'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment