Monorepo设置中的NextJS,Express,Typescript等

While building a pet-project that uses nextjs, I realized that I wanted to have a fully separated monorepo package setup for nextjs and my go-to nodejs API framework express while also making express the custom server for nextjs instead of the built-in server that NextJS is bundled with.

在构建一个使用nextjs的宠物项目时,我意识到我想为nextjs和我的go-to nodejs API框架表达一个完全分离的monorepo软件包设置,同时还表达对nextjs而不是内置服务器的自定义服务器与NextJS捆绑在一起的。

TL;DR: Check out the code here

TL; DR:在 此处 签出代码

Before reinventing the wheel I spent quite some time looking for someone that had already done this but I found nothing, if you know of something similar leave it in the comments section so I can compare my solution to theirs.

在重新发明轮子之前,我花了很多时间寻找已经做到这一点的人,但是我什么也没发现,如果您知道类似的内容,请在评论部分中保留,以便我可以将自己的解决方案与他们的解决方案进行比较。

The closest thing I knew about was an official example for setting up a custom-server in nextjs. With this example at hand then the most important thing was to move the server code to its own package and making sure it worked well for both nextjs and my own API endpoints.

我最了解的是在nextjs中设置自定义服务器的官方示例。 有了这个例子,最重要的是将服务器代码移到其自己的程序包中,并确保它对nextjs和我自己的API端点都适用。

The objective of this post is not to explain how to setup a typescript monorepo with lerna and yarn. For an in-depth explanation, you can check https://medium.com/@NiGhTTraX/how-to-set-up-a-typescript-monorepo-with-lerna-c6acda7d4559

这篇文章的目的不是要解释如何用lerna和yarn设置打字稿monorepo。 有关详细说明,请查看https://medium.com/@NiGhTTraX/how-to-set-up-a-typescript-monorepo-with-lerna-c6acda7d4559

Overall in this example, I set up three packages:

总体而言,在此示例中,我设置了三个软件包:

  • web-client

    网络客户端

Contains all the nextjs pages, components for the client-side work

包含所有nextjs页面,客户端工作的组件

  • web-server

    网络服务器

Contains all the express code for serving the API endpoints that your project might need and also to handle nextjs requests.

包含用于服务项目可能需要的API端点以及处理nextjs请求的所有表达代码。

  • web-server-logger

    网络服务器记录器

Contains an example package, a logger with bunyan to be used in the web-server package.

包含一个示例程序包,一个带有bunyan的记录器,可在Web服务器程序包中使用。

The key things I had to realize after lots of trial and error was the way nextjs works with custom servers where the main code to explain is:

经过反复试验,我必须意识到的关键是nextjs与自定义服务器一起工作的方式,其中要解释的主要代码是:

网络服务器nextjs处理程序 (web-server nextjs handler)

import { Router, Request, Response } from 'express';
import URL from 'url';
import nextapp from '@jcalderonzumba/web-client';
const router = Router();
const handler = nextapp.getRequestHandler();
// TODO: FIX deprecation warning. (NextJS requires the query string parameter)router.get('/*', (req: Request, res: Response) => {
// eslint-disable-next-line
return handler(req, res, { ...URL.parse(req.url, true) });
});
export default router;

网络服务器启动器 (web-server starter)

import { logger } from '@jcalderonzumba/web-server-logger';
import express from 'express';
import cookiesMiddleware from 'universal-cookie-express';
import bodyParser from 'body-parser';
import compression from 'compression';
import cookieParser from 'cookie-parser';
import * as routes from './routes';
import nextapp from '@jcalderonzumba/web-client';
const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
const app = express();
app.set('x-powered-by', false);
app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(cookiesMiddleware());
app.use('/api', routes.serverAPIRouter);
app.use('/', routes.nextJSRouter);
(async (): Promise<void> => {
try {
await nextapp.prepare();
app.listen(port, listenPortError => {
if (listenPortError) {
logger.error(
{ err: listenPortError },
`[ExpressServer] Error starting server ${listenPortError}`
);
throw listenPortError;
}
logger.info(`[ExpressServer] Server ready, listening on port ${port}`);
});
} catch (err) {
logger.error(
{ err },
'[ExpressServer] Unexpected error while starting server'
);
}
})();

In order for express to be the custom server for nextjs, we need to connect express js routes with nextjs request handler and we also need to prepare nextjs before starting the server.

为了使express成为nextjs的定制服务器,我们需要将express js路由与nextjs请求处理程序连接,并且还需要在启动服务器之前准备nextjs。

In both files, we make use of a “nextapp” that lives in a different package. This is the key issue I found while migrating from the custom-server example to a monorepo so I had to create a module withing the web-client package that could be imported in web-server.

