文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2024-12-03 04:01

关注

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

设置项目

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

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

Workspaces(工作区)

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

  1. 使用 mkdir my-app 创建项目的文件夹(可以自由选择所需的名称)。
  2. 使用 cd my-app 进入文件夹。
  3. 使用 yarn init 初始化它。这将提示您创建初始 package.json 文件的相关问题(不用担心,一旦创建文件,您可以随时对其进行修改)。如果您不想使用 yarn init 命令,则始终可以手动创建文件,并将以下内容复制到其中:
  1.   "name""my-app"
  2.   "version""1.0.0"
  3.   "license""UNLICENSED"
  4.   "private"true // Required for yarn workspace to work 

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

  1. my-app/ 
  2. ├─ packages/ // 我们当前和将来的所有模块都将存在的地方 
  3. │  ├─ app/ 
  4. │  ├─ common/ 
  5. │  ├─ server/ 
  6. ├─ package.json 

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

软件包名称使用的命名约定是在每个软件包之前都使用 @my-app 

  •     "target""es2017"
  •     "module""CommonJS"
  •     "lib": ["ESNext""DOM"], 
  •  
  •      
  •     "moduleResolution""node"
  •     "esModuleInterop"true
  •  
  •      
  •     "baseUrl""./"
  •     "paths": { 
  •       "@flipcards 
  •     "jsx""react"
  •     "experimentalDecorators"true
  •     "resolveJsonModule"true 
  •   }, 
  •   "exclude": ["node_modules""**/node_modulespublic/script.js 
  • 文件夹结构应如下所示:

    1. my-app/ 
    2. ├─ packages/ 
    3. ├─ .gitignore 
    4. ├─ package.json 

    添加代码

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

    Common

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

    文件

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

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

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

    src/index.ts

    1. export const APP_TITLE = 'my-app'

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

    package.json

    1.   "name""@my-app/common"
    2.   "version""0.1.0"
    3.   "license""UNLICENSED"
    4.   "private"true
    5.   "main""./src/index.ts" // 添加这一行来为 TS 提供入口点 

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

    结构提醒:

    1. common/ 
    2. ├─ src/ 
    3. │  ├─ index.ts 
    4. ├─ package.json 

    App

    依赖项

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

    从项目的根目录运行:

    package.json

    1.   "name""@my-app/app"
    2.   "version""0.1.0"
    3.   "license""UNLICENSED"
    4.   "private"true
    5.   "dependencies": { 
    6.     "@my-app/common""^0.1.0", // Notice that we've added this import manually 
    7.     "react""^17.0.1"
    8.     "react-dom""^17.0.1" 
    9.   }, 
    10.   "devDependencies": { 
    11.     "@types/react""^17.0.3"
    12.     "@types/react-dom""^17.0.2" 
    13.   } 

    文件

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

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

    public/index.html

    1.  
    2.  
    3.    
    4.     my-app 
    5.     name="description" content="Welcome on my application!" /> 
    6.    
    7.    
    8.      
    9.     -- 这个 div 是我们将注入 React 应用程序的地方 --> 
    10.     "root">
     
  •     -- 这是包含我们的应用程序的脚本的路径 --> 
  •     "script.js"
  •    
  •  
  •  现在我们有了要渲染的页面,我们可以通过添加下面的两个文件来实现非常基本但功能齐全的 React 应用程序。

    src/index.tsx

    1. import * as React from 'react'
    2. import * as ReactDOM from 'react-dom'
    3.  
    4. import { App } from './App'
    5.  
    6. ReactDOM.render(, document.getElementById('root')); 

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

    src/App.tsx

    1. import { APP_TITLE } from '@flipcards/common'
    2. import * as React from 'react'
    3.  
    4. export function App(): React.ReactElement { 
    5.   const [count, setCount] = React.useState(0); 
    6.  
    7.   return ( 
    8.     
       
    9.        
    10.       

       

    11.         This is the main page of our application where you can confirm that it 
    12.         is dynamic by clicking the button below. 
    13.       

       
    14.  
    15.       

      Current count: {count}

       
    16.        setCount((prev) => prev + 1)}>Increment 
    17.     
     
  •   ); 
  • 这个简单的 App 组件将呈现我们的应用和动态计数器。这将是我们的 React tree 的入口点。随意添加您想要的任何代码。

    就是这样!我们已经完成了非常基本的 React 应用程序。目前它并没有太大的作用,但是我们总是可以稍后再使用它并添加更多功能。

    结构提醒:

    1. app/ 
    2. ├─ public
    3. │  ├─ index.html 
    4. ├─ src/ 
    5. │  ├─ App.tsx 
    6. │  ├─ index.tsx 
    7. ├─ package.json 

    Server

    依赖项

    server 软件包将需要以下依赖项:

    从项目的根目录运行:

    package.json

    1.   "name""@my-app/server"
    2.   "version""0.1.0"
    3.   "license""UNLICENSED"
    4.   "private"true
    5.   "dependencies": { 
    6.     "@my-app/common""^0.1.0", // 请注意,我们已手动添加了此导入 
    7.     "cors""^2.8.5"
    8.     "express""^4.17.1" 
    9.   }, 
    10.   "devDependencies": { 
    11.     "@types/cors""^2.8.10"
    12.     "@types/express""^4.17.11" 
    13.   } 

    文件

    现在我们的 React 应用程序已经准备就绪,我们需要的最后一部分是服务器来为其提供服务。首先为其创建以下文件夹:

    接下来,添加 server 的主文件:

    src/index.ts

    1. import { APP_TITLE } from '@flipcards/common'
    2. import cors from 'cors'
    3. import express from 'express'
    4. import { join } from 'path'
    5.  
    6. const PORT = 3000; 
    7.  
    8. const app = express(); 
    9. app.use(cors()); 
    10.  
    11. // 服务来自 "public" 文件夹的静态资源(例如:当有图像要显示时) 
    12. app.use(express.static(join(__dirname, '../../app/public'))); 
    13.  
    14. // 为 HTML 页面提供服务 
    15. app.get('*', (req: any, res: any) => { 
    16.   res.sendFile(join(__dirname, '../../app/public''index.html')); 
    17. }); 
    18.  
    19. app.listen(PORT, () => { 
    20.   console.log(`${APP_TITLE}'s server listening at http://localhost:${PORT}`); 
    21. }); 

    这是一个非常基本的 Express 应用程序,但如果除了单页应用程序之外我们没有任何其他服务,那么这就足够了。

    结构提醒:

    1. server/ 
    2. ├─ src/ 
    3. │  ├─ index.ts 
    4. ├─ package.json 

    构建应用

    Bundlers(打包构建捆绑器)

    为了将 TypeScript 代码转换为可解释的 JavaScript 代码,并将所有外部库打包到单个文件中,我们将使用打包工具。JS/TS 生态系统中有许多捆绑器,如 WebPack、Parcel 或 Rollup,但我们将选择 esbuild。与其他捆绑器相比,esbuild 自带了许多默认加载的特性(TypeScript, React),并有巨大的性能提升(快了 100 倍)。如果你有兴趣了解更多,请花时间阅读作者的常见问题解答。

    这些脚本将需要以下依赖项:

    从项目的根目录运行:yarn add -D -W esbuild ts-node。

    package.json

    1.   "name""my-app"
    2.   "version""1.0"
    3.   "license""UNLICENSED"
    4.   "private"true
    5.   "workspaces": ["packages 
    6. interface BuildOptions { 
    7.   env: 'production' | 'development'
    8.  
    9.  
    10. export async function buildApp(options: BuildOptions) { 
    11.   const { env } = options; 
    12.  
    13.   await build({ 
    14.     entryPoints: ['packages/app/src/index.tsx'], // 我们从这个入口点读 React 应用程序 
    15.     outfile: 'packages/app/public/script.js', // 我们在 public/ 文件夹中输出一个文件(请记住,在 HTML 页面中使用了 "script.js") 
    16.     define: { 
    17.       'process.env.NODE_ENV': `"${env}"`, // 我们需要定义构建应用程序的 Node.js 环境 
    18.     }, 
    19.     bundle: true
    20.     minify: env === 'production'
    21.     sourcemap: env === 'development'
    22.   }); 
    23.  
    24.  
    25. export async function buildServer(options: BuildOptions) { 
    26.   const { env } = options; 
    27.  
    28.   await build({ 
    29.     entryPoints: ['packages/server/src/index.ts'], 
    30.     outfile: 'packages/server/dist/index.js'
    31.     define: { 
    32.       'process.env.NODE_ENV': `"${env}"`, 
    33.     }, 
    34.     external: ['express'], // 有些库必须标记为外部库 
    35.     platform: 'node', // 为 Node 构建时,我们需要为其设置环境 
    36.     target: 'node14.15.5'
    37.     bundle: true
    38.     minify: env === 'production'
    39.     sourcemap: env === 'development'
    40.   }); 
    41.  
    42.  
    43. async function buildAll() { 
    44.   await Promise.all([ 
    45.     buildApp({ 
    46.       env: 'production'
    47.     }), 
    48.     buildServer({ 
    49.       env: 'production'
    50.     }), 
    51.   ]); 
    52.  
    53. // 当我们从终端使用 ts-node 运行脚本时,将执行此方法 
    54. buildAll(); 

    该代码很容易解释,但是如果您觉得遗漏了部分,可以查看 esbuild 的 API文档 以获取完整的关键字列表。

    我们的构建脚本现已完成!我们需要做的最后一件事是在我们的 package.json 中添加一个新命令,以方便地运行构建操作。

    1.   "name""my-app"
    2.   "version""1.0"
    3.   "license""UNLICENSED"
    4.   "private"true
    5.   "workspaces": ["packages*/node_modules 
    6.  
    7. # Builds 
    8. **/dist 
    9. */*/script.js 

    随意添加任何您想忽略的文件,以减轻您的最终镜像。

    构建 Docker Image

    现在我们的应用程序已经为 Docker 准备好了,我们需要一种从 Docker 生成实际镜像的方法。为此,我们将向根 package.json添加一个新命令:

    1.   "name""my-app"
    2.   "version""1.0.0"
    3.   "license""MIT"
    4.   "private"true
    5.   "workspaces": ["packages/*"], 
    6.   "devDependencies": { 
    7.     "esbuild""^0.9.6"
    8.     "ts-node""^9.1.1"
    9.     "typescript""^4.2.3" 
    10.   }, 
    11.   "scripts": { 
    12.     "app""yarn workspace @my-app/app"
    13.     "common""yarn workspace @my-app/common"
    14.     "server""yarn workspace @my-app/server"
    15.     "build""ts-node ./scripts/build.ts"
    16.     "serve""node ./packages/server/dist/index.js"
    17.     "docker""docker build . -t my-app" // Add this line 
    18.   } 

    docker build . -t my-app 命令告诉 docker 使用当前目录(.)查找 Dockerfile,并将生成的镜像(-t)命名为 my-app。

    确保运行了 Docker 守护进程,以便在终端中使用 docker 命令。

    现在该命令已经在我们项目的脚本中,您可以使用 yarn docker 运行它。

    在运行该命令后,您应该期望看到以下终端输出:

    1. Sending build context to Docker daemon  76.16MB 
    2. Step 1/12 : FROM node:14.15.5-alpine 
    3.  ---> c1babb15a629 
    4. Step 2/12 : WORKDIR /usr/src/app 
    5.  ---> b593905aaca7 
    6. Step 3/12 : COPY ./package.json . 
    7.  ---> e0046408059c 
    8. Step 4/12 : COPY ./yarn.lock . 
    9.  ---> a91db028a6f9 
    10. Step 5/12 : COPY ./packages/app/package.json ./packages/app/ 
    11.  ---> 6430ae95a2f8 
    12. Step 6/12 : COPY ./packages/common/package.json ./packages/common/ 
    13.  ---> 75edad061864 
    14. Step 7/12 : COPY ./packages/server/package.json ./packages/server/ 
    15.  ---> e8afa17a7645 
    16. Step 8/12 : RUN yarn 
    17.  ---> 2ca50e44a11a 
    18. Step 9/12 : COPY . . 
    19.  ---> 0642049120cf 
    20. Step 10/12 : RUN yarn build 
    21.  ---> Running in 15b224066078 
    22. yarn run v1.22.5 
    23. $ ts-node ./scripts/build.ts 
    24. Done in 3.51s. 
    25. Removing intermediate container 15b224066078 
    26.  ---> 9dce2d505c62 
    27. Step 11/12 : EXPOSE 3000 
    28.  ---> Running in f363ce55486b 
    29. Removing intermediate container f363ce55486b 
    30.  ---> 961cd1512fcf 
    31. Step 12/12 : CMD [ "yarn""serve" ] 
    32.  ---> Running in 7debd7a72538 
    33. Removing intermediate container 7debd7a72538 
    34.  ---> df3884d6b3d6 
    35. Successfully built df3884d6b3d6 
    36. Successfully tagged my-app:latest 

    就是这样!现在,我们的镜像已创建并注册在您的机器上,供 Docker 使用。如果您希望列出可用的 Docker 镜像,则可以运行 docker image ls 命令:

    1. → docker image ls 
    2. REPOSITORY    TAG       IMAGE ID        CREATED          SIZE 
    3. my-app        latest    df3884d6b3d6    4 minutes ago    360MB 

    像这样运行命令

    通过命令行运行一个可用的 Docker 镜像非常简单:docker run -d -p 3000:3000 my-app

    你可以确认你的容器正在运行 docker ps。这将列出所有正在运行的容器:

    1. → docker ps 
    2. CONTAINER ID    IMAGE     COMMAND                  CREATED          STATUS          PORTS                    NAMES 
    3. 71465a89b58b    my-app    "docker-entrypoint.s…"   7 seconds ago    Up 6 seconds    0.0.0.0:3000->3000/tcp   determined_shockley 

    现在,打开浏览器并导航到以下URL http://localhost:3000,查看您正在运行的应用程序🚀!

     

    来源:黑客下午茶内容投诉

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    软考中级精品资料免费领

    • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

      难度     813人已做
      查看
    • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

      难度     354人已做
      查看
    • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

      难度     318人已做
      查看
    • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

      难度     435人已做
      查看
    • 2024年上半年系统架构设计师考试综合知识真题

      难度     224人已做
      查看

    相关文章

    发现更多好内容

    猜你喜欢

    AI推送时光机
    位置:首页-资讯-后端开发
    咦!没有更多了?去看看其它编程学习网 内容吧
    首页课程
    资料下载
    问答资讯