diff --git a/packages/faas-cli-plugin-invoke/package.json b/packages/faas-cli-plugin-invoke/package.json index 992646b25bd1..c5ff61e94cac 100644 --- a/packages/faas-cli-plugin-invoke/package.json +++ b/packages/faas-cli-plugin-invoke/package.json @@ -12,7 +12,6 @@ "@midwayjs/runtime-mock": "^0.2.65", "@midwayjs/serverless-fc-starter": "^0.2.65", "@midwayjs/serverless-fc-trigger": "^0.2.65", - "@midwayjs/serverless-invoke": "^0.2.67", "@midwayjs/serverless-scf-starter": "^0.2.65", "@midwayjs/serverless-scf-trigger": "^0.2.65", "@midwayjs/serverless-spec-builder": "^0.2.66", diff --git a/packages/serverless-invoke/package.json b/packages/serverless-invoke/package.json index 1452c06cf4de..cd3332905e31 100644 --- a/packages/serverless-invoke/package.json +++ b/packages/serverless-invoke/package.json @@ -4,19 +4,7 @@ "main": "dist/index", "typings": "dist/index.d.ts", "dependencies": { - "@midwayjs/faas-util-ts-compile": "^0.2.67", - "@midwayjs/fcli-command-core": "^0.2.67", - "@midwayjs/locate": "^1.0.3", - "@midwayjs/mwcc": "^0.1.9", - "@midwayjs/runtime-engine": "^0.2.65", - "@midwayjs/runtime-mock": "^0.2.65", - "@midwayjs/serverless-fc-starter": "^0.2.65", - "@midwayjs/serverless-fc-trigger": "^0.2.65", - "@midwayjs/serverless-scf-starter": "^0.2.65", - "@midwayjs/serverless-scf-trigger": "^0.2.65", - "@midwayjs/serverless-spec-builder": "^0.2.66", - "fs-extra": "^8.1.0", - "globby": "^10.0.1" + "@midwayjs/fcli-plugin-invoke": "^0.2.68" }, "devDependencies": { "@midwayjs/faas": "^0.2.65", diff --git a/packages/serverless-invoke/src/core.ts b/packages/serverless-invoke/src/core.ts deleted file mode 100644 index 711d81f2e2ee..000000000000 --- a/packages/serverless-invoke/src/core.ts +++ /dev/null @@ -1,260 +0,0 @@ -/* - 单进程模式的invoke - invoke -> (trigger)-> invokeCore -> entrence -> userCode[ts build] - 1. 用户调用invoke - 2. tsc编译用户代码到dist目录 - 3. 开源版: 【创建runtime、创建trigger】封装为平台invoke包,提供getInvoke方法,会传入args与入口方法,返回invoke方法 -*/ -import { FaaSStarterClass, cleanTarget } from './utils'; -import { join, resolve, relative } from 'path'; -import { - existsSync, - writeFileSync, - ensureFileSync, - remove, -} from 'fs-extra'; -import { loadSpec, getSpecFile } from '@midwayjs/fcli-command-core'; -import { writeWrapper } from '@midwayjs/serverless-spec-builder'; -import { AnalyzeResult, Locator } from '@midwayjs/locate'; -import { - compareFileChange, - copyFiles, -} from '@midwayjs/faas-util-ts-compile'; -import { compileWithOptions, compileInProject } from '@midwayjs/mwcc'; -import { IInvoke } from './interface'; -const lockMap = {}; -interface InvokeOptions { - baseDir?: string; // 目录,默认为process.cwd - functionName: string; // 函数名 - handler?: string; // 函数的handler方法 - trigger?: string; // 触发器 - buildDir?: string; // 构建目录 - sourceDir?: string; // 函数源码目录 - incremental?: boolean; // 开启增量编译 (会无视 clean true) - clean?: boolean; // 清理调试目录 - verbose?: boolean; // 输出详细日志 -} - -export abstract class InvokeCore implements IInvoke { - options: InvokeOptions; - baseDir: string; - starter: any; - spec: any; - buildDir: string; - wrapperInfo: any; - specFile: string; - codeAnalyzeResult: AnalyzeResult; - - constructor(options: InvokeOptions) { - options = this.formatOptions(options); - this.options = options; - this.baseDir = this.options.baseDir; - this.buildDir = resolve(this.baseDir, options.buildDir || 'dist'); - this.spec = loadSpec(this.baseDir); - this.specFile = getSpecFile(this.baseDir).path; - } - - protected async getStarter() { - if (this.starter) { - return this.starter; - } - const { functionName } = this.options; - const starter = new FaaSStarterClass({ - baseDir: this.buildDir, - functionName, - }); - await starter.start(); - this.starter = starter; - return this.starter; - } - - // 获取用户代码中的函数方法 - protected async getUserFaaSHandlerFunction() { - const handler = - this.options.handler || this.getFunctionInfo().handler || ''; - const starter = await this.getStarter(); - return starter.handleInvokeWrapper(handler); - } - - protected getFunctionInfo(functionName?: string) { - functionName = functionName || this.options.functionName; - return ( - (this.spec && this.spec.functions && this.spec.functions[functionName]) || - {} - ); - } - - abstract async getInvokeFunction(); - - waitForTsBuild(buildLogPath, count?) { - count = count || 0; - return new Promise(resolve => { - if (count > 100) { - return resolve(); - } - if (lockMap[buildLogPath] === 'waiting') { - setTimeout(() => { - this.waitForTsBuild(buildLogPath, count + 1).then(resolve); - }, 300); - } else { - resolve(); - } - }); - } - - protected async buildTS() { - const { baseDir } = this.options; - const tsconfig = resolve(baseDir, 'tsconfig.json'); - // 非ts - if (!existsSync(tsconfig)) { - return; - } - // 设置走编译,扫描 dist 目录 - process.env.MIDWAY_TS_MODE = 'false'; - const debugRoot = this.options.buildDir || '.faas_debug_tmp'; - // 分析目录结构 - const locator = new Locator(baseDir); - this.codeAnalyzeResult = await locator.run({ - tsCodeRoot: this.options.sourceDir, - tsBuildRoot: debugRoot, - }); - this.buildDir = this.codeAnalyzeResult.tsBuildRoot; - if (!this.codeAnalyzeResult.tsBuildRoot) { - return; - } - const buildLogPath = resolve(this.buildDir, '.faasTSBuildTime.log'); - if (!lockMap[buildLogPath]) { - lockMap[buildLogPath] = 'waiting'; - } else if (lockMap[buildLogPath] === 'waiting') { - await this.waitForTsBuild(buildLogPath); - } - if (existsSync(buildLogPath)) { - const fileChanges = await compareFileChange( - [ - this.specFile, - `${relative(baseDir, this.codeAnalyzeResult.tsCodeRoot) || '.'}/**/*`, - ], - [buildLogPath], - { cwd: baseDir } - ); - if (!fileChanges || !fileChanges.length) { - lockMap[buildLogPath] = true; - this.debug('Auto skip ts compile'); - return; - } - } - lockMap[buildLogPath] = 'waiting'; - ensureFileSync(buildLogPath); - writeFileSync(buildLogPath, `ts build at ${Date.now()}`); - // clean directory first - if (this.options.clean) { - await cleanTarget(this.buildDir); - } - try { - if (this.codeAnalyzeResult.integrationProject) { - await compileWithOptions(baseDir, join(this.buildDir, 'dist'), { - include: [this.codeAnalyzeResult.tsCodeRoot] - }); - } else { - await compileInProject(this.baseDir, join(this.buildDir, 'dist')); - } - } catch (e) { - await remove(buildLogPath); - lockMap[buildLogPath] = false; - console.log(e); - throw new Error(`Typescript Build Error, Please Check Your FaaS Code!`); - } - lockMap[buildLogPath] = true; - // 针对多次调用清理缓存 - Object.keys(require.cache).forEach(path => { - if (path.indexOf(this.buildDir) !== -1) { - delete require.cache[path]; - } - }); - } - - public async invoke(...args: any) { - await this.copyFile(); - await this.buildTS(); - const invoke = await this.getInvokeFunction(); - const result = await invoke(...args); - if (this.options.clean) { - await cleanTarget(this.buildDir); - } - return result; - } - - private async invokeError(err) { - console.log('[faas invoke error]'); - console.log(err); - process.exit(1); - } - - protected async loadHandler(starter: string) { - const wrapperInfo = await this.makeWrapper(starter); - const { fileName, handlerName } = wrapperInfo; - this.wrapperInfo = wrapperInfo; - try { - const handler = require(fileName); - return handler[handlerName]; - } catch (e) { - this.invokeError(e); - } - } - - protected async copyFile() { - const packageObj: any = this.spec.package || {}; - return copyFiles({ - sourceDir: this.baseDir, - targetDir: this.buildDir, - include: packageObj.include, - exclude: packageObj.exclude, - log: path => { - this.debug('copy file', path); - }, - }); - } - - // 写入口 - private async makeWrapper(starter: string) { - const funcInfo = this.getFunctionInfo(); - const [handlerFileName, name] = funcInfo.handler.split('.'); - const fileName = resolve(this.buildDir, `${handlerFileName}.js`); - - writeWrapper({ - baseDir: this.baseDir, - service: { - layers: this.spec.layers, - functions: { [this.options.functionName]: funcInfo }, - }, - distDir: this.buildDir, - starter, - }); - return { fileName, handlerName: name }; - } - - protected wrapperHandler(handler) { - return handler; - } - - private formatOptions(options: InvokeOptions) { - if (!options.baseDir) { - options.baseDir = process.cwd(); - } - // 开启增量编译,则不自动清理目录 - if (options.incremental) { - options.clean = false; - } - if (options.clean !== false) { - options.clean = true; - } - return options; - } - - debug(...args) { - if (!this.options.verbose) { - return; - } - console.log('[Verbose] ', ...args); - } -} diff --git a/packages/serverless-invoke/src/index.ts b/packages/serverless-invoke/src/index.ts index d1c37dc81431..d30c9175ecf9 100644 --- a/packages/serverless-invoke/src/index.ts +++ b/packages/serverless-invoke/src/index.ts @@ -1,4 +1 @@ -export * from './main'; -export * from './interface'; -export * from './core'; -export * from './utils'; +export * from '@midwayjs/fcli-plugin-invoke'; diff --git a/packages/serverless-invoke/src/interface.ts b/packages/serverless-invoke/src/interface.ts deleted file mode 100644 index 4f80c542fda7..000000000000 --- a/packages/serverless-invoke/src/interface.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface InvokeOptions { - functionDir?: string; // 函数所在目录 - functionName: string; // 函数名 - data?: any[]; // 函数入参 - log?: boolean; // 是否进行console输出 - trigger?: string; // 触发器 - provider?: string; // 部署的环境 - providerEventMap?: any; - starter?: any; - eventPath?: string; - eventName?: string; - layers?: any; - handler?: string; - midwayModuleName?: string; - sourceDir?: string; // 一体化目录结构下,函数的目录,比如 src/apis,这个影响到编译 - clean?: boolean; // 清理调试目录 - incremental?: boolean; // 增量编译 - verbose?: boolean; // 输出更多信息 -} - -export interface IInvoke { - invoke(...args: any); -} diff --git a/packages/serverless-invoke/src/invoke.ts b/packages/serverless-invoke/src/invoke.ts deleted file mode 100644 index 6406bfd19885..000000000000 --- a/packages/serverless-invoke/src/invoke.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { InvokeCore } from './core'; -import { createRuntime } from '@midwayjs/runtime-mock'; -import * as FCTrigger from '@midwayjs/serverless-fc-trigger'; - -/** - * 1、社区平台,找到入口,执行入口 + 参数 - * 2、自定义运行时,执行运行时的 invoke 方法 + 参数 - */ -export class Invoke extends InvokeCore { - async getInvokeFunction() { - let invoke; - let runtime; - let triggerMap; - const provider = this.spec && this.spec.provider && this.spec.provider.name; - if (provider) { - let handler: any = ''; - if (provider === 'fc' || provider === 'aliyun') { - handler = await this.loadHandler(require.resolve('@midwayjs/serverless-fc-starter')); - triggerMap = FCTrigger; - } else if (provider === 'scf' || provider === 'tencent') { - handler = await this.loadHandler(require.resolve('@midwayjs/serverless-scf-starter')); - } - if (handler) { - runtime = createRuntime({ - handler: this.wrapperHandler(handler) - }); - } - } - - if (runtime) { - invoke = async (...args) => { - const trigger = this.getTrigger(triggerMap, args); - await runtime.start(); - const result = await runtime.invoke(...trigger); - await runtime.close(); - return result; - }; - } - if (!invoke) { - invoke = await this.getUserFaaSHandlerFunction(); - } - return invoke; - } - - getTrigger(triggerMap, args) { - if (!triggerMap) { - return args; - } - let triggerName = this.options.trigger; - if (!triggerName) { - const funcInfo = this.getFunctionInfo(); - if (funcInfo.events && funcInfo.events.length) { - triggerName = Object.keys(funcInfo.events[0])[0]; - } - } - const EventClass = triggerMap[triggerName]; - if (EventClass) { - return [new EventClass(...args)]; - } - return args; - } -} diff --git a/packages/serverless-invoke/src/main.ts b/packages/serverless-invoke/src/main.ts deleted file mode 100644 index d78ab83aa9b7..000000000000 --- a/packages/serverless-invoke/src/main.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Invoke } from './invoke'; -import { InvokeOptions } from './interface'; -export const getInvoke = (Invoke, ...args) => { - return async (options: InvokeOptions) => { - if (!options.data || !options.data.length) { - options.data = [{}]; - } - let otherOptions = {}; - if (args && args.length) { - otherOptions = args[args.length - 1]; - } - const invokeFun = new Invoke({ - baseDir: options.functionDir, - functionName: options.functionName, - handler: options.handler, - trigger: options.trigger, - sourceDir: options.sourceDir, - clean: options.clean, - incremental: options.incremental, - ...otherOptions - }); - return invokeFun.invoke([].concat(options.data)); - }; -}; - -export const invoke = getInvoke(Invoke); diff --git a/packages/serverless-invoke/src/utils.ts b/packages/serverless-invoke/src/utils.ts deleted file mode 100644 index 3edb0b680894..000000000000 --- a/packages/serverless-invoke/src/utils.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - existsSync, - remove, -} from 'fs-extra'; -import { join } from 'path'; -export const exportMidwayFaaS = (() => { - const midwayModuleName = process.env.MidwayModuleName || '@midwayjs/faas'; - const faasPath = join(process.cwd(), './node_modules/', midwayModuleName); - if (existsSync(faasPath)) { - return require(faasPath); - } else { - try { - return require(midwayModuleName); - } catch (e) { - return { FaaSStarter: class DefaulltMidwayFaasStarter {} }; - } - } -})(); - -export const FaaSStarterClass = exportMidwayFaaS.FaaSStarter; - -export const cleanTarget = async (p: string) => { - if (existsSync(p)) { - await remove(p); - } -}; diff --git a/packages/serverless-invoke/test/main.test.ts b/packages/serverless-invoke/test/main.test.ts index b02581131907..e62757e50c4b 100644 --- a/packages/serverless-invoke/test/main.test.ts +++ b/packages/serverless-invoke/test/main.test.ts @@ -1,11 +1,9 @@ -import { getInvoke } from '../src'; -import { Invoke } from '../src/invoke'; +import { invoke } from '../src'; import { join } from 'path'; import * as assert from 'assert'; -const invoke = getInvoke(Invoke, { verbose: true }); describe('/test/main.test.ts', () => { it('invoke', async () => { - const result: any = await (invoke as any)({ + const result: any = await invoke({ functionDir: join(__dirname, 'fixtures/baseApp'), functionName: 'http', clean: false,