互联网技术 / 互联网资讯 · 2024年1月8日

使用Yarn workspace,TypeScript,esbuild,React和Express构建K8S云原生应用(一)

使用Yarn workspace,TypeScript,esbuild,React和Express构建 K8S 云原生应用(一)

本文将指导您使用 K8S ,DockeR,YaRn woRkspace ,typescRIPt,esbuild,ExpReSS 和 React 来设置构建一个基本的云原生 Web 应用程序。在本教程的最后,您将拥有一个可完全构建和部署在 K8S 上的 Web 应用程序。

设置项目

该项目将被构造为 MonoRepo。 MonoRepo 的目标是提高模块之间共享的代码量,并更好地预测这些模块如何一起通信(例如在微服务架构中)。出于本练习的目的,我们将使结构保持简单:

app,它将代表我们的 React websITe。 seRveR,它将使用 ExpReSS 服务我们的 app。 coMMon,其中一些代码将在 app 和 seRveR 之间共享。

设置项目之前的唯一要求是在机器上安装 yaRn。 YaRn 与 NPM 一样,是一个程序包管理器,但性能更好,功能也略多。您可以在官方文档中阅读有关如何安装它的更多信息。

WoRkspaces(工作区)

进入到要初始化项目的文件夹,然后通过您喜欢的终端执行以下步骤:

鸿蒙官方战略合作共建――HaRMonyOS技术社区 使用 MkdiR My-app 创建项目的文件夹(可以自由选择所需的名称)。 使用 cd My-app 进入文件夹。 使用 yaRn inIT 初始化它。这将提示您创建初始 package.json 文件的相关问题(不用担心,一旦创建文件,您可以随时对其进行修改)。如果您不想使用 yaRn inIT 命令,则始终可以手动创建文件,并将以下内容复制到其中: { “naMe”: “My-app”, “version”: “1.0.0”, “license”: “UNLICENSED”, “pRivate”: tRue }

现在,已经创建了 package.json 文件,我们需要为我们的模块app,coMMon 和 seRveR 创建文件夹。为了方便 yaRn woRkspace 发现模块并提高项目的可读性(ReadaBIlITy),我们将模块嵌套在 packages 文件夹下:

My-app/ ├─ packages/ // 我们当前和将来的所有模块都将存在的地方 │ ├─ app/ │ ├─ coMMon/ │ ├─ seRveR/ ├─ package.json

我们的每个模块都将充当一个小型且独立的项目,并且需要其自己的 package.json 来管理依赖项。要设置它们中的每一个,我们既可以使用 yaRn inIT(在每个文件夹中),也可以手动创建文件(例如,通过 IDE)。

