阿里云函数计算typescript脚手架
2020-02-11
背景
最近一直在折腾阿里云函数计算,发现这东西确实方便啊,最理想的情况下确实可以达到noOps。但问题是,函数计算需要改写程序入口,普通的nodejs服务器如果要运行到函数计算平台上,需要做许多改写的处理,导致没办法用许多成熟的nodejs服务器脚手架,比如eggJS。于是基于官方骨架教程做了一套我自己熟悉技术栈的骨架模板。用于以后的开发。
- 语言: TypeScript
- 运行时: nodejs8
- 开发框架: express
- 代码打包: webpack
- 代码规范: eslint(airbnb规则)+prettier
代码地址
使用方法
使用方法主要用函数计算提供的cli工具fun
实现思路
实现主要问题是将函数计算的HTTP触发器绑定到Express服务器实例上。通常的函数计算HTTP触发器是:
module.exports.handler = (req, res, context) => {
// ...
};
一个express服务器则是:
const express = require('express')
const app = express()
app.get('/', (req, res) => res.send('Hello World!'))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
我们可以看出最大的区别,如果我们的代码要运行在函数计算平台,我们不需要app.listen
来监听运行环境的某个端口,而是由函数计算平台来主动调用handler。
而函数计算官方提供了一个将函数计算的HTTP触发器事件代理到nodejs服务器的库@webserverless/fc-express
,我们删除掉主动listen的代码,用这个库做一层http转发。
import { Server } from '@webserverless/fc-express';
import express from 'express';
const app = express();
app.all('*', (req, res) => {
res.send('Hello serverless with TypeScript & Express5!');
});
const server = new Server(app);
// 删除主动listen的代码
// app.listen(3000, () => console.log('Example app listening on port 3000!'))
// 代理触发器事件
module.exports.handler = (req, res, context) => {
server.httpProxy(req, res, context);
};
于是我们就可以使用我们熟悉的express来做开发了。
Webpack和TypeScript配置
// webpack.config.common.js
const path = require('path');
module.exports = {
entry: './src/index.ts',
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
{
test: /\.ts$/,
exclude: /node_modules/,
loader: 'awesome-typescript-loader',
},
],
exprContextCritical: false, // 去除express的模块规范警告
},
};
// tsconfig.json
{
"include": ["src/*"],
"exclude": ["node_modules", "**/*.test.ts", "dist", ".fun"],
"compilerOptions": {
"esModuleInterop": true,
"inlineSourceMap": false,
"sourceMap": true,
"moduleResolution": "node",
"allowJs": true,
"lib": ["dom", "es5", "scripthost", "es2015.promise"]
}
}
# template.yml
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
demo-service: # service name
Type: 'Aliyun::Serverless::Service'
Properties:
Description: ''
demo: # function name
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
Runtime: nodejs8
CodeUri: './dist'
Timeout: 60
Events:
httpTrigger:
Type: HTTP
Properties:
AuthType: ANONYMOUS
Methods: ['POST', 'GET']
主要就几个要点:
- 入口改写为
index.ts
- 目标模块标准为函数计算支持的umd标准
- 使用
awesome-typescript-loader
去加载ts模块 - webpack打包输出到
dist
文件夹 - yaml模板中配置触发器类型为HTTP,并指定触发器代码在
dist
文件夹