@hippy/debug-server-next
Version:
Debug server for hippy.
191 lines (190 loc) • 8.66 kB
JavaScript
;
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.saveDevPort = exports.normalizeWebpackConfig = exports.getWebpackConfig = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const os_1 = tslib_1.__importDefault(require("os"));
const hippy_hmr_plugin_1 = tslib_1.__importDefault(require("@hippy/hippy-hmr-plugin"));
const qrcode_1 = tslib_1.__importDefault(require("qrcode"));
const safe_1 = require("colors/safe");
const log_1 = require("@debug-server-next/utils/log");
const url_1 = require("@debug-server-next/utils/url");
const config_1 = require("@debug-server-next/config");
const ip_1 = require("@debug-server-next/utils/ip");
const port_1 = require("@debug-server-next/utils/port");
const process_1 = require("@debug-server-next/utils/process");
const enum_1 = require("@debug-server-next/@types/enum");
tslib_1.__exportStar(require("./inject-entry"), exports);
const log = new log_1.Logger('webpack-util');
async function getWebpackConfig(configPath) {
let webpackConfig;
const webpackConfigPath = path_1.default.resolve(process.cwd(), configPath);
if (configPath && fs_1.default.existsSync(webpackConfigPath)) {
webpackConfig = await (_a = webpackConfigPath, Promise.resolve().then(() => tslib_1.__importStar(require(_a))));
}
return (webpackConfig === null || webpackConfig === void 0 ? void 0 : webpackConfig.default) || webpackConfig;
}
exports.getWebpackConfig = getWebpackConfig;
function normalizeWebpackConfig(versionId, config) {
const enableRemoteDebug = isRemoteDebugEnabled(config);
if (!enableRemoteDebug)
return log.warn('remote debug is disabled!');
normalizeRemoteDebug(versionId, config);
appendHMRPlugin(versionId, config);
}
exports.normalizeWebpackConfig = normalizeWebpackConfig;
function normalizeRemoteDebug(versionId, config) {
config.devServer = {
// 默认为 false,设为 true 调试服务支持多个工程同时调试,彼此之间不会干扰
multiple: false,
// 默认为 false,hippy vue 项目可以手动开启
vueDevtools: false,
// 默认 hot, liveReload 都为 true,如果只想使用 live-reload 功能,请将 hot 设为 false,liveReload 设为 true
hot: true,
liveReload: true,
client: {
overlay: false,
},
autoLaunchHippyDebug: true,
injectJSDevtools: {
domains: []
},
...(config.devServer || {}),
};
config.devServer.remote = {
protocol: 'http',
host: '127.0.0.1',
port: 38989,
qrcode: false,
proxy: '',
...(config.devServer.remote || {}),
};
config.devServer.remote.port = Number(config.devServer.remote.port);
if (config.devServer.autoLaunchHippyDebug) {
autoLaunchHippyDebug(config.devServer.remote);
}
const { protocol, host, port, qrcode: qrcodeFn } = config.devServer.remote;
const publicPath = getPublicPath(versionId, config.devServer);
config.output.publicPath = publicPath;
log.info((0, safe_1.bold)((0, safe_1.yellow)(`webpack publicPath is set as: ${config.output.publicPath}`)));
const ignorePort = couldIgnorePort(protocol, port);
const bundleUrl = (0, url_1.makeUrl)(`${config.output.publicPath}index.bundle`, {
debugUrl: (0, url_1.makeUrl)(`${(0, url_1.getWSProtocolByHttpProtocol)(protocol)}://${host}${ignorePort ? '' : `:${port}`}/debugger-proxy`),
});
const homeUrl = `${protocol}://${host}${ignorePort ? '' : `:${port}`}/extensions/home.html?hash=${versionId}`;
config.devServer.cb = () => {
process.nextTick(() => {
// only print qrcode when use remote debug server
const needVersionId = needPublicPathWithVersionId(host, config.multiple);
if (needVersionId)
log.info('paste the following bundleUrl in app to open hippy page');
log.info('bundleUrl: %s', (0, safe_1.bold)((0, safe_1.green)(bundleUrl)));
log.info('find debug page on: %s', (0, safe_1.bold)((0, safe_1.green)(homeUrl)));
if (needVersionId && qrcodeFn && typeof qrcodeFn === 'function') {
const qrcodeStr = qrcodeFn(bundleUrl);
log.info('bundleUrl QRCode scheme: %s', (0, safe_1.bold)((0, safe_1.green)(qrcodeStr)));
qrcode_1.default.toString(qrcodeStr, {
small: true,
type: 'terminal',
}, (e, qrcodeStr) => {
if (e)
log.error('draw QRCode of bundleUrl failed: %j', (e === null || e === void 0 ? void 0 : e.stack) || e);
log.info('scheme qrcode:\n%s', qrcodeStr);
});
}
});
};
}
function appendHMRPlugin(versionId, config) {
const hotManifestPublicPath = getPublicPath(versionId, config.devServer);
const i = config.plugins.findIndex((plugin) => plugin.constructor.name === hippy_hmr_plugin_1.default.name);
if (i !== -1) {
config.plugins.splice(i, 1);
}
if (!config.devServer.hot && !config.devServer.liveReload)
return;
config.plugins.push(new hippy_hmr_plugin_1.default({ hotManifestPublicPath }));
}
/**
* remote debug is enabled by default if enable webpack-dev-server
*/
function isRemoteDebugEnabled(webpackConfig) {
return webpackConfig.mode === 'development' || webpackConfig.devServer;
}
/**
* when use debug-server-next in local, publicPath will append versionId if set devServer.multiple === true
* and will always append versionId for remote
*/
function needPublicPathWithVersionId(host, multiple) {
const isLocal = host === 'localhost' || host === '127.0.0.1';
if (isLocal)
return Boolean(multiple);
return true;
}
function getPublicPath(versionId, { remote: { host, port, protocol }, multiple }) {
const ignorePort = couldIgnorePort(protocol, port);
if (!needPublicPathWithVersionId(host, multiple))
return `${protocol}://${host}${ignorePort ? '' : `:${port}`}/`;
return `${protocol}://${host}${ignorePort ? '' : `:${port}`}/${versionId}/`;
}
function couldIgnorePort(protocol, port) {
const couldIgnore = (protocol === 'https' && Number(port) === 443) || (protocol === 'http' && Number(port) === 80);
log.silly(couldIgnore);
// TODO iOS doesn't support ignore port
return false;
}
/**
* hippy-dev process will save hmrPort to file,
* hippy-debug process will auto reverse hmrPort when device reconnect.
*/
async function saveDevPort(hmrPort) {
const { cachePath } = config_1.config;
fs_1.default.mkdirSync(cachePath, { recursive: true });
return fs_1.default.writeFileSync(config_1.config.hmrPortPath, String(hmrPort));
}
exports.saveDevPort = saveDevPort;
/**
* auto launch hippy:debug if remote.host is local hostname
*/
async function autoLaunchHippyDebug({ protocol, host, port }) {
if (protocol !== 'http')
return;
const hostList = await (0, ip_1.getAllLocalHostname)();
if (!hostList.includes(host))
return;
const inUse = await (0, port_1.isPortInUse)(port);
if (inUse) {
const osType = os_1.default.type();
let checkPortCMD;
if (osType === enum_1.OSType.Darwin)
checkPortCMD = `lsof -i :${port}`;
else if (osType === enum_1.OSType.Windows)
checkPortCMD = `netstat -aon|findstr "${port}"`;
return log.warn((0, safe_1.bold)((0, safe_1.yellow)(`hippy-debug port ${port} is in use, please check by run "${checkPortCMD}"`)));
}
const cp = await (0, process_1.exec)('node', [path_1.default.join(__dirname, '../../../dist/index-debug.js'), '--port', port]);
if (!global.__CHILD_PROCESS__)
global.__CHILD_PROCESS__ = [];
global.__CHILD_PROCESS__.push(cp);
}