diff --git a/README.md b/README.md index ea3c808061a8..fa95bd1c2cbf 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,26 @@ and then we edit the `package.json` file's start script to be now run it with `npm start` +### Mocking a Static Backend +Webpack dev server allows us to modify the ExpressJS `app` object using the `setup` method. +We do this by passing a file to `--server-config` + +We create a file next to the project's `package.json` called `server.conf.js` with the content + +```json +module.exports = function(app){ + app.get('/api/*', function(req, res){ + res.sendFile(req.originalUrl, {root: __dirname + '/mocks/'}); + }); +}; + +``` + +now run it with `ng serve --server-config server.conf.json` + +Thus fetches to `/api/foo` will return flat json from `/mocks/api/foo` + + ### Deploying the app via GitHub Pages You can deploy your apps quickly via: diff --git a/packages/angular-cli/commands/serve.ts b/packages/angular-cli/commands/serve.ts index abb0013f8e3d..bd140888abe5 100644 --- a/packages/angular-cli/commands/serve.ts +++ b/packages/angular-cli/commands/serve.ts @@ -15,6 +15,7 @@ export interface ServeTaskOptions { port?: number; host?: string; proxyConfig?: string; + serverConfig?: any; watcher?: string; liveReload?: boolean; liveReloadHost?: string; @@ -53,6 +54,7 @@ const ServeCommand = Command.extend({ description: 'Listens only on localhost by default' }, { name: 'proxy-config', type: 'Path', aliases: ['pc'] }, + { name: 'server-config', type: 'Path', aliases: ['sc'] }, { name: 'watcher', type: String, default: 'events', aliases: ['w'] }, { name: 'live-reload', type: Boolean, default: true, aliases: ['lr'] }, { diff --git a/packages/angular-cli/custom-typings.d.ts b/packages/angular-cli/custom-typings.d.ts index c82e20002580..96de0982cd77 100644 --- a/packages/angular-cli/custom-typings.d.ts +++ b/packages/angular-cli/custom-typings.d.ts @@ -4,6 +4,7 @@ interface IWebpackDevServerConfigurationOptions { historyApiFallback?: {[key: string]: any} | boolean; compress?: boolean; proxy?: {[key: string]: string}; + setup?: any; staticOptions?: any; quiet?: boolean; noInfo?: boolean; diff --git a/packages/angular-cli/tasks/serve-webpack.ts b/packages/angular-cli/tasks/serve-webpack.ts index 4aedab2b0800..2ce3d3a5b7d5 100644 --- a/packages/angular-cli/tasks/serve-webpack.ts +++ b/packages/angular-cli/tasks/serve-webpack.ts @@ -69,6 +69,17 @@ export default Task.extend({ } } + let serverConfig = {}; + if (serveTaskOptions.serverConfig) { + const serverConfigPath = path.resolve(this.project.root, serveTaskOptions.serverConfig); + if (fs.existsSync(serverConfigPath)) { + serverConfig = require(serverConfigPath); + } else { + const message = 'Server config file ' + serverConfigPath + ' does not exist.'; + return Promise.reject(new SilentError(message)); + } + } + let sslKey: string = null; let sslCert: string = null; if (serveTaskOptions.ssl) { @@ -95,6 +106,7 @@ export default Task.extend({ stats: statsConfig, inline: true, proxy: proxyConfig, + setup: serverConfig, compress: serveTaskOptions.target === 'production', watchOptions: { poll: CliConfig.fromProject().config.defaults.poll diff --git a/tests/e2e/tests/misc/static-server.ts b/tests/e2e/tests/misc/static-server.ts new file mode 100644 index 000000000000..8156d5272806 --- /dev/null +++ b/tests/e2e/tests/misc/static-server.ts @@ -0,0 +1,29 @@ +import { writeFile } from '../../utils/fs'; +import { request } from '../../utils/http'; +import { killAllProcesses, ng } from '../../utils/process'; +import { ngServe } from '../../utils/project'; +import { expectToFail } from '../../utils/utils'; + + +export default function() { + const serverConfigFile = 'server.config.js'; + const serverConfig = `module.exports = function(app){ + app.get('/api/test', function(req, res){ + res.json({ status:'TEST_API_RETURN' }); + }); + };`; + + return Promise.resolve() + .then(() => writeFile(serverConfigFile, serverConfig)) + .then(() => ngServe('--server-config', serverConfigFile)) + .then(() => request('http://localhost:4200/api/test')) + .then(body => { + if (!body.match(/TEST_API_RETURN/)) { + throw new Error('Response does not match expected value.'); + } + }) + .then(() => killAllProcesses(), (err) => { killAllProcesses(); throw err; }) + + // A non-existing proxy file should error. + .then(() => expectToFail(() => ng('serve', '--server-config', 'config.non-existent.js'))); +}