您现在的位置是:热点 >>正文
使用Yarn workspace,TypeScript,esbuild,React和Express构建 K8S 云原生应用(一)
热点446人已围观
简介...
本文将指导您使用 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 // Required for yarn workspace to work }
现在,已经创建了 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 │ ├─ Ya;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 */ &nbsrnp;"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 允 w许我们通过 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 添加代码
这部分or将着重于将代码添加到我们的 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" // 添加这一行来为 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", // Notice that we've added this import manually "react": "^17.ks0.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
You need to enable JavaScript to run this app.
现在我们有了要渲染的页面,我们可以通过添加下面的两个文件来实现非常基本但功能齐全的 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 { APpaP_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}
setCount((prev) => prev + 1)}>Increment); }
这个简单的 App 组件将呈现我们的应用标题和动态计数器。这将是我们的 React tree 的入口点。随意添加您想要的任何代码。
就是这样!我们已经完成了非常基本的 React 应用程序。目前它并没有太大的作用,但是我们总是可以稍后再使用它并添加更多功能。
结构提醒:
app/ ├─ public/ │ ├─ index.html ├─ src/ │ ce ├─ App.tsx │ ├─ index.tsx ├─ package.json Server
依赖项
server 软件包将需要以下依赖项:
cors express
从项目的根目录运行:
yarn server add cors express yarn server add -D @types/cors @types/express(为 TypeScript 添加类型typings)
package.json
{ "name": "@my-app/server", "version": "0.1.0", "license": "UNLICENSED", "private": true, "dependencies": { "@my-app/common": "^0.1.0", // 请注意,我们已手动添加了此导入 "cors": "^2.8.5", "express": "^4.17.1" }, "devDependencies": { "@types/cors": "^2.8.10", "@types/express": "^4.17.11" } } 文件
现在我们的 React 应用程序已经准备就绪,我们需要的最后一部分是服务器来为其提供服务。首先为其创建以下文件夹:
一个 src/ 文件夹,包含我们服务器的代码。
接下来,添加 server 的主文件:
src/index.ts
import { APP_TITLE } from '@flipcards/common'; import cors from 'cors'; import express from 'express'; import { join } from 'path'; const PORT = 3000; const a,Tpp = express(); app.use(cors()); // 服务来自 "public" 文件夹的静态资源(例如:当有图像要显示时) app.use(express.static(join(__dirname, '../../app/public'))); // 为 HTML 页面提供服务 app.get('*', (req: any, res: any) => { res.sendFile(join(__dirname, '../../app/public', 'index.html')); }); app.listen(PORT, () => { console.log(`${APP_TITLE}'s server listening at http://localhost:${PORT}`); });
这是一个非常基本的 Express 应用程序,但如果除了单页应用程序之外我们没有任何其他服务,那么这就足够了。
结构提醒:
server/ ├─ src/ │ ├─ index.ts ├─ package.json 构建应用
Bundlers(打包构建捆绑器)
为了将 TypeScript 代码转换为可解释的 JavaScript 代码,并将所有外部库打包到单个文件中,我们将使用打包工具。JS/TS 生态系统中有许多捆绑器,如 WebPack、Parcel 或 Rollup,但我们将选择 esbuild。与其他捆绑器相比,esbuild 自带了许多默认加载的特性(TypeScript, React),并有巨大的性能提升(快了 100 倍)。如果你有兴趣了解更多,请花时间阅读作者的常见问题解答。
这些脚本将需要以下依赖项:
esbuild 是我们的捆绑器 ts-node 是 TypeScript 的 REPL,我们将使用它来执行脚本
从项目的根目录运行:yarn add -D -W esbuild ts-node。
package.json
{ "name": "my-app", "version": "1.0", "license": "UNLICENSED", "private": true, "workspaces":yp ["packages/*"], "devDependencies": { "esbuild": "^0.9.6", "ts-node": "^9.1.1", "typescript": "^4.2.3" }, "scripts": { "app": "yarn workspace @my-app/app", "common": "yarn workspace @my-app/common", "server": "yarn workspace @my-app/server" } } Build(编译构建)
现在,我们拥有构建应用程序所需的所有工具,因此让我们创建第一个脚本。
首先在项目的根目录下创建一个名为 scripts/ 的新文件夹。
我们的脚本将用 TypeScript 编写,并从命令行使用 ts-node 执行。尽管存在用于 esbuild 的 CLI,但是如果您要传递更复杂的参数或将多个工作流组合在一起,则可以通过 JS 或 TS 使用该库,这更加方便。
在 scripts/ 文件夹中创建一个 build.ts 文件,并在下面添加代码(我将通过注释解释代码的作用):
scripts/build.ts
import { build } from 'esbuild'; /** * 在构建期间传递的通用选项。 */ interface BuildOptions { env: 'production' | 'development'; } /** * app 包的一个构建器函数。 */ export async function buildApp(options: BuildOptions) { const { env } = opteSions; await build({ entryPoints: ['packages/app/src/index.tsx'], // 我们从这个入口点读 React 应用程序 outfile: 'packages/app/public/script.js', // 我们在 public/ 文件夹中输出一个文件(请记住,在 HTML 页面中使用了 "script.js") define: { 'process.env.NODE_ENV': `"${env}"`, // 我们需要定义构建应用程序的 Node.js 环境 }, bundle: true, minify: env === 'production', sourcemap: env === 'development', }); } /** * server 软件包的构建器功能。 */ export async function buildServer(options: BuildOptions) { const { env } = options; await build({ entryPoints: ['packages/server/src/index.ts'], outfile: 'packages/server/dist/index.js', define: { &ncrbsp; 'process.env.NODE_ENV': `"${env}"`, }, external: ['express'], // 有些库必须标记为外部库 platform: 'node', // 为 Node 构建时,我们需要为其设置环境 target: 'node14.15.5', bundle: true, minify: env === 'production', sourcemap: env === 'development', }); } /** * 所有软件包的构建器功能。 */ async function buildAll() { await Promise.all([ buildApp({ env: 'production', }), buildServer({ env: 'production', }), ]); } // 当我们从终端使用 ts-node 运行脚本时,将执行此方法 buildAll();
该代码很容易解释,但是如果您觉得遗漏了部分,可以查看 esbuild 的 API文档 以获取完整的关键字列表。
我们的构建脚本现已完成!我们需要做的最后一件事是在我们的 package.json 中添加一个新命令,以方便地运行构建操作。
{ "name": "my-app", "veiprsion": "1.0", "license": "UNLICENSED", "private": true, "workspaces": ["packages/*"], "devDependencies": { "esbuild": "^0.9.6", "ts-node": "^9.1.1", "typescript": "^4.2.3" }, "scripts": { "app": "yarn workspace @my-app/app", "common": "yarn workspace @my-app/common", "server": "yarn workspace @my-app/server", "build": "ts-node ./scripts/build.ts" // Add this line here } }
现在,您可以在每次对项目进行更改时从项目的根文件夹运行 yarn build 来启动构建过程(如何添加hot-reloading,稍后讨论)。
结构提醒:
my-app/ ├─ packages/ ├─ scripts/ │ ├─ build.ts ├─ package.json ├─ tsconfig.json Serve(提供服务)
我们的应用程序已经构建好并可以提供给全世界使用,我们只需要向 package.json 添加最后一个命令即可:
{ "name": "my-app", "version": "1.0", "license": "UNLICENSED", "private": trt,ue, "workspaces": ["packages/*"], "devDependencies": { "esbuild": "^0.9.6", "ts-node": "^9.1.1", "typescript": "^4.2.3" }, "scripts": { "app": "yarn workspace @my-app/app", "common": "yarn workspace @my-app/common", "server": "yarn workspace @my-app/server", "build": "ts-node ./scripts/build.ts", "serve": "node ./packages/server/dist/index.js" // Add this line here } }
由于我们现在正在处理纯 JavaScript,因此可以使用 node 二进制文件启动服务器。因此,继续运行 yarn serve。
如果您查看控制台,您将看到服务器正在成功侦听。你也可以打开一个浏览器,导航到 http://localhost:3000 来显示你的 React 应用
Tags:
相关文章
标签: 九龙仓置业 海港城 投资物业 酒店
热点云梦级3月10日云梦级消息,九龙仓置业(01997.HK)公布年度业绩,截至205年12月31日止年度,基础净盈利增加5%至64.56亿港元,原因是财务支出减少。投资物业盈利增加7%至62.38亿港元...
【热点】
阅读更多标签: 柏奥尼克机器人 PNDbotics Adam系列 人形机器人
热点云梦级4月28日云梦级消息,近日,梧桐树资本被投企业——柏奥尼克机器人(宁波)有限公司(PNDbotics)宣布完成数亿元新一轮融资。本轮融资由中信证券旗下顶级私募股权投资平台中信金石领投,所融资金将...
【热点】
阅读更多标签: 魅族 Flyme 雷鸟创新 PANDAER
热点云梦级3月13日云梦级消息,据《智能涌现》从内部人士处获悉,魅族近期宣布一轮大调整,超50%的员工即将离开,涉及400人左右。这部分人有三个去处——其中,一部分将获得“N+2”的赔偿。 云梦级消息人士...
【热点】
阅读更多
热门文章
最新文章
友情链接
- 标签: 康师傅
- https://www.remit.co.jp/vi/?s=google霸屏优化【tg:seogoogle987】,MiU
- https://www.springfieldlibrary.org/library/?s=google霸屏优化【tg:seogoogle987】,lys
- https://www.scivee.tv/?s=google霸屏优化【tg:seogoogle987】,Nb7
- https://www.stormberg.com/no/search?q=google霸屏优化【tg:seogoogle987】,rV6
- https://www.sensorshop24.de/catalogsearch/result/index/?type=132&q=google霸屏优化【tg:seogoogle987】,0Eq
- https://www.kawainter.com/catalogsearch/result/?q=google霸屏优化【tg:seogoogle987】,lvl
- https://www.mynextmove.org/find/search?s=google霸屏优化【tg:seogoogle987】,MVU
- https://www.riohondo.edu/?action=QUERY&s=google霸屏优化【tg:seogoogle987】,8er
- https://www.libros.unam.mx/catalogsearch/result/?cat=37&dir=asc&format=20&lit=20&manufacturer=3230&mode=list&order=year_edition&q=google霸屏优化【tg:seogoogle987】,MUo
- https://www.uckfieldtc.gov.uk/?s=google霸屏优化【tg:seogoogle987】,uiv
- https://www.ng-slo.si/si/iskanje?cat=114&q=google霸屏优化【tg:seogoogle987】,QAj
- https://www.mingwai.edu.hk/?langzh-hant&s=google霸屏优化【tg:seogoogle987】,v0f
- https://www.partilerdunyasi.com/index.php?route=product/search&tag=google霸屏优化【tg:seogoogle987】,fg4
- https://www.safetv.go.kr/base/search/view?searchWord=google霸屏优化【tg:seogoogle987】kyW
- https://www.zisha.com/shop/list.shtml?wap_keyword=google霸屏优化【tg:seogoogle987】,NXE
- https://www.teamlab.art/ko/?submit=google霸屏优化【tg:seogoogle987】,GVM
- https://www.lauben.com/en/?action=SEARCH&s=google霸屏优化【tg:seogoogle987】,kJc
- https://search.danawa.com/dsearch.php?query=google霸屏优化【tg:seogoogle987】mwP
- https://www.ussalabama.com/?action=CHECK&s=google霸屏优化【tg:seogoogle987】,jaf
- https://www.stonerealestate.com.au/?cat=100&s=google霸屏优化【tg:seogoogle987】,DsQ
- https://www.nextavenue.org/?action=QUERY&s=google霸屏优化【tg:seogoogle987】,3DZ
- https://www.symatoys.com/search.html?ID=UyMD6aO58bPrJvQAB1I0N69KzJBZeNPC&keyword=google霸屏优化【tg:seogoogle987】,Vig
- https://www.skicheck.at/en/?action=CHECK&s=google霸屏优化【tg:seogoogle987】,ja2
- https://www.pixiv.net/tags/google霸屏优化【tg:seogoogle987】,oD3
- https://search.danawa.com/dsearch.php?query=google霸屏优化【tg:seogoogle987】921
- https://blvdseafood.com/?s=google霸屏优化【tg:seogoogle987】enr
- https://www.nss.nhs.scot/search?q=google霸屏优化【tg:seogoogle987】,VuX
- https://www.tmtpost.com/search?q=google霸屏优化【tg:seogoogle987】,LMh
- https://www.trockenmittel.ch/catalogsearch/result/?iC=ZM3&q=google霸屏优化【tg:seogoogle987】,Bhe
- https://www.supersauna.de/catalogsearch/result/?q=google霸屏优化【tg:seogoogle987】,0OR
- https://www.sebson.de/en/search?query=google霸屏优化【tg:seogoogle987】,MPL
- https://www.roberthalf.com/us/en/jobs/all/google霸屏优化【tg:seogoogle987】GnE
- https://www.swanagerailway.co.uk/search?q=google霸屏优化【tg:seogoogle987】,u5N
- https://www.qylaws.com/search/google霸屏优化【tg:seogoogle987】,cmi
- https://www.abbreviations.com/google霸屏优化【tg:seogoogle987】DEz
- https://www.roblox.com/discover/?cat=107&Keyword=google霸屏优化【tg:seogoogle987】,wVP
- https://www.tumblr.com/tagged/google霸屏优化【tg:seogoogle987】,q1u
- https://www.lindseymedicalsupply.com/search/google霸屏优化【tg:seogoogle987】,PHD
- https://www2.ual.es/ProyectoLates/?s=google霸屏优化【tg:seogoogle987】,MqH
- https://www.wellbees.com/catalogsearch/result/?action=CHECK&q=google霸屏优化【tg:seogoogle987】,QZi
- https://www.tarleton.edu/news/search/google霸屏优化【tg:seogoogle987】,LVm
- https://www.lyrics.com/lyrics/google霸屏优化【tg:seogoogle987】,Plt
- https://www.oprny.com/search.php?search_query=google霸屏优化【tg:seogoogle987】,dmn
- https://www.openspaceinstitute.org/search?q=google霸屏优化【tg:seogoogle987】,4Vn
- https://www.duksung.ac.kr/search/front/Search.jsp?qt=google霸屏优化【tg:seogoogle987】hNj
- https://www.tombow.com/search/google霸屏优化【tg:seogoogle987】,ZlE
- https://www.tcv.org.uk/search/google霸屏优化【tg:seogoogle987】,8N0
- https://yscc1986.net/search/google霸屏优化【tg:seogoogle987】9uK
- https://www.voices.com/talents/search?keywords=google霸屏优化【tg:seogoogle987】,1b5
- https://www.world-architects.com/en/search?term=google霸屏优化【tg:seogoogle987】,JpI