<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一頓操作猛如虎,部署一個(gè)萬能 BFF

          共 5558字,需瀏覽 12分鐘

           ·

          2021-09-22 12:40

          通過將 gatsby 的本地開發(fā) GraphQL 服務(wù)器 Serverless 化,借助其強(qiáng)大和豐富的插件系統(tǒng)以及生態(tài),實(shí)現(xiàn)一個(gè)萬能的 BFF 層。


          Gatsby Js

          Gatsby Js 最初的定位是一個(gè)靜態(tài)站點(diǎn)生成器,和一般的靜態(tài)站點(diǎn)生成器不同,它擁有豐富的源插件,可以從各種數(shù)據(jù)源同步數(shù)據(jù),通過 GraphQL Server 將這些數(shù)據(jù)暴露給客戶端。


          由于它追求極致的性能和用戶體驗(yàn),因此其 GraphQL Server 只在站點(diǎn)生成階段運(yùn)行。也就是說,在本地開發(fā)和站點(diǎn)編譯時(shí),擁有一個(gè)動(dòng)態(tài)服務(wù)器,編譯階段,會(huì)讀取所有的數(shù)據(jù),最終生成靜態(tài)的 html 文件,并且分發(fā)到強(qiáng)大的 CDN 網(wǎng)絡(luò),從而實(shí)現(xiàn)頁面秒開效果。


          gatsby 的生態(tài),幾乎集成了一切數(shù)據(jù)源,不管是調(diào)用 API、還是讀取數(shù)據(jù)庫、還是直接解析各種配置文件或者 markdown,都不用再寫代碼,只需要添加相關(guān)插件即可。盡管目前這一切只發(fā)生在編譯階段,但是只需要稍作魔改,就能將其部署成一個(gè)動(dòng)態(tài)服務(wù),變成一個(gè)萬能 BFF!


          BFF 層

          我不僅被它的極致用戶體驗(yàn)解決方案所吸引,還被它的本地 GraphQL Server 所吸引,憑借它豐富的插件,它這個(gè) GraphQL Server 就是一個(gè)天然優(yōu)秀的 BFF 層呀!

          雖然其本地 GraphQL Server 只是用來生成靜態(tài)站點(diǎn)的,但是如果能將它部署到公網(wǎng),就可以實(shí)時(shí)為多端提供服務(wù)了,不僅網(wǎng)站可以使用其數(shù)據(jù)源,小程序,APP 都可以使用。


          BFF 層的提出,本來是針對(duì)不同的端提供不同的 BFF 服務(wù),但由于使用了 GraphQL,將服務(wù)的聚合裁剪功能扔到前端,于是一個(gè)服務(wù)就能同時(shí)給到不同的端。


          免費(fèi)的 AWS lambda

          部署到公網(wǎng)很有吸引力,但是要花錢的話,就沒意思了。


          于是,我把目光瞄準(zhǔn)了 AWS lambda,它的免費(fèi)額度夠我用的了。



          說干就干

          最終效果演示:https://jqp5j170i6.execute-api.us-east-1.amazonaws.com/dev/gatsby/graphql



          源代碼庫:https://github.com/Jeff-Tian/serverless-space


          源代碼庫代碼較多,主要是把 gatsby-js 的一個(gè)庫 gatsby-recipes 拷貝過來做了一番魔改,以繞過 AWS lambda 環(huán)境中,不能寫文件的問題。下面對(duì)主要的改造過程做個(gè)分解。


          Serverless

          Serverless 本意是去掉服務(wù)器,讓開發(fā)者只需要關(guān)注業(yè)務(wù)邏輯,不用管基礎(chǔ)設(shè)施,不同的云廠商對(duì)其有不同的實(shí)現(xiàn)。Serverless 框架做了個(gè)抽象,讓開發(fā)者通過一個(gè)統(tǒng)一的 yaml 文件定義服務(wù),它來對(duì)不同的云廠商做具體的適配。


          安裝

          npm install -g serverless



          定義服務(wù)

          serverless.yml

          service: serverless-space
          provider: name: aws runtime: nodejs12.x lambdaHashingVersion: 20201221 package: patterns: - '!node_modules/**' - '!layers/**' functions: gatsby: handler: dist/src/gatsby.handler layers: - {Ref: LibLambdaLayer} events: - http: method: ANY path: gatsby/ - http: method: ANY path: 'gatsby/{proxy+}' environment: SERVERLESS_EXPRESS_PLATFORM: aws

          plugins: - serverless-plugin-layer-manager - serverless-offline - serverless-express

          layers: lib: path: layers name: space-lib description: My dependencies retain: true

          從上面可以看到,定義中使用了一些插件,serverless-offline 和 serverless-express 是為了方便本地運(yùn)行用的,實(shí)現(xiàn) serverless offline 在本地環(huán)境下模擬 lambda。而 serverless-plugin-layer-manager 則是用來對(duì) lambda 分層。通過使用這個(gè)插件,只需要定義層就好,省去了手動(dòng)壓縮、上傳、關(guān)聯(lián)等等繁雜的工作,非常方便。


          分層

          分層的好處是把變動(dòng)不頻繁的 node_modules 部分與變動(dòng)頻繁的應(yīng)用業(yè)務(wù)邏輯代碼隔離,從而減小每次發(fā)布時(shí)的網(wǎng)絡(luò)傳輸大小,以及可以實(shí)現(xiàn)同一個(gè)層同時(shí)為多個(gè) lambda 服務(wù)。


          在 serverless yaml 配置文件里,對(duì)于分層有個(gè)命名約定。比如你的分層命名為 xxx,那么在引用它時(shí),就要用 {Ref: XxxLambdaLayer},并且注意大小寫。


          全局安裝 serverless 及其插件

          這并不是必需的,但是推薦。原因是無論是對(duì)于 lambda 應(yīng)用代碼,以及 node_modules 分層大小,都有一個(gè) 250 M 的上限,這個(gè)上限是壓縮前的大小。如果不采用全局安裝,會(huì)導(dǎo)致 serverless 自動(dòng)將插件安裝在 node_modules 里,導(dǎo)致增加 node_modules 文件夾的大小。

          npm install -g serverlessnpm install -g serverless-plugin-layer-manager...


          部署

          serverless 可以一鍵部署,自動(dòng)搞定資源分配和建立關(guān)聯(lián)、以及權(quán)限配置等等。在寫好應(yīng)用代碼,配置好 serverless.yml 文件后,就能一鍵部署:


          serverless deploy


          項(xiàng)目大致目錄結(jié)構(gòu)

          |---- layers            |---- nodejs               |---- .npmrc               |---- node_modules|---- node_modules|---- src      |---- gatsby.ts      |---- gatsby-recipes                      |---- ...|---- serverless.yml|---- tsconfig.json|---- tsconfig.build.json|---- package.json


          layers 目錄是分層用的,注意它一定要包含一個(gè) nodejs 目錄,在部署前,必須的依賴就安裝在這個(gè)目錄下,所以可以在這個(gè)目錄下建立一個(gè)文件 .npmrc,并配置為只安裝生產(chǎn)必須的依賴:


          .npmrc


          only=production


          TypeScript 配置

          TypeScript 是 JavaScript 的一個(gè)超集,解決了原生 JavaScript 飽受詬病的動(dòng)態(tài)特性,建立了一個(gè)完善的類型系統(tǒng)。為了使用 TypeScript 開發(fā)的同時(shí),部署成 JavaScript,需要配置指示 tsc 如何將 TypeScript 轉(zhuǎn)譯成 JavaScript。


          tsconfig.json

          {  "compilerOptions": {    "module": "commonjs",    "esModuleInterop": true,    "declaration": true,    "removeComments": true,    "emitDecoratorMetadata": true,    "experimentalDecorators": true,    "allowSyntheticDefaultImports": true,    "target": "es2017",    "sourceMap": true,    "outDir": "./dist",    "baseUrl": "./",    "incremental": true,    "skipLibCheck": true,    "allowJs": true,    "jsx": "react-jsx",  },  "include": [    "src/**/*",    "README.md"  ]}


          注意這里在 "include" 部分除了包含必要的 src 目錄下的文件外,還額外引入了根目錄下的 READ.md 文件,這只是為了讓生成的 dist 目錄保留原始項(xiàng)目結(jié)構(gòu)(即有 src 部分),不然 dist 目錄下會(huì)直接是 src 下的被轉(zhuǎn)譯后的文件。


          為了排除不必要的文件,可以在 tsconfig.build.json 里指定:

          {  "extends": "./tsconfig.json",  "exclude": [    "dist",    "test",    "**/*spec.ts"  ]}

          這里還配置了 "jsx" 以支持 react-jsx,因?yàn)?gatsby-recipes 里需要。


          魔改 gatsby-recipes

          將 0.9.3 這個(gè)版本的 gatsby-recipes 源文件拷貝到項(xiàng)目,刪除其 dist 目錄,然后打開 src/gatsby-recipes/src/providers/npm/package.js 文件,將其原本的 getConfigStore 引用刪除,然后改寫:

          - import {getConfigStore} from 'gatsby-core-utils'+ const getConfigStore = () => ({ get: () => 'yarn' })

          這樣就能避免在 lambda 環(huán)境,該文件嘗試寫文件的錯(cuò)誤。


          gatsby.ts 入口文件


          這是整個(gè) lambda 的入口,詳細(xì)參見源代碼。主要工作是將 express 替換成 serverless/express,同時(shí)引入 bodyParser,否則會(huì)接受不到客戶端傳來的 GraphQL 查詢。因?yàn)?GraphQL 本質(zhì)上是一個(gè) HTTP Post 請(qǐng)求。


          import express from 'serverless-express/express'import {graphqlHTTP} from "express-graphql"import cors from "cors"import bodyParser from "body-parser"

          const app = express()

          app.use(cors())app.use(bodyParser.json())

          app.use(`/graphql`, graphqlHTTP({ schema, graphiql: true, context: {root: directory}}))
          const port = 3000

          if (require.main === module) { console.log('called directly')

          app.listen(port, () => { console.log(`Example gatsby serverless app listening at http://localhost:${port}`) })}

          export default app

          const bootstrap = async () => { return serverlessExpress({app})}

          let server

          export const handler: Handler = async ( event: any, context: Context, callback: Callback,) => { server = server ?? (await bootstrap()) return server(event, context, callback)}


          以上代碼判斷 require.main,如果是本地直接運(yùn)行,就會(huì)監(jiān)聽 (3000) 端口,準(zhǔn)備提供服務(wù)。而如果是在 lambda 環(huán)境,那么 handler 函數(shù)會(huì)被觸發(fā)。


          總結(jié)

          通過對(duì) gatsby-recipes 的魔改,使得 gatsby 本地開發(fā)用的 GraphQL Server 可以運(yùn)行在 AWS lambda 上,從而實(shí)現(xiàn)了一個(gè)免費(fèi)又強(qiáng)大(萬能)的 BFF 層。


          后面只需要添加不同的數(shù)據(jù)源插件,就能給不同的前端提供幾乎所有服務(wù)了。


          有興趣的同學(xué)歡迎持續(xù)關(guān)注、點(diǎn)贊和在看,后面將持續(xù)更新,使用真實(shí)案例,分解如何利用該萬能 BFF,應(yīng)用在具體的場景上。


          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  殴州亚洲视频 | 国产一级a毛一级a做视频 | 伊人久色 | 成人日批视频 | 国产精品婷婷午夜在线观看 |