Skip to content

Commit

Permalink
feat(serve): add proxy support
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
mmrath authored and TheLarkInn committed Aug 19, 2016
1 parent 22a6b59 commit 9d69748
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 6 deletions.
8 changes: 3 additions & 5 deletions addon/ng2/commands/serve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ const defaultPort = process.env.PORT || 4200;
export interface ServeTaskOptions {
port?: number;
host?: string;
proxy?: string;
insecureProxy?: boolean;
proxyConfig?: string;
watcher?: string;
liveReload?: boolean;
liveReloadHost?: string;
Expand All @@ -37,9 +36,8 @@ module.exports = Command.extend({

availableOptions: [
{ name: 'port', type: Number, default: defaultPort, aliases: ['p'] },
{ name: 'host', type: String, default: 'localhost', aliases: ['H'], description: 'Listens on localhost by default' },
{ name: 'proxy', type: String, aliases: ['pr', 'pxy'] },
{ name: 'insecure-proxy', type: Boolean, default: false, aliases: ['inspr'], description: 'Set false to proxy self-signed SSL certificates' },
{ name: 'host', type: String, default: 'localhost', aliases: ['H'], description: 'Listens on all interfaces by default' },
{ name: 'proxy-config', type: 'Path', aliases: ['pc'] },
{ name: 'watcher', type: String, default: 'events', aliases: ['w'] },
{ name: 'live-reload', type: Boolean, default: true, aliases: ['lr'] },
{ name: 'live-reload-host', type: String, aliases: ['lrh'], description: 'Defaults to host' },
Expand Down
16 changes: 15 additions & 1 deletion addon/ng2/tasks/serve-webpack.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import * as chalk from 'chalk';
import * as SilentError from 'silent-error';
import * as Task from 'ember-cli/lib/models/task';
import * as webpack from 'webpack';
import * as WebpackDevServer from 'webpack-dev-server';
Expand Down Expand Up @@ -27,11 +29,23 @@ module.exports = Task.extend({
colors: true
}));

let proxyConfig = {};
if (commandOptions.proxyConfig) {
const proxyPath = path.resolve(this.project.root, commandOptions.proxyConfig);
if (fs.existsSync(proxyPath)) {
proxyConfig = require(proxyPath);
} else {
var message = 'Proxy config file ' + proxyPath + ' does not exist.';
return Promise.reject(new SilentError(message));
}
}

const webpackDevServerConfiguration: IWebpackDevServerConfigurationOptions = {
contentBase: config.output.path,
historyApiFallback: true,
stats: webpackDevServerOutputOptions,
inline: true
inline: true,
proxy: proxyConfig
};

const serveMessage:string = chalk.green(`\n*\n*\n NG Live Development Server is running on http://${commandOptions.host}:${commandOptions.port}.\n*\n*`);
Expand Down
78 changes: 78 additions & 0 deletions tests/e2e/e2e_workflow.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ var treeKill = require('tree-kill');
var child_process = require('child_process');
var ng = require('../helpers/ng');
var root = path.join(process.cwd(), 'tmp');
var express = require('express');
var http = require('http');
var request = require('request');

function existsSync(path) {
try {
Expand Down Expand Up @@ -564,6 +567,81 @@ describe('Basic end-to-end Workflow', function () {
throw new Error(msg);
});
});

it('Serve with proxy config', function () {
this.timeout(240000);
var ngServePid;
var server;

function executor(resolve, reject) {
var startedProtractor = false;
var app = express();
server = http.createServer(app);
server.listen();
app.set('port', server.address().port);

app.get('/api/test', function (req, res) {
res.send('TEST_API_RETURN');
});
var backendHost = 'localhost';
var backendPort = server.address().port

var proxyServerUrl = `http://${backendHost}:${backendPort}`;
const proxyConfigFile = path.join(process.cwd(), 'proxy.config.json');
const proxyConfig = {
'/api/*': {
target: proxyServerUrl
}
};
fs.writeFileSync(proxyConfigFile, JSON.stringify(proxyConfig, null, 2), 'utf8');
var serveProcess = child_process.exec(`${ngBin} serve --proxy-config proxy.config.json`, { maxBuffer: 500 * 1024 });
ngServePid = serveProcess.pid;

serveProcess.stdout.on('data', (data) => {
if (/webpack: bundle is now VALID/.test(data.toString('utf-8')) && !startedProtractor) {

// How to get the url with out hardcoding here?
request( 'http://localhost:4200/api/test', function(err, response, body) {
expect(response.statusCode).to.be.equal(200);
expect(body).to.be.equal('TEST_API_RETURN');
resolve();
});
}
});

serveProcess.stderr.on('data', (data) => {
reject(data);
});
serveProcess.on('close', (code) => {
code === 0 ? resolve() : reject('ng serve command closed with error')
});
}

// Need a way to close the express server
return new Promise(executor)
.then(() => {
if (ngServePid) treeKill(ngServePid);
if(server){
server.close();
}
})
.catch((msg) => {
if (ngServePid) treeKill(ngServePid);
if(server){
server.close();
}
throw new Error(msg);
});
});

it('Serve fails on invalid proxy config file', function (done) {
this.timeout(420000);
sh.exec(`${ngBin} serve --proxy-config proxy.config.does_not_exist.json`, (code) => {
expect(code).to.not.equal(0);
done();
});
});

});

function isMobileTest() {
Expand Down

0 comments on commit 9d69748

Please sign in to comment.