UNPKG

@lark-project/cli

Version:

飞书项目插件开发工具

161 lines (160 loc) 9.3 kB
"use strict"; 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;