介绍
在previous part中,我们探索了 Mean 堆栈的关键组成部分,以及它们如何一起工作。我们还很好地掌握了monorepo方法以及如何构建文件夹。
在这一部分中,我们将采取一种动手方法,专注于编码和实验MonorePo方法。按照分步说明,我们将学习如何有效设置和使用MonorePo方法,这将使我们能够创建可扩展且易于维护的Web应用程序。我们将获得宝贵的见解,以无缝整合 Express.js 和打字稿,使我们能够最大程度地构建强大而有效的项目。激动人心的东西,对
是什么使打字稿成为卑鄙堆栈的绝佳选择?
当然! TypeScript无需介绍,因为其强大的功能和开发人员的经验在网络开发社区中众所周知。但是,让我们强调一些将在MonorePo环境中显着有益于我们的平均堆栈项目的一些关键要素:
- 完整的堆栈一致性:打字稿为您的整个均值堆栈带来统一性。由于Angular已经使用Typescript,因此将Typescript与服务器端上的Express.js合并增强了堆栈的一致性和兼容性。无论是在正面还是在后面工作,您都可以保持相同的开发实践。
- 共享类型定义:全栈JavaScript开发中的一个常见挑战是使数据模型定义在服务器和客户端之间保持一致。在带有打字稿的MonorePo设置中,您可以在正面和背面共享类型的定义(例如接口或类型)。这种方法可确保您的MongoDB数据模型,Express.js服务和Angular组件就其处理的数据结构一致。
- 可伸缩性和可维护性:作为MonorePo在单个存储库中包含多个项目,它们允许更容易的代码共享和依赖关系管理。将其与打字稿的强键入结合有助于创建可扩展和可维护的Web应用程序,以随着项目的需求而增长。
- 增强的代码协作:在涉及多个开发人员的MonorePo项目中,打字稿的类型注释是有效的文档,可以促进团队成员之间的无缝沟通和理解。这促进了改进的协作,并最大程度地减少了代码冲突的机会,从而导致开发工作流平滑。
将打字稿与monorepo中的express.js结合在一起,均值堆栈应用程序提供了许多好处,包括提高代码质量,生产率和可维护性。它确保一致性,增强协作并启用可扩展的Web开发。
在我的recently published article中阅读有关monorepo的更多信息。
并查看monorepo tools website以获取更多信息。
现在,让我们将重点转移到有效管理项目的另一个关键方面:软件包管理。
PNPM:表演件软件包管理器
pnpm是JavaScript的软件包经理,它是开源,高效且以性能为导向的。它通常被认为是npm和Yarn的替代方法。 pnpm 通过提供与同行相同的功能,但具有独特的优势,可以在MonorePo设置中脱颖而出。其内容 - 可调的文件系统可减少重复并节省磁盘空间,从而比NPM或YARN更快,更有效地安装。 PNPM的工作空间功能通过将它们链接在一起以跨项目的无缝更新,从而使其在存储库中的多个软件包变得轻松,从而提高了工作流效率。
以下是使用PNPM管理MonorePo的一些关键优势:
- 增强的性能:由于其有效的存储方法,PNPM的安装速度比NPM或纱线更快。当包裹已经在商店中,并且一个项目请求安装时,PNPM仅在项目的 node_modules 目录和商店中的软件包之间创建一个紧密的链接,从而导致安装时间更快。
-
工作空间管理: PNPM通过其工作区功能在MonorePo中管理多个软件包提供一流的支持。您可以在整个工作空间上运行脚本,安装,更新和链接包装,从而更容易管理相互依存的软件包。此外,它还为Monorepos提供了开箱即用的支持,该功能具有工作空间:*协议和
--filter
标志。 - 单个实例存储: pnpm使用一种称为单个实例存储的独特方法,该方法涉及在计算机上的集中式全局存储位置链接软件包。这种创新的方法可确保如果多个项目依赖相同的软件包版本,则仅存储一次,从而大大降低了磁盘空间的使用。
- 强兼容性: PNPM与NPM和纱线无缝集成,以确保兼容性和平滑过渡。将现有项目从NPM或YARN迁移到PNPM需要对配置或软件包结构的最小更改,从而使采用过程变得直接。
总体而言,PNPM为有效管理大型项目提供了可靠,有效的解决方案,使其成为基于MonorePo的开发的令人信服的选择。
您可以使用 npm 或 YARN 工作区而不是PNPM,如果您喜欢。
让我们探索如何使用PNPM实现monorePo结构。
使用PNPM创建monorepo结构
安装PNPM之前,请确保您的系统上已经安装了Node.js。您可以通过执行以下命令来检查node.js是否已安装:
node -v
# v20.4.0
如果您没有安装node.js,则可以从official website下载它。 npm与node.js捆绑在一起,因此安装node.js。
时,您都可以获得两者截至本文发表的那天,我正在使用可用的最新版本,20.4.0
。
如果您同时从事多个JavaScript项目,我强烈建议使用nvm (Node Version Manager)。此工具允许您在计算机上的多个版本的node.js之间进行安装,管理和切换。这是一个很棒的工具,可以使您的工作效率更高。
设置Node.js和NPM后,下一步是安装PNPM。您可以使用Brew(如果已经安装)或NPM作为替代方案。
# using brew
brew install pnpm
# using npm
npm install -g pnpm
有关安装PNPM的更多信息,请询问提供各种选项的installation guide。
要确保正确安装了PNPM,您可以验证其版本:
pnpm -v
# 8.6.7
要设置MonorePo的根,请创建一个新的目录。例如,我将命名 bugsight 。
在根目录中创建 apps 目录。为您的 clien t和服务器应用程序 apps 目录。
接下来,在根级别创建软件包目录。这将拥有共享的代码, client 和 server 应用程序都可以使用。例如,您可以创建一个包含您共享打字稿配置的 tsconfig 包。
这是您的monorepo的预期目录结构:
bugsight
├── apps
├ ├── server
├ └── client
└── packages
├── tsconfig
└── ....
单片应用程序是一个奇异的实体,要求其所有组件集体部署。另一方面,monorepo是不同的。它可以在同一存储库中托管几个独立的应用程序,同时共享本地软件包,同时启用独立部署。因此,与整体相比,monorepos在部署方面具有更大的灵活性。
要生成顶级 package.json 文件,请在根目录中初始化pnpm。
pnpm init
启动该过程后,您会注意到 package.json 已生成。
{
"name": "bugsight",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
在这一点上,结果似乎与使用 npm 相当。尽管如此,重要的是要提到
。pnpm init
命令与npm init --yes
相当运行。这意味着它在初始化时会自动分配默认值,但是如果要个性化这些值,则可以在初始配置后进行。
要在MonorePo中设置PNPM工作区,我们需要在顶级制作 pnpm-workspace.yaml 文件。该文件概述了MonorePo的布局,并标识了其中包含的工作区或软件包的路径。然后,PNPM将相应地识别并处理这些子包。
packages:
- 'apps/*'
- 'packages/*'
值得一提的是,您可以使用 .npmrc 文件来控制PNPM MonorePo中的软件包管理。该文件显着影响PNPM的操作和MonorePo结构。但是,这些设置需要仔细考虑以与您的项目的要求保持一致。在official docs中阅读有关它的更多信息。
使用Nx,Turborepo和Bazel等各种工具,管理MonorePo工作区可以更容易。对于像我们这样的小型莫诺普,这些工具最初似乎过于杀伤。 PNPM,YARN或NPM等包装管理人员的内置工作区功能可能足以管理小型Monorepo。
但是,随着项目的增长,您可能会开始感到需要更高级功能,例如改善包装间依赖关系的处理,复杂的代码共享和优化的构建过程。这是这些工具可以有所帮助的地方。
使用PNPM设置我们的MonorePo结构后,是时候继续进行以下部分了。在此步骤中,我们将致力于创建基本的Express服务器。
创建最小的快递服务器
要启动,转到服务器文件夹并初始化一个package.json文件。
pnpm init
使用pnpm init
后, package.json 文件将自动生成使用默认值,而无需任何提示。您必须访问 package.json 文件并修改主字段值。具体来说,请将其更改为src/index.js
而不是index.js
。
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
...
}
要设置服务器代码,请创建 src 目录。在此目录中,创建 index.js 文件。
src 文件夹是项目源代码的常规位置。它为您的应用程序代码提供了一个专门的空间,与其他文件分开,例如配置,文档或依赖项。这种分离有助于维护有组织的代码库,从而更容易构建工具来识别源文件,管理测试并控制版本控制中包含的内容。
添加一个直接的JavaScript代码以验证将打印值的设置。
const print = message => {
console.log(message);
};
print('JavaScript is AWESOME');
要执行此JavaScript文件,请使用服务器文件夹中的以下命令:
node src/index.js
“ javascript很棒” 邮件应在您的终端中打印。
让我们安装Express,它将允许我们创建服务器。
pnpm add express --filter server
--filter
标志是PNPM强大的功能,可以在MonorePo设置中管理软件包。此标志使您可以指定要应用命令的包装。因此,它允许您从项目中的任何位置执行针对特定文件夹的PNPM命令。
Read more about the filter flag.要确保正确执行命令,使用 package.json **文件中指定的相同工作区
name
是必不可少的。例如,如果** package.json中的属性name
是 server 文件夹中的server
,请使用server
作为--filter
flag的值来瞄准相应的工作区。
在MonorePo设置中,从根文件夹中运行命令通常很方便以避免频繁的文件夹切换。
pnpm --filter <package-name> <command>
# pnpm --filter server dev
对于组织良好且结构化的代码库,建议使用导出start
方法的 server.js 文件。该方法可以在我们的入口点 index.js 中使用,除了启动Express Server以外,它可能还包括其他功能。
const express = require('express');
const start = () => {
const app = express();
app.use('/', (req, res, next) => {
return res.send('JavaScript is AWESOME');
});
app.listen(4000, () => {
console.info(`Server running on port 4000...`);
});
};
module.exports = { start };
为了简单起见,我们对端口号进行了硬编码。但是,后来,我们将探索如何处理环境变量。
。要启动服务器,请在main index.js 文件中调用开始方法。
const server = require('./server');
server.start();
我们可以使用以前使用用于运行JavaScript文件的相同方法启动服务器。
node src/index.js
# Server running on port 4000...
要访问服务器,打开您喜欢的浏览器并导航到http://localhost:4000,该浏览器调用端点/
。到达那里后,您应该观察到消息“ JavaScript很棒” 在页面上显示。
与Nodemon一起热重新加载
我们将使用 nodemon 而不是Node.js 19中引入的
--watch
标志。 Nodemon提供了更适合我们需求的高级功能,尤其是打字稿集成。当前,Node--watch
选项缺乏足够的自定义,因此我们选择了Nodemon作为我们的首选解决方案。
Nodemon是一个实用程序,可为node.js应用程序提供热加载,允许无需手动停止和重新启动服务器的实时更新。由于开发人员可以立即看到其变化的影响,因此此功能大大加快了开发过程。
Nodemon通常被安装为开发依赖性。您可以通过:
安装它
pnpm add -D nodemon --filter server
安装Nodemon后,您可以使用它来启动您的应用程序,通过在您的命令中用nodemon
替换node
。此功能启用热加载,该重新加载将在检测到代码更改时自动重新启动服务器。
nodemon src/index.js
# Server running on port 4000...
最好包括启动服务器的脚本。虽然当前命令可能短而直接,但随着时间的推移,它可能需要其他参数,具体取决于实例(例如, prod , test , dev )。
。
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"dev": "nodemon src/index.ts",
}
...
}
您可以在root package.json 文件中包含一个脚本以从任何文件夹运行服务器。该脚本将允许您快速启动服务器,无论您当前的工作目录如何。
{
"name": "bugsight",
"version": "1.0.0",
"description": "",
"scripts": {
"dev:server": "pnpm --filter server dev"
},
...
}
类似于添加依赖项,我们使用-—filter
标志指定软件包和附加参数来指示应执行的脚本(dev
)。
要从根文件夹运行服务器,请使用此命令:
pnpm run dev:server
另外,如果您喜欢从任何其他文件夹运行它,则可以在命令中包含-w
标志。
pnpm -w run dev:server
现在,我们已经探索了Nodemon及其对服务器开发的好处,让我们继续前进,我们将在其中讨论与Express.
集成打字稿的内容。将打字稿与express.js集成
首先,我们必须为我们的打字稿配置创建一个共享软件包。在软件包目录中,创建一个名为 tsconfig 的新文件夹。
使用终端,导航到 tsconfig 文件夹并初始化 package.json 文件。
pnpm init
建议将软件包名称更改为@bugsight/tsconfig
,以防止与其他NPM软件包的命名冲突。使用示波器名称,如果您决定发布软件包,则可以避免NPM注册表上现有软件包的问题。
{
"name": "@bugsight/tsconfig",
"version": "1.0.0",
"description": "",
...
}
安装打字稿作为开发依赖性。在此工作区中,打字稿是所需的唯一依赖。
pnpm add -D typescript
要为我们的服务器,客户端或其他软件包创建共享的tsconfig文件,我们需要生成 tsconfig.base.json.json 文件,该文件用作TyxpeRction的配置文件。该文件在编译过程中指导打字稿编译器,以将我们的项目转换为JavaScript。您可以手动创建 tsconfig.base.json 文件或使用npx tsc --init
命令,
使用预设编译器选项生成默认文件。
{
"compilerOptions": {
"noImplicitAny": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"alwaysStrict": true,
"useUnknownInCatchVariables": true,
"allowUnreachableCode": false,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true
}
}
无论您使用 Angular 或 express ,这些规则只是几个示例。这就是为什么我将它们包含在共享软件包中的原因。但是,您可以根据自己的喜好调整打字稿设置。此外,将来,我可能会引入其他规则以进一步增强配置。
有关可用规则的完整列表,请参考the official docs。
现在我们已经完成了配置包,我们可以将其添加为 package.json.json 服务器的文件。
{
"name": "server",
"main": "src/index.js",
"dependencies": {
"@bugsight/tsconfig": "workspace:*",
"express": "^4.18.2"
}
...
}
PNPM引入了
workspace:*
协议。当您使用此协议向项目添加软件包时,您可以确保使用最新的代码并在项目之间保持一致性。
要继续执行以下命令以安装所需的软件包或任何丢失的软件包:
pnpm install --filter server
让我们仔细看看PNPM如何处理安装的软件包。
bugsight 是您的monorepo的根,而根部的 node_modules 是共享的node_modules。 客户端和服务器是您的应用程序,每个应用程序都有 node_modules 目录,其中包含共享 node_modules中依赖项的符号链接文件夹。
>共享的tsconfig
软件包安装在root node_modules 目录中,并在每个应用程序的 node_modules 中链接。客户端和服务器可以在保持磁盘效率并避免重复安装的同时使用共享的tsconfig
软件包。
monorepos通常会导致许多 node_modules 目录,这些目录可以使用 vscode 之类的编辑器混乱工作空间。但是, vscode 提供了一种最小化此视觉混乱的方法。修改设置使您可以隐藏所有 node_modules 文件夹中的文件夹。
为此,打开您的设置文件并添加以下内容:
"files.exclude": {
"**/node_modules": true
}
另外,您可以通过排除node_modules和pnpm-lock文件来避免污染搜索结果:
"search.exclude": {
"**/node_modules": true,
"pnpm-lock.yaml": true
}
我建议在此项目中使用Visual Studio代码中的专用配置文件。创建一个单独的配置文件使您可以配置针对本项目要求量身定制的特定设置,扩展和偏好,而不会干扰其他项目并引起冲突。
Read more about profiles and how to use them effectively.
接下来,让我们在服务器目录中创建一个 tsconfig.json 文件。这将有助于扩展基本配置,并为服务器提供专门的额外设置。
{
"extends": "@bugsight/tsconfig/tsconfig.base.json",
"include": ["src/**/*"],
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"esModuleInterop": true,
"moduleResolution": "node",
"outDir": "dist",
"baseUrl": "./src"
}
}
重要的是要提到,我们指的是 tsconfig.base.json 文件,而无需使用相对路径。取而代之的是,我们以名称为名,因为它已安装为 node_modules 目录中的依赖项。
使用TypeScript时,它不会直接运行。它通过一个称为转溶的过程,该过程将其转换为JavaScript。 Transpiler使用 tsconfig.json 文件中定义的设置来决定如何将打字稿代码转换为JavaScript。
让我们更改 index.js 和 server.js 的文件扩展名为 .ts 。此外,更新文件的内容以使用ES6模块,该模块需要使用import
和export
语法,如下所示:
import express from 'express';
const start = () => {
const app = express();
app.use('/', (req, res, next) => {
return res.send('JavaScript is AWESOME');
});
app.listen(4000, () => {
console.info(`Server running on port 4000...`);
});
};
export { start };
import * as server from './server';
server.start();
您会遇到TS文件中出现的错误。这是您的打字稿配置正确设置的好兆头。
Express Import的第一个错误表示express
软件包是用JavaScript编写的,没有导出的模块。
发生第二个错误是因为三个参数具有隐式any
类型,这与我们的基本TSCONFIG中的noImplicitAny
规则相对。此错误实际上连接到第一个错误。如果express
软件包有导出的模块,则这些参数将自动收到适当的类型。
尽管在JavaScript中对Node.js和Express进行了编码,但是Typescript的类型检查仍然可以通过合并DefinitelyTyped repository on GitHub的类型定义来使用。该存储库为各种JavaScript库(包括node.js and express)提供了一流的打字稿定义。为了避免从一开始创建类型声明,您可以使用@types/{packageName}
模式有效地找到这些类型 - 陈述。
使用此命令将类型定义作为开发依赖项安装(-D
)。建议这样做,因为这些定义仅在开发过程中需要,并且对于生产构建不是必需的。
pnpm add -D @types/node @types/express --filter server
与@types/node
相关的软件包包含API的定义,例如file
,process
和path
。安装这些类型应解决打字稿文件中的任何错误。
我们需要更新 package.json 文件以使用打字稿版本。
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"dev": "nodemon src/index.ts"
}
}
让我们尝试启动服务器。
pnpm run dev:server
有望发生错误。
我们需要使用ts-node软件包在node.js环境中执行打字稿文件。此软件包可以随时编译打字稿文件,将其转换为a
可以使用nodemon
执行的JavaScript文件。
,由于 ts-node Integration,Nodemon在版本1.19.0的发行版中,包括对打字稿文件的内置支持。这意味着不再需要手动配置。虽然节点CLI默认情况下仍用于执行JavaScript文件,但Nodemon将自动切换到使用TS-Node用于打字稿文件。这使得开发过程在使用Typescript和Nodemon时更加简单。
重新运行开发脚本后,基于打字稿的Express Server应该在没有问题的情况下运行。访问 https://localhost:4000 确认该消息显示在屏幕上。
接下来,我们将包括两个其他脚本:build
和prod
。这些脚本在项目的开发,测试和部署阶段中起着至关重要的作用。
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"build": "tsc --build",
"dev": "nodemon src/index.ts",
"prod": "npm run build && node ./dist/index.js"
}
}
build
脚本的目的是将我们的打字稿代码编译到JavaScript中。它使用tsc
命令指定。此命令将我们的打字稿文件转换为JavaScript对应物,将它们输出在** tsconfig.json **中的outDir
4444parameter定义的 ./ dist 目录中。
prod
脚本在生产模式下为我们的应用程序服务。它通过从./dist
目录运行编译的index.js
来启动生产服务器。通常在使用build
脚本构建应用程序后执行此脚本。
就像dev
脚本一样,您可以在路由 package.json 文件中包含两个脚本,因此可以从任何地方访问它们。
{
"name": "bugsight",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build:server": "pnpm --filter server build",
"dev:server": "pnpm --filter server dev",
"prod:server": "pnpm --filter server prod"
}
}
推到github
前往Github和create a new repository。您无需使用 readme 或 .gitignore 。
初始化它。在您的本地项目目录中,使用终端通过使用命令来初始化 git (如果尚未完成):
pnpm run dev:server
然后,使用命令:
添加新的GitHub存储库的URL
git remote add origin <your-github-repo-url>
# git remote add origin https://github.com/ayoubkhial/bugsight.git
这将您的本地存储库连接到github上的遥控器。
在将代码推到GitHub存储库之前,设置 .gitignore 文件以指定存储库中不包括哪些文件或目录是必不可少的。这对于MonorePo设置尤其至关重要,以免用不必要的文件使您的存储库混乱。
在您项目的根目录中,创建一个名为 .gitignore 的新文件。
node_modules
dist
.vscode
.DS_Store
Using this configuration, you can prevent specific directories and files, such as node_modules, dist (usually containing compiled code), .DS_Store (created by macOS), and the .vscode folder containing your IDE workspace settings, from being included when pushing to GitHub.
现在您可以上台,提交并将本地提交推向远程存储库
git add .
git commit -m "Initial commit"
git push -u origin master
结论
总而言之,将打字稿集成在平均堆栈中可以通过提供强大的键入和直观的错误检查来显着增强您的开发体验。
您可以在this repository中找到完整的代码源;随意给它一个星星。
如果您想跟上这个系列,请考虑在我发表文章后立即获得更新。