@lark-project/cli
Version:
飞书项目插件开发工具
161 lines (160 loc) • 9.3 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startProject = void 0;
const cheerio = __importStar(require("cheerio"));
const qrcode_1 = __importDefault(require("qrcode"));
const webpack_1 = __importStar(require("webpack"));
const webpack_dev_server_1 = __importDefault(require("webpack-dev-server"));
const constants_1 = require("../../../constants");
const get_plugin_profile_for_v2_1 = require("../../../get-plugin-profile-for-v2");
const types_1 = require("../../../types");
const env_1 = require("../../../utils/env");
const generate_html_entry_script_1 = require("../../../utils/generate-html-entry-script");
const ip_1 = require("../../../utils/ip");
const kill_port_1 = require("../../../utils/kill-port");
const logger_1 = require("../../../utils/logger");
const resolve_project_path_1 = require("../../../utils/resolve-project-path");
const update_point_config_origin_1 = require("../../../utils/update-point-config-origin");
const preflight_local_config_1 = require("../../../utils/preflight-local-config");
const check_local_config_drift_1 = require("../../../utils/check-local-config-drift");
const utils_1 = require("../../../v1/utils");
const webpack_config_react_1 = require("../../webpack/custom-ui/webpack.config.react");
const webpack_dev_server_config_1 = require("../../webpack/dev-server/webpack-dev-server.config");
const open_browser_1 = require("../../../utils/open-browser");
const find_entries_1 = require("../find-entries");
const download_html_tpl_1 = require("./download-html-tpl");
async function startProject(payload) {
await (0, kill_port_1.killPort)(constants_1.DEV_SERVER_PORT);
await (0, update_point_config_origin_1.getConfigSource)(payload === null || payload === void 0 ? void 0 : payload.source_type);
await (0, preflight_local_config_1.preflightLocalConfig)();
(0, check_local_config_drift_1.checkLocalConfigDrift)();
const pluginProfile = await (0, get_plugin_profile_for_v2_1.getPluginProfileForV2)();
const [needBuildResources, missedResourceIds] = (0, find_entries_1.findEntries)(pluginProfile);
if (missedResourceIds.length) {
logger_1.logger.warn(`The resource entries for these ids (${missedResourceIds.join(', ')}) is missing in plugin.config.json.`);
}
if (!needBuildResources.length) {
// resources 为空 = 没有任何前端渲染点位(webhook 形态:intercept / listen_event /
// ai_field / 无卡片 ai_node 等)——合法状态,业务跑在开发者自己的后端 webhook 上,
// 没有可本地预览的前端产物。不报错,提示用户去 publish。
if (!pluginProfile.resources.length) {
logger_1.logger.info('This plugin has no frontend artifact to preview locally — it is webhook-only (its behavior runs on your backend).');
logger_1.logger.info('Make sure your webhook callback endpoint(s) are reachable, then run "lpm publish" to release.');
return;
}
// resources 非空但没有前端 feature 引用它们 —— 配置不一致,照旧报错
logger_1.logger.error('No resources need to build, please check the plugin.config.json / developer platform and retry.');
process.exit(1);
}
// 拉取 HTML 模板
const firstWebFeature = pluginProfile.features.find(f => { var _a, _b; return (_b = (_a = f[types_1.EFeaturePlatform.web]) === null || _a === void 0 ? void 0 : _a.resourceId) === null || _b === void 0 ? void 0 : _b.resource; });
const firstMobileFeature = pluginProfile.features.find(f => { var _a, _b; return (_b = (_a = f[types_1.EFeaturePlatform.mobile]) === null || _a === void 0 ? void 0 : _a.resourceId) === null || _b === void 0 ? void 0 : _b.resource; });
const downloadTplTasks = [];
if (firstWebFeature) {
downloadTplTasks.push((0, download_html_tpl_1.downloadHTMLTemplateAndCache)({
pageServerDomain: pluginProfile.pageServerDomain,
pluginId: pluginProfile.id,
platform: types_1.EFeaturePlatform.web,
resourceId: firstWebFeature[types_1.EFeaturePlatform.web].resourceId.resource,
}));
}
if (firstMobileFeature) {
downloadTplTasks.push((0, download_html_tpl_1.downloadHTMLTemplateAndCache)({
pageServerDomain: pluginProfile.pageServerDomain,
pluginId: pluginProfile.id,
platform: types_1.EFeaturePlatform.mobile,
resourceId: firstMobileFeature[types_1.EFeaturePlatform.mobile].resourceId.resource,
}));
}
await (0, utils_1.wrapOraLoading)(() => Promise.all(downloadTplTasks), 'downloading the html template...');
const webpackConfigs = needBuildResources.map(resource => {
const { id, entry } = resource;
const platform = pluginProfile.findFirstFeaturePlatformByResourceId(id);
return (0, webpack_config_react_1.getWebpackConfigForReact)({
key: id,
webpackEnv: 'development',
entry: (0, resolve_project_path_1.resolveProjectPath)(entry),
generateHtmlTemplate: (jsFiles, cssFiles) => {
const htmlTpl = (0, download_html_tpl_1.getCachedHTMLByPlatform)(platform);
const $ = cheerio.load(htmlTpl);
const entryScript = (0, generate_html_entry_script_1.generateHTMLEntryScript)(jsFiles, cssFiles);
$(entryScript).prependTo($('head'));
const finalHTML = $.html();
return finalHTML;
},
});
});
logger_1.logger.debug(JSON.stringify(webpackConfigs, null, 0));
const multiCompiler = new webpack_1.MultiCompiler(webpackConfigs.map(c => (0, webpack_1.default)(c)), { parallelism: 3 });
let isFirstCompileDone = true;
multiCompiler.hooks.done.tap('LPM_START_MULTI_COMPILER_DONE', () => {
// rebuild 不打印二维码
if (!isFirstCompileDone) {
return;
}
isFirstCompileDone = false;
// 有移动端产物才打印二维码
if (pluginProfile.hasMobileFeature()) {
const url = new URL(`${pluginProfile.siteDomain}/openapp/plugin/dev/m`);
// 避免 siteDomain 带了 /,替换掉多余的 /
url.pathname = url.pathname.replace(/\/+/g, '/');
let localIPv4 = env_1.env.originForDevServer;
// 当用户指定 devServer 返回资源的 origin,则不取本地 ipv4 地址
if (!localIPv4) {
localIPv4 = (0, ip_1.getNotLoopBackIpv4)();
}
const localAddress = `${env_1.env.disableHttps ? 'http' : 'https'}://${localIPv4}:${constants_1.DEV_SERVER_PORT}`;
const qrCodeUrl = `${url.toString()}?plugin_id=${pluginProfile.id}&local_address=${localAddress}`;
logger_1.logger.debug(qrCodeUrl);
qrcode_1.default.toString(qrCodeUrl, { type: 'terminal', small: true }, function (err, url) {
console.log('\n');
console.log(url);
console.log('Please use Lark App scan the QRCode above, debug your plugin in the app. \n');
});
}
// --auto: 自动打开浏览器调试页面
if (payload === null || payload === void 0 ? void 0 : payload.auto) {
const debugUrl = new URL(pluginProfile.siteDomain);
debugUrl.searchParams.set('plugin_debugging', 'true');
const debugUrlStr = debugUrl.toString();
logger_1.logger.success(`Debug URL: ${debugUrlStr}`);
(0, open_browser_1.openBrowser)(debugUrlStr);
}
});
const webpackDevServerConfig = await (0, webpack_dev_server_config_1.getWebpackDevServerConfig)();
logger_1.logger.debug(JSON.stringify(webpackDevServerConfig, null, 0));
const devServer = new webpack_dev_server_1.default(webpackDevServerConfig, multiCompiler);
devServer.startCallback(() => {
logger_1.logger.success('Starting the development server...');
});
devServer.stopCallback(() => {
logger_1.logger.success('The development server stoped.');
});
}
exports.startProject = startProject;