Malagu 框架提供了一个命令行工具 @malagu/cli
,该工具提供了一些基础的命令,帮助我们初始化、运行、构建和部署项目。该工具只包含最核心的功能,通过命令行插件机制把一些非核心的功能、不同平台部署逻辑通过插件的方式提供,命令行插件也是组件的一种形式。通过插件机制,我们可以为命令行工具添加新的命令,或者扩展老的命令。在 Malagu 框架中,很多地方都使用到了命令行插件。
安装
命令行工具除了 malagu init
命令意外,其他命令都会委托给当前项目中的 @malagu/service
执行,无需担心全局命令与项目本地命令版本不一致问题。命令行工具基于 npm 和 yarn 进行包的管理,命令行会基于当前项目的环境情况智能选择合适的包管理工具,如果 npm 和 yarn 都满足条件,则优先选择使用 yarn 工具。例如:当项目根目录下存在 yarn.lock
文件,则使用 yarn。当然,我们也可以强行指定包管理器,使用配置属性: malagu.packager
。
# 指定淘宝镜像源下载会更快
npm install -g @malagu/cli --registry https://registry.npm.taobao.org
命令行说明
我们可以通过 malagu -h
命令查看命令行帮助信息,malagu -h
命令如下:
Usage: malagu <command> [options]
Malagu CLI 0.0.44
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
init [options] [name] [template] init a application
serve [options] [entry] serve a applicaton
build [options] [entry] build a application
deploy [options] [entry] deploy a applicaton
config config faas adapter profile
主要包含四个核心命令:
- malagu init:初始化一个模板应用
- malagu serve:本地运行应用
- malgu build:构建应用,一般情况不使用,部署应用的时候自动使用该命令构建项目
- malagu deploy:部署应用,通过
-s, --skip-build
选项跳过构建过程 - malagu config:配置 FaaS 适配器相关的个性信息,例如 AKSK,region 等等。该命令是一个上下文命令,只要满足一定上下文要求才会看到该命令,所有需要在项目根目录执行该命令,并且项目依赖了 FaaS 适配器相关的组件,例如
fc-adapter
、scf-adapter
等等。
初始化
我们可以通过 malagu init
命令使用模板,malagu init
命令如下:
Usage: malagu init [options] [name] [template]
init a application
Options:
-o, --output-dir [path] output directory (default: ".")
-h, --help output usage information
参数:
name
应用名称,可选,如果没有指定应用名称,则使用模板名称作为应用名称tempate
应用模板,可选,支持指定内置模板名称和 GitHub Repository 地址。如果指定template
参数,则必须指定应用名称;如果没有指定template
参数,命令行会提示我们从内置模板中选择一个
选项:
-o,--output-dir
应用输出的位置,可选,如果不指定该选项,则输出位置为命令行执行时的工作目录
示例:
# 不指定名称,从内置模板列表中选择
$ malagu init
# 指定名称,从内置模板列表中选择
$ malagu init demo
# 指定模板为内置模板名称
$ malagu init demo backend-app
# 指定模板为 GitHub Repository 地址
$ malagu init demo git@github.com:cellbang/cellbang-site.git # 或者 malagu init demo https://github.com/cellbang/cellbang-site.git
内置模板
- sample-app:前后端一体化应用,前后端通信使用 RPC 风格
- backend-app:后端应用,使用 REST 风格暴露 API 接口
- vue-app:使用 vue 作为前端的前后端一体化应用
- database-app:访问数据库应用,配置好数据库链接,使用 typeorm 操作数据库
- accounts:账号中心,配置好数据库和 github 等第三方 oauth 凭证即可完成一个真实场景的第三方认证与授权
- schedule:定时任务调度应用,支持 Serverless 场景,屏蔽不同 Serverless 平台之间的差异,一键部署
- admin-app:前后端一体化应用,前后端通信使用 RPC 风格,后端管理系统模板
- microservice:微服务应用
- file-service:基于对象存储服务的文件服务应用
- puppeteer:无头浏览器应用
- monorepo:monorepo 项目风格应用,将一个大项目拆分成多个 Malagu 组件
- mycli:命令行应用,快速开发命令行工具
```bash
/‘_/___
\ /\_ \ /\ \ __ \//\ \ __ __ __ __ \ \ \__\ \ /'__
\ \ \ \ /‘\ /'_
\/\ \/\ \ \ \ _/\ \/\ \L._ _\ _/\ \L._/\ \L\ \ \ _\ \ \ _\ _\ \/._\/__\ \/._\ _ \ _/ \// \//\//\//\/_/\//\//\/L\ \/_//\____/
@malagu/cli@1.18.0 \_/__/
? Select a template to init (Use arrow keys or type to search) ❯ backend-app Official sample-app Official vue-app Official database-app Official admin-app Official microservice Official file-service Official puppeteer Official monorepo Official mycli Official
<a name="Jli2K"></a>
## 本地运行
我们可以通过 `malagu serve` 命令本地运行项目,推荐使用 `npx malagu serve` 运行项目,`malagu serve` 命令如下:
```bash
Usage: serve [options] [entry]
serve a applicaton
Options:
-o, --open [open] Open browser
-p, --port [port] Port used by the server
-t, --targets [targets] Specify application targets
-m, --mode [mode] Specify application mode
-h, --help output usage information
参数:
entry
应用入口文件,可选,一般不需要指定,框架根据当前项目组件依赖情况自动选择合适的应用入口文件
选项:
-o,--open
启动完成后自动打开浏览器访问应用服务地址,可选,默认不打开浏览器-p,--port
应用服务启动的端口号,可选,默认 3000-t,--targets
应用构建目标产物,可选,默认值是['frontend', 'backend']
-m,--mode
应用运行模式,可选,框架根据指定模式加载对应的模式配置件,本命令默认开启local
模式
示例:
# 指定端口号和打开浏览器
$ malagu serve -p 30001 -o
# 指定应用构建目标产物
$ malagu serve -t frontend
# 指定单个应用运行模式
$ malagu serve -m test
# 指定多个应用运行模式
$ malagu serve -m cdn,database # 或者 malagu serve -m cdn -m database
构建
我们可以通过 malagu build
命令构建项目,推荐使用 npx malagu build
构建项目,malagu build
命令如下:
Usage: build [options] [entry]
build a application
Options:
-t, --targets [targets] Specify application targets (default: [])
-m, --mode [mode] Specify application mode (default: [])
-p, --prod [prod] Create a production build
-h, --help output usage information
参数:
entry
应用入口文件,可选,一般不需要指定,框架根据当前项目组件依赖情况自动选择合适的应用入口文件
选项:
-t,--targets
应用构建目标产物,可选,默认值是['frontend', 'backend']
-m,--mode
应用运行模式,可选,框架根据指定模式加载对应的模式配置件,本命令默认开启remote
模式-p,--prod
生产环境标识,可选,简化生产环境构建命令
示例:
# 指定应用构建目标产物
$ malagu build -t frontend
# 指定单个应用运行模式
$ malagu build -m test
# 指定多个应用运行模式
$ malagu build -m cdn,database # 或者 malagu serve demo -m cdn -m database
# 指定生产环境标识
$ malagu build -p
注意:一般情况,不需要手动执行构建命令,因为在执行部署命令的时候会自动构建,部署命令可以通过选项 -s, --skip-build
跳过构建过程。如果你不打算使用框架提供的部署命令,此时,你需要自己手动执行构建命令。不过,当框架提供的部署命令不满足你的业务需要,更推荐的做法是通过提供一个命令 [Deploy](#0ji38)
插件,自定义部署逻辑。
部署
我们可以通过 malagu build
命令部署项目,使用部署命令前,需要安装对应平台的适配器组件,比如 @malagu/fc-adapter
、 @malagu/scf-adapter
等等。推荐使用 npx malagu deploy
部署项目,malagu deploy
命令如下:
Usage: deploy [options] [entry]
deploy a applicaton
Options:
-t, --targets [targets] Specify application targets (default: [])
-m, --mode [mode] Specify application mode (default: [])
-p, --prod [prod] Create a production deployment
-s, --skip-build [skipBuild] Skip the build process
-h, --help
参数:
entry
应用入口文件,可选,一般不需要指定,框架根据当前项目组件依赖情况自动选择合适的应用入口文件
选项:
-t,--targets
应用构建目标产物,可选,默认值是['frontend', 'backend']
-m,--mode
应用运行模式,可选,框架根据指定模式加载对应的模式配置件,本命令默认开启remote
模式-p,--prod
生产环境标识,可选,简化生产环境构建命令-s,--skip-build
跳过构建过程,可选,默认不跳过,部署的时候,构建过程没有问题,但是部署出现了网络问题,这个时候,可以跳过构建过程直接部署
示例:
# 指定应用构建目标产物
$ malagu deploy -t frontend
# 指定单个应用运行模式
$ malagu deploy -m test
# 指定多个应用运行模式
$ malagu deploy -m cdn,database # 或者 malagu serve demo -m cdn -m database
# 指定生产环境标识
$ malagu deploy -p
# 跳过构建过程
$ malagu deploy -s
插件
命令行工具包含最核心的功能,通过命令行插件机制把一些非核心的功能、不同平台部署逻辑通过插件的方式提供,命令行插件也是组件的一种形式。通过插件机制,我们可以为命令行工具添加新的命令,或者扩展老的命令。在 Malagu 框架中,很多地方都使用到了命令行插件。
Cli
插件
执行 malagu
命令的时候,执行该插件。通过 Cli
插件,我们可以为命令行工具添加新的命令,或者扩展老的命令,这是一个自由度非常高的一个插件,比如使用 Cli
插件添加一个新命令:
import { CliContext } from '@malagu/cli-service';
export default async (context: CliContext) => {
const { program } = context;
program
.command('login')
.description('Sign in to the app')
.action(() => {
console.log('login');
});
}
插件代码存放到项目目录 src/cli-hook.ts
或者 src/hooks/cli.ts
,框架自动识别加载,也可以通过属性 cliHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
- 其他信息,执行不同命令,参数是不一样的,该上下文也会把命令的参数放进来,例如
Serve
插件的上下文中,包含了port
、open
、dev
等信息
Webpack
插件
执行 malagu
命令需要 Webpack 构建的时候,执行该插件。通过 Webpack
插件,我们可以自定义 Webpack 构建行为,我们也可以通过 malagu.webpack
属性配置 Webpack,但是,对于一些自由度比较高的配置,Webpack
插件方式更加适合 。比如使用 Webpack
插件添加一个 Webpack 自己的插件:
import { WebpackContext, ConfigurationContext } from '@malagu/cli-service';
export default async (context: WebpackContext) => {
const { configurations } = context;
const config = ConfigurationContext.getFrontendConfiguration(configurations);
if (config) {
const { VueLoaderPlugin } = require('vue-loader');
config
.module
.rule('vue')
.test(/\.vue$/)
.use('vue-loader')
.loader('vue-loader')
.end()
.end()
.rule('css')
.test(/\.css$/)
.use('vue-style-loader')
.loader('vue-style-loader')
.end()
.use('css-loader')
.loader('css-loader');
config
.plugin('vueLoader')
.use(VueLoaderPlugin);
}
};
插件代码存放到项目目录 src/webpack-hook.ts
或者 src/hooks/webpack.ts
,框架自动识别加载,也可以通过属性 webpackHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
configurations
Webpack 配置对象,与getWebpackConfig
不同,getWebpackConfig
获取的是组件属性中的malagu.webpack
program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
- 其他信息, 包含了
prod
、mode
、targets
、dev
、entry
等信息
Deploy
插件
执行 malagu deploy
命令的时候,执行该插件。通过 Deploy
插件,我们可以自定义部署行为。比如使用 Deploy
插件实现项目部署到函数计算平台:
export default async (context: DeployContext) => {
const { cfg } = context;
const deployConfig = getMalaguConfig(cfg, BACKEND_TARGET)['faas-adapter'];
const profileProvider = new ProfileProvider();
profile = {
...await profileProvider.provide(),
...deployConfig.profile
};
const regions = deployConfig.regions || [profile.defaultRegion];
for (region of regions) {
await doDeploy(context, deployConfig);
}
};
插件代码存放到项目目录 src/deploy-hook.ts
或者 src/hooks/deploy.ts
,框架自动识别加载,也可以通过属性 deployHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
configurations
Webpack 配置对象,与getWebpackConfig
不同,getWebpackConfig
获取的是组件属性中的malagu.webpack
program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
- 其他信息, 包含了
prod
、mode
、targets
、dev
、entry
等信息
Build
插件
执行 malagu build
命令的时候,执行该插件。通过 Build
插件,我们可以自定义构建行为。比如使用 Build
插件实现项目为部署到函数计算平台 custom
运行时,而生成 bootstrap
启动文件:
import { BuildContext, getHomePath } from '@malagu/cli-service';
import { join } from 'path';
import { writeFile } from 'fs-extra';
import { FaaSAdapterUtils } from '@malagu/faas-adapter/lib/hooks';
export default async (context: BuildContext) => {
const { pkg, cfg } = context;
const adapterConfig = FaaSAdapterUtils.getConfiguration<any>(cfg);
if (adapterConfig.type === 'custom') {
const destDir = join(getHomePath(pkg), 'bootstrap');
const bootstrap = adapterConfig.function.bootstrap;
delete adapterConfig.function.bootstrap;
await writeFile(destDir, `#!/bin/bash\n${bootstrap}`, { mode: 0o755 });
}
};
插件代码存放到项目目录 src/build-hook.ts
或者 src/hooks/build.ts
,框架自动识别加载,也可以通过属性 buildHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
configurations
Webpack 配置对象,与getWebpackConfig
不同,getWebpackConfig
获取的是组件属性中的malagu.webpack
program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
- 其他信息, 包含了
prod
、mode
、targets
、dev
、entry
等信息
Serve
插件
执行 malagu serve
命令的时候,执行该插件。通过 Serve
插件,我们可以自定义本地运行行为。比如使用 Serve
插件实现基于 Webpack Dev Server 的本地运行:
import { ServeContext } from '@malagu/cli-service';
import * as express from 'express';
export class Deferred<T> {
resolve: (value?: T) => void;
reject: (err?: any) => void; // tslint:disable-line
promise = new Promise<T>((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
}
export default async (context: ServeContext) => {
const { app, entryContextProvider } = context;
app.use(express.json());
app.use(express.raw());
app.use(express.text());
app.use(express.urlencoded({ extended: true }));
let doDispatch: (req: any, res: any) => void;
const compileDeferred = new Deferred<void>();
context.compiler.hooks.done.tap('WebServe', () => {
entryContextProvider().then(async (ctx: any) => {
const { Dispatcher, Context, HttpContext, ContainerProvider, Application, container } = ctx;
const c = await container;
ContainerProvider.set(c);
await c.get(Application).start();
const dispatcher = c.get(Dispatcher);
doDispatch = (req: any, res: any) => {
const httpContext = new HttpContext(req, res);
Context.run(() => dispatcher.dispatch(httpContext));
};
compileDeferred.resolve();
});
});
app.all('*', async (req: any, res: any) => {
await compileDeferred.promise;
doDispatch(req, res);
});
};
插件代码存放到项目目录 src/serve-hook.ts
或者 src/hooks/serve.ts
,框架自动识别加载,也可以通过属性 serveHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
server
http 的 Server 对象app
基础框架应用对象,例如 Express 的 Application 对象compiler
Webpack 的编译对象entryContextProvider
通过入口文件提供上下文的方法,通过该异步方法可以获取启动 Malagu 应用需要的上下文configurations
Webpack 配置对象,与getWebpackConfig
不同,getWebpackConfig
获取的是组件属性中的malagu.webpack
program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
- 其他信息,包含了
port
、open
、dev
等信息
Config
插件
框架在应用配置计算表达式之前,执行该插件。通过 Config
插件,我们可以动态添加一些特殊的应用配置。比如使用 Config
插件为应用配置动态添加阿里云账号 ID:
import { ConfigContext } from '@malagu/cli-service';
import { DefaultProfileProvider, FaaSAdapterUtils, FaaSAdapterConfiguration } from '@malagu/faas-adapter/lib/hooks';
export default async (context: ConfigContext) => {
const { config, cfg } = context;
if (config.mode && config.mode.includes('remote')) {
context.spinner?.stop();
const adapterConfig = FaaSAdapterUtils.getConfiguration<FaaSAdapterConfiguration>(cfg);
const profileProvider = new DefaultProfileProvider();
const profile = await profileProvider.provide(adapterConfig);
const faasAdapter = config.malagu['faas-adapter'];
if (!faasAdapter.account?.id) {
faasAdapter.account = profile.account;
}
if (!faasAdapter.region) {
faasAdapter.region = profile.region;
}
}
};
插件代码存放到项目目录 src/config-hook.ts
或者 src/hooks/config.ts
,框架自动识别加载,也可以通过属性 configHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
config
应用配置对象program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
Init
插件
执行 malagu init
命令的时候,执行该插件。比如:
import { InitContext } from '@malagu/cli';
export default async (context: InitContext) => {
...
};
插件代码存放到项目目录 src/init-hook.ts
或者 src/hooks/init.ts
,框架自动识别加载,也可以通过属性 initHooks
自定义其他目录位置。
通过命令行上下文,我们可以取到一下相关信息:
program
命令行对象,通过该对象可以获取命令相关信息pkg
应用程序包,通过该对象可以获取应用程序包相关信息,例如应用版本、应用名称、应用包含的组件等等信息cfg
应用配置信息,通过该对象可以获取应用配置信息,该应用的配置信息为所有组件属性聚合并计算了表达式以后的值。框架也提供了一些关于应用配置相关的工具方法:getConfig
根据target
获取前端或者后端配置getMalaguConfig
根据target
获取前端或者后端malagu
配置getWebpackConfig
根据target
获取前端或者后端webpack
配置
- 其他信息,包含了
name
、tempate
、outputDir
等信息