Skip to content

Commit 9d69748

Browse files
mmrathTheLarkInn
authored andcommitted
feat(serve): add proxy support
Add support to proxy backend. Proxy confguration would support all the configuration mentioned at https://webpack.github.io/docs/webpack-dev-server.html#proxy except transforamtions done using functions. Configuration should be added to a json file and file name(relative to project root) should be passed as an argument to ng serve command e.g `ng serve --proxy-config proxy.config.json`
1 parent 22a6b59 commit 9d69748

File tree

3 files changed

+96
-6
lines changed

3 files changed

+96
-6
lines changed

addon/ng2/commands/serve.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ const defaultPort = process.env.PORT || 4200;
1414
export interface ServeTaskOptions {
1515
port?: number;
1616
host?: string;
17-
proxy?: string;
18-
insecureProxy?: boolean;
17+
proxyConfig?: string;
1918
watcher?: string;
2019
liveReload?: boolean;
2120
liveReloadHost?: string;
@@ -37,9 +36,8 @@ module.exports = Command.extend({
3736

3837
availableOptions: [
3938
{ name: 'port', type: Number, default: defaultPort, aliases: ['p'] },
40-
{ name: 'host', type: String, default: 'localhost', aliases: ['H'], description: 'Listens on localhost by default' },
41-
{ name: 'proxy', type: String, aliases: ['pr', 'pxy'] },
42-
{ name: 'insecure-proxy', type: Boolean, default: false, aliases: ['inspr'], description: 'Set false to proxy self-signed SSL certificates' },
39+
{ name: 'host', type: String, default: 'localhost', aliases: ['H'], description: 'Listens on all interfaces by default' },
40+
{ name: 'proxy-config', type: 'Path', aliases: ['pc'] },
4341
{ name: 'watcher', type: String, default: 'events', aliases: ['w'] },
4442
{ name: 'live-reload', type: Boolean, default: true, aliases: ['lr'] },
4543
{ name: 'live-reload-host', type: String, aliases: ['lrh'], description: 'Defaults to host' },

addon/ng2/tasks/serve-webpack.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import * as fs from 'fs';
12
import * as path from 'path';
23
import * as chalk from 'chalk';
4+
import * as SilentError from 'silent-error';
35
import * as Task from 'ember-cli/lib/models/task';
46
import * as webpack from 'webpack';
57
import * as WebpackDevServer from 'webpack-dev-server';
@@ -27,11 +29,23 @@ module.exports = Task.extend({
2729
colors: true
2830
}));
2931

32+
let proxyConfig = {};
33+
if (commandOptions.proxyConfig) {
34+
const proxyPath = path.resolve(this.project.root, commandOptions.proxyConfig);
35+
if (fs.existsSync(proxyPath)) {
36+
proxyConfig = require(proxyPath);
37+
} else {
38+
var message = 'Proxy config file ' + proxyPath + ' does not exist.';
39+
return Promise.reject(new SilentError(message));
40+
}
41+
}
42+
3043
const webpackDevServerConfiguration: IWebpackDevServerConfigurationOptions = {
3144
contentBase: config.output.path,
3245
historyApiFallback: true,
3346
stats: webpackDevServerOutputOptions,
34-
inline: true
47+
inline: true,
48+
proxy: proxyConfig
3549
};
3650

3751
const serveMessage:string = chalk.green(`\n*\n*\n NG Live Development Server is running on http://${commandOptions.host}:${commandOptions.port}.\n*\n*`);

tests/e2e/e2e_workflow.spec.js

+78
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ var treeKill = require('tree-kill');
1111
var child_process = require('child_process');
1212
var ng = require('../helpers/ng');
1313
var root = path.join(process.cwd(), 'tmp');
14+
var express = require('express');
15+
var http = require('http');
16+
var request = require('request');
1417

1518
function existsSync(path) {
1619
try {
@@ -564,6 +567,81 @@ describe('Basic end-to-end Workflow', function () {
564567
throw new Error(msg);
565568
});
566569
});
570+
571+
it('Serve with proxy config', function () {
572+
this.timeout(240000);
573+
var ngServePid;
574+
var server;
575+
576+
function executor(resolve, reject) {
577+
var startedProtractor = false;
578+
var app = express();
579+
server = http.createServer(app);
580+
server.listen();
581+
app.set('port', server.address().port);
582+
583+
app.get('/api/test', function (req, res) {
584+
res.send('TEST_API_RETURN');
585+
});
586+
var backendHost = 'localhost';
587+
var backendPort = server.address().port
588+
589+
var proxyServerUrl = `http://${backendHost}:${backendPort}`;
590+
const proxyConfigFile = path.join(process.cwd(), 'proxy.config.json');
591+
const proxyConfig = {
592+
'/api/*': {
593+
target: proxyServerUrl
594+
}
595+
};
596+
fs.writeFileSync(proxyConfigFile, JSON.stringify(proxyConfig, null, 2), 'utf8');
597+
var serveProcess = child_process.exec(`${ngBin} serve --proxy-config proxy.config.json`, { maxBuffer: 500 * 1024 });
598+
ngServePid = serveProcess.pid;
599+
600+
serveProcess.stdout.on('data', (data) => {
601+
if (/webpack: bundle is now VALID/.test(data.toString('utf-8')) && !startedProtractor) {
602+
603+
// How to get the url with out hardcoding here?
604+
request( 'http://localhost:4200/api/test', function(err, response, body) {
605+
expect(response.statusCode).to.be.equal(200);
606+
expect(body).to.be.equal('TEST_API_RETURN');
607+
resolve();
608+
});
609+
}
610+
});
611+
612+
serveProcess.stderr.on('data', (data) => {
613+
reject(data);
614+
});
615+
serveProcess.on('close', (code) => {
616+
code === 0 ? resolve() : reject('ng serve command closed with error')
617+
});
618+
}
619+
620+
// Need a way to close the express server
621+
return new Promise(executor)
622+
.then(() => {
623+
if (ngServePid) treeKill(ngServePid);
624+
if(server){
625+
server.close();
626+
}
627+
})
628+
.catch((msg) => {
629+
if (ngServePid) treeKill(ngServePid);
630+
if(server){
631+
server.close();
632+
}
633+
throw new Error(msg);
634+
});
635+
});
636+
637+
it('Serve fails on invalid proxy config file', function (done) {
638+
this.timeout(420000);
639+
sh.exec(`${ngBin} serve --proxy-config proxy.config.does_not_exist.json`, (code) => {
640+
expect(code).to.not.equal(0);
641+
done();
642+
});
643+
});
644+
567645
});
568646

569647
function isMobileTest() {

0 commit comments

Comments
 (0)