在这两个文件中,我们都使用位于另一个软件包中的“ nextapp”。 这是我从定制服务器示例迁移到monorepo时发现的关键问题,因此我必须创建一个带有可导入Web服务器的Web客户端程序包的模块。

网络客户端nextapp模块 (web-client nextapp module)

// file index.ts
import next from 'next';
import { resolve } from 'path';
const dev = process.env.NODE_ENV !== 'production';
let nextDir = __dirname;
if (nextDir.indexOf('/dist') !== -1) {
nextDir = resolve(__dirname, '../');
}
const nextapp = next({
dev,
dir: nextDir
});
export default nextapp;

To be able to compile both this single-file module (index.ts) and also nextjs I had to modify nextjs default build dir and also create a specific tsconfig file for said module

为了能够编译此单文件模块(index.ts)和nextjs,我必须修改nextjs的默认生成目录,并为该模块创建一个特定的tsconfig文件

next.config.js (next.config.js)

module.exports = {
poweredByHeader: false,
distDir: 'dist/next'
};

tsconfig.app.json (tsconfig.app.json)

{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"noEmit": false,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": "./"
},
"include": ["src/index.ts"]
}

With this configuration, nextjs stuff will be compiled to dist/next/** and the single file nextapp module will land in dist/index.js.

通过这种配置,nextjs的内容将被编译为dist / next / **,单个文件nextapp模块将位于dist / index.js中。

I had to create this structure because in development mode nextjs deletes the build dir so it will also kill index.js nextapp module and that can be troublesome for the web-server as it depends on dist/index.js.

我必须创建此结构,因为在开发模式下,nextjs会删除构建目录,因此它也会杀死index.js nextapp模块,这对于Web服务器可能是麻烦的,因为它取决于dist / index.js。

Once you do these changes you will have a successfully connected express-server and nextjs where all your requests will be handled by express and if needed forwarded to nextjs handlers that live in a different package.

完成这些更改后,您将拥有成功连接的express-server和nextjs,其中所有请求都将由express处理,并在需要时转发到位于其他程序包中的nextjs处理程序。

我为什么要做所有这些? (Why did I do all of this?)

挑战与学习 (Challenge and learning)

I am a Director of Engineering at Travelperk, (we are hiring engineers, join us), which means my work time needs to be spent on other things than coding, however, I still enjoy coding especially with nodejs/react/nextjs/typescript, therefore when I failed to find a solution for what I wanted to do in my pet-project I knew it was a “challenge accepted” situation.

我是Travelperk的工程总监(我们正在招聘工程师,请加入我们 ),这意味着我的工作时间需要花在编码上以外的其他事情上,但是,我仍然喜欢编码,尤其是使用nodejs / react / nextjs / typescript时,因此,当我无法为自己的宠物项目想解决的问题找到解决方案时,我知道那是“接受挑战”的情况。

Image for post

Having said that, I have not coded professionally for over eight years so if my approach is not what you would have done, leave your suggestions in the comments section.

话虽如此,但我从事专业编码已有八年多了,因此,如果我的方法不符合您的要求,请在注释部分中留下您的建议。

关注点分离 (Separation of concerns)

This setup allows me to separate concerns of client-side code and server-side code, so I can have a package that only cares for my nextjs pages, components, styles, CSS, etc. and another package that host the endpoints I might need to consume, middlewares, etc.

通过此设置,我可以将对客户端代码和服务器端代码的关注分开,因此我可以拥有一个仅关心我的nextjs页面,组件,样式,CSS等的程序包,以及另一个托管我可能需要的端点的程序包。消费,中间件等

私人页面上的安全性。 (Security on private pages.)

I’m not saying nextjs is not secure or that it can not be secured but with this setup, to add an additional layer of protection of private page I can just add a middleware in express that forces a user to be logged in to access that content and since nextjs is SSR, every time someone not authenticated tries to access that page, express will stop it before it even reaches nextjs.

我并不是说nextjs不安全或不能安全,但是通过此设置,要添加一个私有页面保护层,我可以添加一个中间件以表达方式,强制用户登录以访问该中间件。内容,并且由于nextjs是SSR,因此每次未经身份验证的人尝试访问该页面时,express都会在到达nextjs之前停止它。

清洁程序package.json (Cleaner package.json)

I have built pet-projects using the traditional nextjs custom-server approach of everything in the same package and that ends up with lots of libraries that are only needed for the server, once again, you are mixing stuff that should be separated.

我使用传统的nextjs自定义服务器方法在同一个程序包中的所有内容上构建了宠物项目,最终产生了很多只需要服务器使用的库,再一次,您正在混合应分开的内容。

翻译自: https://medium.com/@jcalderonzumba/nextjs-express-typescript-etc-in-a-monorepo-setup-fa8217b3699b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值