"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;