@fxext/cli
Version:
fanxing miniapp cli
196 lines (176 loc) • 6.45 kB
JavaScript
const fs = require("fs");
const path = require("path");
const https = require("https");
const httpProxy = require('http-proxy');
const inquirer = require('inquirer');
const qrcode = require('qrcode-terminal');
const connect = require("connect");
const harmon = require('harmon');
const getCertificate = require('./ssl/getCertificate');
const log = require('../log');
const { getLocalIP } = require('../utils');
const projectConfig = require('../project.config.json');
async function serve() {
let url = process.argv[2];
if (!url) {
url = 'http://localhost:7456';
}
const reg = new RegExp('(https?)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]');
if (!reg.test(url)) {
log.error("请输入正确的http调试地址");
return;
}
// 选择小程序模式
async function selectAppMode() {
const { miniAppMode, miniAppId } = await inquirer.prompt([
{
type: 'input',
message: '请输入小程序appId',
name: 'miniAppId',
validate: (value) => {
const appIdStr = String(value).trim();
if (appIdStr.length) {
return true;
}
return '请输入小程序appId';
}
},
{
type: 'list',
message: '请选项小程序模式',
name: 'miniAppMode',
choices: [
{
name: '主播模式'
},
{
name: '用户模式'
}
]
}
]);
return { miniAppMode, miniAppId };
}
// 获取项目配置,如果没有,则生成默认配置
const projectConfigPath = path.join(process.cwd(), 'project.config.json');
let config;
if (fs.existsSync(projectConfigPath)) {
config = JSON.parse(fs.readFileSync(projectConfigPath));
} else {
const gameName = path.basename(process.cwd());
projectConfig.name = gameName;
const { miniAppMode, miniAppId } = await selectAppMode();
projectConfig.builder.appMode = miniAppMode === '主播模式' ? 0 : 1;
projectConfig.builder.appId = miniAppId;
projectConfig.builder.buildConfig = [
{
layoutType: 'm',
framework: 'cocos'
},
{
layoutType: 'streamer_pc',
framework: 'cocos'
}
];
fs.writeFileSync(projectConfigPath, JSON.stringify( projectConfig, null, 2));
config = projectConfig;
}
const app = connect();
const selects = [];
const simpleselect = {};
const { sdkVersion, appId, appMode = 0, sdkType, version, buildConfig, https: useHttps } = config.builder;
let sdkFileName = appMode === 1 ? 'fx-ext-user.js' : 'fx-ext.js';
if (sdkType === 'partner') {
sdkFileName = 'fx-ext-partner.js';
}
// 需要插入html - head里面的内容
const insertHTML = [
`<meta
http-equiv="Content-Security-Policy"
content="connect-src 'self' https://*.kgimg.com https://*.kugou.com; default-src 'self' https://*.kgimg.com https://*.kugou.com; block-all-mixed-content; img-src 'self' https://*.kgimg.com https://*.kugou.com; font-src 'self' https://*.kgimg.com https://*.kugou.com; style-src 'self' https://*.kgimg.com https://*.kugou.com 'unsafe-inline'; script-src 'unsafe-eval' 'unsafe-inline' 'self' https://*.kgimg.com https://*.kugou.com; frame-src https://fanxing.kugou.com https://mfanxing.kugou.com https://localhost:*; object-src 'none';"
/>`,
`<script src="https://s4fx.kgimg.com/pub2/fx-ext/${sdkVersion}/${sdkFileName}"></script>`
]
simpleselect.query = 'title';
simpleselect.func = function (node) {
let insert = `<title>${config.name}</title>`;
insertHTML.forEach(item => {
insert += item;
});
node.createWriteStream({
outer: true
}).end(insert);
}
selects.push(simpleselect);
app.use(harmon([], selects, true));
const proxy = httpProxy.createProxyServer({
target: url
});
app.use('/streamer_pc.html', function (req, res) {
proxy.web(req, res);
});
app.use('/index.html', function (req, res) {
proxy.web(req, res);
});
app.use('/m/app.json', function (req, res) {
const appJsonPath = path.join(process.cwd(), './m/app.json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('content-type', 'application/json');
if (fs.existsSync(appJsonPath)) {
res.end(fs.readFileSync(appJsonPath));
} else {
res.statusCode = 404;
res.end();
}
});
app.use('/streamer_pc/app.json', function (req, res) {
const appJsonPath = path.join(process.cwd(), './streamer_pc/app.json');
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('content-type', 'application/json');
if (fs.existsSync(appJsonPath)) {
res.end(fs.readFileSync(appJsonPath));
} else {
res.statusCode = 404;
res.end();
}
});
app.use('/', function (req, res) {
proxy.web(req, res);
});
const selfSignCert = getCertificate();
const server = https.createServer({
key : selfSignCert,
cert: selfSignCert
}, app).listen(config.builder.port, config.builder.host === 'localhost' ? '0.0.0.0' : config.builder.host);
server.on('upgrade', function(req, socket, head) {
proxy.ws(req, socket, head);
});
const { port, host } = config.builder;
const mode = appMode === '主播模式' ? 0 : 1;
const qrcodeUrl = `https://${getLocalIP()}:${port}/index.html?type=miniapp&miniAppId=${appId}&appMode=${mode}`;
qrcode.generate(qrcodeUrl, { small: true });
log.hint('\nAPP端调试二维码,详情查看:https://fanxing.kugou.com/open/doc/pages/develop/debug/app.html\n');
if (version >= 2) {
const messages = [
`App running at:`,
`- 本地IP地址: ${getLocalIP()}`,
`- 开发端口号: ${port}`,
'请将该信息配置到开发者中心',
'',
`本地服务:`
];
for (const entryItem of buildConfig) {
if (entryItem.framework === 'cocos') {
if (entryItem.layoutType === 'm') {
messages.push(`Web面板:${useHttps ? 'https' : 'http'}://${host}:${port}/index.html`);
} else if (entryItem.layoutType === 'streamer_pc') {
messages.push(`伴侣面板:${useHttps ? 'https' : 'http'}://${host}:${port}/streamer_pc.html`);
}
}
}
log.hint(messages.join('\n'));
} else {
log.hint(`App running at:\n- Local: https://${host}:${port}\n- Network: https://${getLocalIP()}:${port}\n- 请将该信息配置到开发者中心`);
}
}
module.exports = serve;