Nextjs는 웹 서버 따로 설정하지 않아도 서버 측 렌더링 웹 앱을 쉽게 만들 수 있음 .
대부분의 경우 필요없지만 express나 fastify 등 별도의 서버가 필요한 경우도 있다.
Nextjs로 리펙토링
리펙토링을 nextjs로 진행해 기존 로직이나 미들웨어를 유지하고 싶은 경우
멀티테넌시 지원이 필요한 경우
멀티 도메인 (현재 호스트명에 따라 선택적으로 렌더링하는 기능)이 있지만 도메인이 많거나 워크 플로를 단순화 해야하는 경우
세부 제어가 필요하는 경우
const { parse } = require('url');
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
async function main() {
try {
await app.prepare();
// next 대신 요청 처리
const handle = app.getRequestHandler();
const server = express();
server
.get('/', (req, res) => {
res.send('Hello World!');
})
.get('/about', (req, res) => {
const { query } = parse(req.url, true);
app.render(req, res, '/about', query);
})
.get('/api/greet', (req, res) => {
res.json({ name: req.query?.name ?? 'unknown' });
})
.get(/_next\/.+/, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
})
.listen(3000, () => console.log('server ready'));
} catch (err) {
console.log(err.stack);
}
}
main();
next를 렌더링 하려면 2번째 get 처럼 app.render 함수를 이용한다.
3번째 server.get처럼 api/greet가 nextjs의 페이지로 연결하지않고 가짜 api를 제공한다.
vercel이나 netlify같은 서비스에 배포할 수 없음
(서버리스 펑션으로 할 순 있으나 복잡)
{
"presets" : ["next/bable"]
}
describe("cutTextToLength cuts a string when it's too long", () => {
test('Should cut a string that exceeds 10 characters', () => {
const initialString = 'This is a 34 character long string';
const cutResult = cutTextToLength(initialString, 10);
expect(cutResult).toEqual('This is a ...');
});
test("Should not cut a string if it's shorter than 10 characters", () => {
// ~~~
});
});
/**
* @jest-environment jsdom
*/
describe('ArticleCard', () => {
test('Generated link should be in the correct format', () => {
const component = render(<ArticleCard {...article} />);
const link = component.getByRole('link').getAttribute('href');
expect(link).toBe('/articles/healthy-summer-meloncarrot-soup-u12w3o0d');
});
}
yarn add -D cypress
로 설치{
"baseUrl":"http://localhost:3000"
}
describe('articles APIs', () => {
// 1
it(`should correctly set application/json header`, () => {
cy.request('http://localhost:3000/api/articles')
.its('headers')
.its('content-type')
.should('include', 'application/json');
});
// 2
it(`should correctly return a 200 status code`, () => {
cy.request('http://localhost:3000/api/articles')
.its('status').should('be.equal', 200);
});
// 3
it(`should correctly return a list of articles`, (done) => {
cy.request('http://localhost:3000/api/articles')
.its('body')
.each((article) => {
expect(article).to.have.keys('id', 'title', 'body', 'author', 'image');
expect(article.author).to.have.keys('id', 'name');
expect(article.image).to.have.keys('url', 'author');
done();
});
});
// 4
it(`should correctly return a an article given an ID`, (done) => {
cy.request('http://localhost:3000/api/article?id=u12w3o0d').then(({ body }) => {
expect(body).to.have.keys('id', 'title', 'body', 'author', 'image');
expect(body.author).to.have.keys('id', 'name');
expect(body.image).to.have.keys('url', 'author');
done();
});
});
}
“e2e” : “start-server-and=test ‘yarn build && yarn start’ [http://localhost:3000](http://localhost:3000) cypress”