You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
493 lines
15 KiB
493 lines
15 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
|
|
function _react() {
|
|
const data = _interopRequireDefault(require("react"));
|
|
|
|
_react = function _react() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _core() {
|
|
const data = require("@umijs/core");
|
|
|
|
_core = function _core() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _utils() {
|
|
const data = require("@umijs/utils");
|
|
|
|
_utils = function _utils() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _express() {
|
|
const data = _interopRequireDefault(require("express"));
|
|
|
|
_express = function _express() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _httpProxyMiddleware() {
|
|
const data = require("http-proxy-middleware");
|
|
|
|
_httpProxyMiddleware = function _httpProxyMiddleware() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function http() {
|
|
const data = _interopRequireWildcard(require("http"));
|
|
|
|
http = function http() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _spdy() {
|
|
const data = _interopRequireDefault(require("spdy"));
|
|
|
|
_spdy = function _spdy() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function url() {
|
|
const data = _interopRequireWildcard(require("url"));
|
|
|
|
url = function url() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _compression() {
|
|
const data = _interopRequireDefault(require("compression"));
|
|
|
|
_compression = function _compression() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _sockjs() {
|
|
const data = _interopRequireDefault(require("sockjs"));
|
|
|
|
_sockjs = function _sockjs() {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
var _utils2 = require("./utils");
|
|
|
|
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
|
|
|
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
|
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
|
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
|
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
|
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
|
|
const logger = new (_core().Logger)('@umijs/server');
|
|
const debug = (0, _utils().createDebug)('umi:server:Server');
|
|
const defaultOpts = {
|
|
afterMiddlewares: [],
|
|
beforeMiddlewares: [],
|
|
compilerMiddleware: null,
|
|
compress: true,
|
|
// enable by default if add HTTP2
|
|
https: !!process.env.HTTP2 ? true : !!process.env.HTTPS,
|
|
onListening: argv => argv,
|
|
onConnection: () => {},
|
|
onConnectionClose: () => {},
|
|
proxy: null,
|
|
headers: {},
|
|
// not use
|
|
host: 'localhost',
|
|
port: 8000,
|
|
writeToDisk: false
|
|
};
|
|
|
|
class Server {
|
|
constructor(opts) {
|
|
this.sockets = []; // Proxy sockets
|
|
|
|
this.socketProxies = [];
|
|
this.opts = _objectSpread({}, defaultOpts, {}, _utils().lodash.omitBy(opts, _utils().lodash.isUndefined));
|
|
this.app = (0, _express().default)();
|
|
this.setupFeatures();
|
|
this.createServer();
|
|
this.socketProxies.forEach(wsProxy => {
|
|
// subscribe to http 'upgrade'
|
|
// @ts-ignore
|
|
this.listeningApp.on('upgrade', wsProxy.upgrade);
|
|
}, this);
|
|
}
|
|
|
|
getHttpsOptions() {
|
|
if (this.opts.https) {
|
|
const credential = (0, _utils2.getCredentials)(this.opts); // note that options.spdy never existed. The user was able
|
|
// to set options.https.spdy before, though it was not in the
|
|
// docs. Keep options.https.spdy if the user sets it for
|
|
// backwards compatibility, but log a deprecation warning.
|
|
|
|
if (typeof this.opts.https === 'object' && this.opts.https.spdy) {
|
|
// for backwards compatibility: if options.https.spdy was passed in before,
|
|
// it was not altered in any way
|
|
logger.warn('Providing custom spdy server options is deprecated and will be removed in the next major version.');
|
|
return credential;
|
|
} else {
|
|
return _objectSpread({
|
|
spdy: {
|
|
protocols: ['h2', 'http/1.1']
|
|
}
|
|
}, credential);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
setupFeatures() {
|
|
const features = {
|
|
compress: () => {
|
|
if (this.opts.compress) {
|
|
this.setupCompress();
|
|
}
|
|
},
|
|
headers: () => {
|
|
if (_utils().lodash.isPlainObject(this.opts.headers)) {
|
|
this.setupHeaders();
|
|
}
|
|
},
|
|
beforeMiddlewares: () => {
|
|
this.opts.beforeMiddlewares.forEach(middleware => {
|
|
// @ts-ignore
|
|
this.app.use(middleware);
|
|
});
|
|
},
|
|
proxy: () => {
|
|
if (this.opts.proxy) {
|
|
this.setupProxy();
|
|
}
|
|
},
|
|
compilerMiddleware: () => {
|
|
if (this.opts.compilerMiddleware) {
|
|
// @ts-ignore
|
|
this.app.use(this.opts.compilerMiddleware);
|
|
}
|
|
},
|
|
afterMiddlewares: () => {
|
|
this.opts.afterMiddlewares.forEach(middleware => {
|
|
// @ts-ignore
|
|
this.app.use(middleware);
|
|
});
|
|
}
|
|
};
|
|
Object.keys(features).forEach(stage => {
|
|
features[stage]();
|
|
});
|
|
}
|
|
/**
|
|
* response headers
|
|
*/
|
|
|
|
|
|
setupHeaders() {
|
|
this.app.all('*', (req, res, next) => {
|
|
// eslint-disable-next-line
|
|
res.set(this.opts.headers);
|
|
next();
|
|
});
|
|
}
|
|
/**
|
|
* dev server compress to gzip assets
|
|
*/
|
|
|
|
|
|
setupCompress() {
|
|
const compressOpts = _utils().lodash.isBoolean(this.opts.compress) ? {} : this.opts.compress;
|
|
this.app.use((0, _compression().default)(compressOpts));
|
|
}
|
|
|
|
deleteRoutes() {
|
|
let startIndex = null;
|
|
let endIndex = null;
|
|
|
|
this.app._router.stack.forEach((item, index) => {
|
|
if (item.name === 'PROXY_START') startIndex = index;
|
|
if (item.name === 'PROXY_END') endIndex = index;
|
|
});
|
|
|
|
debug(`routes before changed: ${this.app._router.stack.map(item => item.name || 'undefined name').join(', ')}`);
|
|
|
|
if (startIndex !== null && endIndex !== null) {
|
|
this.app._router.stack.splice(startIndex, endIndex - startIndex + 1);
|
|
}
|
|
|
|
debug(`routes after changed: ${this.app._router.stack.map(item => item.name || 'undefined name').join(', ')}`);
|
|
}
|
|
/**
|
|
* proxy middleware for dev
|
|
* not coupled with build tools (like webpack, rollup, ...)
|
|
*/
|
|
|
|
|
|
setupProxy(proxyOpts, isWatch = false) {
|
|
let proxy = proxyOpts || this.opts.proxy;
|
|
|
|
if (!Array.isArray(proxy)) {
|
|
if (proxy && 'target' in proxy) {
|
|
proxy = [proxy];
|
|
} else {
|
|
proxy = Object.keys(proxy || {}).map(context => {
|
|
var _proxy;
|
|
|
|
let proxyOptions; // For backwards compatibility reasons.
|
|
|
|
const correctedContext = context.replace(/^\*$/, '**').replace(/\/\*$/, '');
|
|
|
|
if (typeof ((_proxy = proxy) === null || _proxy === void 0 ? void 0 : _proxy[context]) === 'string') {
|
|
proxyOptions = {
|
|
context: correctedContext,
|
|
target: proxy[context]
|
|
};
|
|
} else {
|
|
var _proxy2;
|
|
|
|
proxyOptions = _objectSpread({}, ((_proxy2 = proxy) === null || _proxy2 === void 0 ? void 0 : _proxy2[context]) || {}, {
|
|
context: correctedContext
|
|
});
|
|
}
|
|
|
|
proxyOptions.logLevel = proxyOptions.logLevel || 'warn';
|
|
return proxyOptions;
|
|
});
|
|
}
|
|
}
|
|
|
|
const getProxyMiddleware = proxyConfig => {
|
|
const context = proxyConfig.context || proxyConfig.path; // It is possible to use the `bypass` method without a `target`.
|
|
// However, the proxy middleware has no use in this case, and will fail to instantiate.
|
|
|
|
if (proxyConfig.target) {
|
|
return (0, _httpProxyMiddleware().createProxyMiddleware)(context, _objectSpread({}, proxyConfig, {
|
|
onProxyRes(proxyRes, req, res) {
|
|
var _URL, _proxyConfig$onProxyR;
|
|
|
|
const target = typeof proxyConfig.target === 'object' ? url().format(proxyConfig.target) : proxyConfig.target;
|
|
const realUrl = ((_URL = new URL(req.url || '', target)) === null || _URL === void 0 ? void 0 : _URL.href) || '';
|
|
proxyRes.headers['x-real-url'] = realUrl;
|
|
(_proxyConfig$onProxyR = proxyConfig.onProxyRes) === null || _proxyConfig$onProxyR === void 0 ? void 0 : _proxyConfig$onProxyR.call(proxyConfig, proxyRes, req, res);
|
|
}
|
|
|
|
}));
|
|
}
|
|
|
|
return;
|
|
}; // refresh proxy config
|
|
|
|
|
|
let startIndex = null;
|
|
let endIndex = null;
|
|
let routesLength = null; // when proxy opts change, delete before proxy middlwares
|
|
|
|
if (isWatch) {
|
|
this.app._router.stack.forEach((item, index) => {
|
|
if (item.name === 'PROXY_START') startIndex = index;
|
|
if (item.name === 'PROXY_END') endIndex = index;
|
|
});
|
|
|
|
if (startIndex !== null && endIndex !== null) {
|
|
this.app._router.stack.splice(startIndex, endIndex - startIndex + 1);
|
|
}
|
|
|
|
routesLength = this.app._router.stack.length;
|
|
this.deleteRoutes();
|
|
} // log proxy middleware before
|
|
|
|
|
|
this.app.use(function PROXY_START(req, res, next) {
|
|
next();
|
|
});
|
|
proxy.forEach(proxyConfigOrCallback => {
|
|
let proxyMiddleware;
|
|
let proxyConfig = typeof proxyConfigOrCallback === 'function' ? proxyConfigOrCallback() : proxyConfigOrCallback;
|
|
proxyMiddleware = getProxyMiddleware(proxyConfig);
|
|
|
|
if (proxyConfig.ws && proxyMiddleware) {
|
|
this.socketProxies.push(proxyMiddleware);
|
|
}
|
|
|
|
this.app.use((req, res, next) => {
|
|
if (typeof proxyConfigOrCallback === 'function') {
|
|
const newProxyConfig = proxyConfigOrCallback();
|
|
|
|
if (newProxyConfig !== proxyConfig) {
|
|
proxyConfig = newProxyConfig;
|
|
proxyMiddleware = getProxyMiddleware(proxyConfig);
|
|
}
|
|
} // - Check if we have a bypass function defined
|
|
// - In case the bypass function is defined we'll retrieve the
|
|
// bypassUrl from it otherwise bypassUrl would be null
|
|
|
|
|
|
const bypassUrl = _utils().lodash.isFunction(proxyConfig.bypass) ? proxyConfig.bypass(req, res, proxyConfig) : null;
|
|
|
|
if (typeof bypassUrl === 'boolean') {
|
|
// skip the proxy
|
|
// @ts-ignore
|
|
req.url = null;
|
|
next();
|
|
} else if (typeof bypassUrl === 'string') {
|
|
// byPass to that url
|
|
req.url = bypassUrl;
|
|
next();
|
|
} else if (proxyMiddleware) {
|
|
return proxyMiddleware(req, res, next);
|
|
} else {
|
|
next();
|
|
}
|
|
});
|
|
});
|
|
this.app.use(function PROXY_END(req, res, next) {
|
|
next();
|
|
}); // log proxy middleware after
|
|
|
|
if (isWatch) {
|
|
const newRoutes = this.app._router.stack.splice(routesLength, this.app._router.stack.length - routesLength);
|
|
|
|
this.app._router.stack.splice(startIndex, 0, ...newRoutes);
|
|
}
|
|
}
|
|
|
|
sockWrite({
|
|
sockets = this.sockets,
|
|
type,
|
|
data
|
|
}) {
|
|
sockets.forEach(socket => {
|
|
socket.write(JSON.stringify({
|
|
type,
|
|
data
|
|
}));
|
|
});
|
|
}
|
|
|
|
createServer() {
|
|
const httpsOpts = this.getHttpsOptions();
|
|
|
|
if (httpsOpts) {
|
|
// http2 using spdy, HTTP/2 by default when using https
|
|
this.listeningApp = _spdy().default.createServer(httpsOpts, this.app);
|
|
} else {
|
|
this.listeningApp = http().createServer(this.app);
|
|
}
|
|
}
|
|
|
|
listen({
|
|
port = 8000,
|
|
hostname
|
|
}) {
|
|
var _this = this;
|
|
|
|
return _asyncToGenerator(function* () {
|
|
const foundPort = yield _utils().portfinder.getPortPromise({
|
|
port
|
|
});
|
|
return new Promise(resolve => {
|
|
_this.listeningApp.listen(foundPort, hostname, 5, () => {
|
|
_this.createSocketServer();
|
|
|
|
const ret = {
|
|
port: foundPort,
|
|
hostname,
|
|
listeningApp: _this.listeningApp,
|
|
server: _this
|
|
};
|
|
|
|
_this.opts.onListening(ret);
|
|
|
|
resolve(ret);
|
|
});
|
|
});
|
|
})();
|
|
}
|
|
|
|
createSocketServer() {
|
|
const server = _sockjs().default.createServer({
|
|
log: (severity, line) => {
|
|
if (line.includes('bound to')) return; // console.log(`${chalk.gray('[sockjs]')} ${line}`);
|
|
}
|
|
});
|
|
|
|
server.installHandlers(this.listeningApp, {
|
|
prefix: '/dev-server'
|
|
});
|
|
server.on('connection', connection => {
|
|
// Windows connection might be undefined
|
|
// https://github.com/webpack/webpack-dev-server/issues/2199
|
|
// https://github.com/sockjs/sockjs-node/issues/121
|
|
// https://github.com/meteor/meteor/pull/10891/files
|
|
if (!connection) {
|
|
return;
|
|
}
|
|
|
|
this.opts.onConnection({
|
|
connection,
|
|
server: this
|
|
});
|
|
this.sockets.push(connection);
|
|
connection.on('close', () => {
|
|
this.opts.onConnectionClose({
|
|
connection
|
|
});
|
|
const index = this.sockets.indexOf(connection);
|
|
|
|
if (index >= 0) {
|
|
this.sockets.splice(index, 1);
|
|
}
|
|
});
|
|
});
|
|
this.socketServer = server;
|
|
}
|
|
|
|
}
|
|
|
|
var _default = Server;
|
|
exports.default = _default; |