alm
Version:
The best IDE for TypeScript
184 lines (157 loc) • 5.48 kB
text/typescript
/**
* Dev time server for front-end
*/
import config = require('../webpack.config');
import path = require('path');
import fs = require('fs');
import express = require('express');
import * as utils from "../common/utils";
import {getPort} from './utils/getPort';
const devtimeDetectionFile = __dirname + '/devtime.txt';
let webpackDevServerPort = 0;
let devTimeProxy: (req: express.Request, res: express.Response, next: Function) => void = null;
const bundleDevTimeProxy = () => {
if (devTimeProxy) return devTimeProxy;
/**
* Provide a proxy server that will pass your requests to webpack if a webpack port is found
*/
const httpProxy = require('http-proxy');
const proxyServer = httpProxy.createProxyServer();
devTimeProxy = function(req: express.Request, res: express.Response, next) {
if (!webpackDevServerPort) next();
proxyServer.web(req, res, {
target: `http://127.0.0.1:${webpackDevServerPort}`
});
proxyServer.on('error', (err) => {
console.log('[WDS] Proxy ERROR', err);
});
}
getPort(8888).then((port) => {
// console.log('found port', port); // DEBUG
webpackDevServerPort = port;
const Webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const notification = '[WDS]'; // Webpack dev server
/**
* Update the prod config for dev time ease
*/
const devConfig = Object.create(config);
// Makes sure errors in console map to the correct file and line number
devConfig.devtool = 'eval';
// Add aditional entry points
devConfig.entry = [
// For hot style updates
require.resolve('webpack/hot/dev-server'),
// The script refreshing the browser on hot updates
`${require.resolve('webpack-dev-server/client')}?http://127.0.0.1:${webpackDevServerPort}`,
// Also keep existing
].concat(config.entry);
// Add the Hot Replacement plugin for hot style updates
devConfig.plugins.push(new Webpack.HotModuleReplacementPlugin());
/**
* Standard webpack bundler stuff
*/
const compiler = Webpack(devConfig);
compiler.plugin('compile', function() {
console.log(`${notification} Bundling ..... `)
});
compiler.plugin('done', function(result) {
console.log(`${notification} Bundled in ${(result.endTime - result.startTime)} ms!`);
});
/**
* Wrap up the bundler in a dev server
*/
const bundler = new WebpackDevServer(compiler, {
// We need to tell Webpack to serve our bundled application
// from the build path. When proxying
publicPath: '/build/',
// Configure hot replacement
hot: true,
// The rest is terminal configurations
quiet: true,
noInfo: true,
stats: {
colors: true
}
});
/** Listen on all local address. If we don't then our `getPort` breaks on a mac */
bundler.listen(webpackDevServerPort, '0.0.0.0', function() {
console.log(`${notification} Server listening on port: ${webpackDevServerPort}`);
});
});
return devTimeProxy;
}
function bundleDeploy() {
// build
const Webpack = require('webpack');
const compiler = Webpack(config);
compiler.run((err, stats) => {
if (err) {
console.error('Failed to refresh bundle', err);
}
else {
console.log('Refreshed bundle');
}
});
}
function addDevHeaders(res: express.Response) {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
}
export function setup(app: express.Express) {
/**
* We always refresh the build bundle if it isn't there.
* This is to help *new repo clones* . NPM installs get this file by default.
*/
const outFile = path.join(config.output.path, config.output.filename);
if (!fs.existsSync(outFile)) {
bundleDeploy();
}
/**
* Check for devtime
*/
let devTime = fs.existsSync(devtimeDetectionFile);
if (devTime){
// if started with dev mode start the bundling process immediately
bundleDevTimeProxy();
}
/**
* Proxies to dev server if devtime
*/
app.all('/build/*', function(req, res, next) {
if (devTime) {
bundleDevTimeProxy()(req, res, next);
}
else {
next();
}
});
/**
* Disables caching if devtime
*/
app.use('/', function(req, res, next) {
if (devTime) {
addDevHeaders(res);
}
next();
});
/**
* Dev time vs. prod time toggling
*/
app.use('/dev', (req, res, next) => {
addDevHeaders(res);
devTime = true;
fs.writeFileSync(devtimeDetectionFile, 'If this file exists the server will start in dev mode');
res.send('Hot Reload setup!')
});
app.use('/prod', (req, res, next) => {
bundleDeploy();
addDevHeaders(res);
if (devTime) {
devTime = false;
fs.unlinkSync(devtimeDetectionFile);
}
res.send('Using static bundled files')
});
}