软件包名称使用的命名约定是在每个软件包之前都使用 @My-app/* 作为前缀。这在 NPM 领域中称为作用域。您不必像这样给自己加上前缀,但以后会有所帮助。

一旦创建并初始化了所有三个软件包,您将具有如下所示的相似之处。

app 包:

{ “naMe”: “@My-app/app”, “version”: “0.1.0”, “license”: “UNLICENSED”, “pRivate”: tRue }

coMMon 包:

{ “naMe”: “@My-app/coMMon”, “version”: “0.1.0”, “license”: “UNLICENSED”, “pRivate”: tRue }

seRveR 包:

{ “naMe”: “@My-app/seRveR”, “version”: “0.1.0”, “license”: “UNLICENSED”, “pRivate”: tRue }

最后,我们需要告诉 yaRn 在哪里寻找模块,所以回去编辑项目的 package.json 文件并添加以下 woRkspaces 属性(如果您想了解更多有关详细信息,请查看 YaRn 的 woRkspaces 文档)。

{ “naMe”: “My-app”, “version”: “1.0”, “license”: “UNLICENSED”, “pRivate”: tRue, “woRkspaces”: [“packages/*”] }

您的最终文件夹结构应如下所示:

My-app/ ├─ packages/ │ ├─ app/ │ │ ├─ package.json │ ├─ coMMon/ │ │ ├─ package.json │ ├─ seRveR/ │ │ ├─ package.json ├─ package.json

现在,您已经完成了项目的基础设置。

typescRIPt

现在,我们将第一个依赖项添加到我们的项目:typescRIPt。typescRIPt 是 JavaScRIPt 的超集,可在构建时实现类型检查。

通过终端进入项目的根目录,运行 yaRn add -D -W typescRIPt。

参数 -D 将 typescRIPt 添加到 devDependencies,因为我们仅在开发和构建期间使用它。 参数 -W 允许在工作空间根目录中安装一个包,使其在 app、coMMon 和 seRveR 上全局可用。

您的 package.json 应该如下所示:

{ “naMe”: “My-app”, “version”: “1.0”, “license”: “UNLICENSED”, “pRivate”: tRue, “woRkspaces”: [“packages/*”], “devDependencies”: { “typescRIPt”: “^4.2.3” } }

这还将创建一个 yaRn.lock 文件(该文件确保在项目的整个生命周期中依赖项的预期版本保持不变)和一个 node_modules 文件夹,该文件夹保存依赖项的 BInaRies。

现在我们已经安装了 typescRIPt,一个好习惯是告诉它如何运行。为此,我们将添加一个配置文件,该文件应由您的 IDE 拾取(如果使用 VScode,则会自动获取)。

在项目的根目录下创建一个 tsconfig.json 文件,并将以下内容复制到其中:

{ “coMpileROptions”: { /* BaSiC */ “taRget”: “es2017”, “module”: “CoMMonJS”, “lib”: [“ESNext”, “DOM”], /* modules Resolution */ “moduleResolution”: “node”, “esmoduleInteRop”: tRue, /* Paths Resolution */ “baseURl”: “./”, “paths”: { “@fliPCaRds/*”: [“packages/*”] }, /* Advanced */ “jsx”: “React”, “expeRiMentalDecoRaTors”: tRue, “ResolveJsonmodule”: tRue }, “exclude”: [“node_modules”, “**/node_modules/*”, “dist”] }

您可以轻松地搜索每个 coMpileoptions 属性及其操作,但对我们最有用的是 paths 属性。例如,这告诉 typescRIPt 在 @My-app/seRveR 或 @My-app/app 包中使用 @My-app/coMMon 导入时在哪里查找代码和 tyPINGs。

您当前的项目结构现在应如下所示:

My-app/ ├─ node_modules/ ├─ packages/ │ ├─ app/ │ │ ├─ package.json │ ├─ coMMon/ │ │ ├─ package.json │ ├─ seRveR/ │ │ ├─ package.json ├─ package.json ├─ tsconfig.json ├─ yaRn.lock 添加第一个 scRIPt

YaRn woRkspace 允许我们通过 yaRn woRkspace @My-app/* 命令模式访问任何子包,但是每次键入完整的命令将变得非常多余。为此,我们可以创建一些 helpeR scRIPt 方法来提升开发体验。打开项目根目录下的 package.json,并向其添加以下 scRIPts 属性。

{ “naMe”: “My-app”, “version”: “1.0”, “license”: “UNLICENSED”, “pRivate”: tRue, “woRkspaces”: [“packages/*”], “devDependencies”: { “typescRIPt”: “^4.2.3” }, “scRIPts”: { “app”: “yaRn woRkspace @My-app/app”, “coMMon”: “yaRn woRkspace @My-app/coMMon”, “seRveR”: “yaRn woRkspace @My-app/seRveR” } }

现在可以像在子包中一样执行任何命令。例如,您可以通过键入 yaRn seRveR add expReSS 来添加一些新的依赖项。这将直接向 seRveR 包添加新的依赖项。

在后续部分中,我们将开始构建前端和后端应用程序。

准备 Git

如果计划使用 GIT 作为版本控制工具,强烈建议忽略生成的文件,例如二进制文件或日志。

为此,请在项目的根目录下创建一个名为 .GitignoRe 的新文件,并将以下内容复制到其中。这将忽略本教程稍后将生成的一些文件,并避免提交大量不必要的数据。

# Logs yaRn-debug.log* yaRn-Error.log* # BInaRies node_Modules/ # Builds dist/ **/public/scRIPt.js

文件夹结构应如下所示:

My-app/ ├─ packages/ ├─ .GitignoRe ├─ package.json 添加代码

这部分将着重于将代码添加到我们的 coMMon、app 和 seRveR 包中。

CoMMon

我们将从 coMMon 开始,因为此包将由 app 和 seRveR 使用。它的目标是提供共享的逻辑(shaRed logic)和变量(vaRiables)。

文件

在本教程中,coMMon 软件包将非常简单。首先,从添加新文件夹开始:

sRc/ 文件夹,包含包的代码。

创建此文件夹后,将以下文件添加到其中:

sRc/index.ts

expoRt const app_TITLE = ”My-app”;

现在我们有一些要导出的代码,我们想告诉 typescRIPt从其他包中导入它时在哪里寻找它。为此,我们将需要更新 package.json 文件:

package.json

{ “naMe”: “@My-app/coMMon”, “version”: “0.1.0”, “license”: “UNLICENSED”, “pRivate”: tRue, “MAIn”: “./sRc/index.ts” }

我们现在已经完成了 coMMon 包!

结构提醒:

coMMon/ ├─ sRc/ │ ├─ index.ts ├─ package.json app 依赖项

该 app 包将需要以下依赖项:

React React-doM

从项目的根目录运行:

yaRn app add React React-doM yaRn app add -D @types/React @types/React-doM (为 typescRIPt添加类型tyPINGs)

package.json

{ “naMe”: “@My-app/app”, “version”: “0.1.0”, “license”: “UNLICENSED”, “pRivate”: tRue, “dependencies”: { “@My-app/coMMon”: “^0.1.0”, “React”: “^17.0.1”, “React-doM”: “^17.0.1” }, “devDependencies”: { “@types/React”: “^17.0.3”, “@types/React-doM”: “^17.0.2” } }

要创建我们的 React 应用程序,我们将需要添加两个新文件夹:

一个 public/ 文件夹,它将保存基本 HTML 页面和我们的 aSSets。 一个 sRc/ 文件夹,其中包含我们应用程序的代码。

一旦创建了这两个文件夹,我们就可以开始添加 HTML 文件,该文件将成为我们应用程序的宿主。

public/index.htMl

My-app

需要启用 JavaScRIPt 才能运行此应用。

现在我们有了要渲染的页面,我们可以通过添加下面的两个文件来实现非常基本但功能齐全的 React 应用程序。

sRc/index.tsx

iMpoRt * as React fRoM ”React”; iMpoRt * as ReactDOM fRoM ”React-doM”; iMpoRt { app } fRoM ”./app”; ReactDOM.RendeR(, docuMent.getEleMentById(‘Root’));

此代码从我们的 HTML 文件挂接到 Root div 中,并将 React组件树 注入其中。

sRc/app.tsx

iMpoRt { app_TITLE } fRoM ”@fliPCaRds/coMMon”; iMpoRt * as React fRoM ”React”; expoRt function app(): React.ReactEleMent { const [count, setCount] = React.useState(0); RetuRn (

WelcoMe on {app_TITLE}!

THis is the MAIn page of ouR application wheRe you can confiRM that IT is dynaMic by clicking the button below.

CuRRent count: {count}

OpenMagic API

Need more than content? Move into the product flow.

If you are here for model access, pricing, developer docs, or the future API console, the dedicated product path now lives on api.openmagic.ai.

登录免费注册