์๋ฒ๋ฆฌ์ค Webpack vs Esbuild
- #serverless
- #esbuild
- #webpack
- #swc
๋ค์ด๊ฐ๋ฉฐ
์๋
ํ์ธ์! ์๋์์์ ๋ฐฑ์๋ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๊ณ ์๋ ์ ๊ทผ์๋ผ๊ณ ํฉ๋๋ค.
์๋์ ๋ฐฑ์๋ ์๋น์ค๋ ๋๋ถ๋ถ ์๋ฒ๋ฆฌ์ค๋ก ๊ตฌ์ฑ๋์ด ์๊ณ , serverless-webpack๋ฅผ ํ์ฉํ๊ณ ์์์ต๋๋ค.
์ต๊ทผ์ ts-loader/ts-jest ๋ฅผ swc-loader/swc-jest ๋ก ๋ณ๊ฒฝํ์๊ณ ,
์ด๋ฒ์ serverless-esbuild ๋ก ๋ฐ๊พธ๊ฒ ๋ ๊ณผ์ ๊ณผ ํจ๊ณผ๋ฅผ ์๊ฐํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
- NestJS
- typeorm / MySQL
- Serverless Framework
๋น๊ต ๊ฒฐ๊ณผ๋ถํฐ ๋ฏธ๋ฆฌ ๋ณด๊ณ ์ถ์ผ์๋ฉด, ์๋ ๋งํฌ๋ฅผ ๋๋ฌ๋ณด์ธ์~
SWC
SWC๋ Rust๋ก ์ ์๋ ๋น๋ํด์
๋๋ค. ๋ฒ๋ค๋ฌ๋ ์์ง ์์
์ค์ผ๋ก ๋์ด์์ด์, webpack์ swc-loader๋ง ์ ์ฉํด์ ์ฌ์ฉํ์ต๋๋ค.
๊ธฐ์กด์ ์ฌ์ฉํ๋ nest build
์ ์๋๋ฅผ ๋น๊ตํด๋ณด๋ฉด, ์์ฒญ๋ ์๋ ํฅ์์ ๋๋ ์ ์์ต๋๋ค.
๊ฒ๋ค๊ฐ ts-jest๋ swc-jest๋ก ๋์ฒดํ ์ ์์ต๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก ๊ต์ฅํ ๋นจ๋ผ์ง ๊ฑธ ์ ์ ์์ต๋๋ค.
nest build | swc | |
๋น๋ ์๊ฐ | 10.41s | 0.67s |
ts-jest | swc-jest | |
ํ ์คํธ ์๊ฐ | 16s | 5s |
์ฌ์ฉ๋ package.json script๋ ์๋์ ๊ฐ์ต๋๋ค.
"build:webpack": "nest build --webpack",
"build:swc": "swc --ignore \"**/*.spec.ts\" --delete-dir-on-start --out-dir dist/src/ src/",
ํ ์คํธ๋ jest ์ค์ ์ transform ๋ถ๋ถ๋ง ๋ณ๊ฒฝํ๋ฉด ๋ฉ๋๋ค.
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"transform": {
"^.+\\.(t|j)s$": "swc-jest"
},
์ฌ์ฉํ swc ์ค์ ํ์ผ(.swcrc)๋ ์๋์ ๊ฐ์ต๋๋ค.
{
"sourceMaps": true,
"module": {
"type": "commonjs",
"lazy": true
},
"jsc": {
"target": "es2021",
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true,
"baseUrl": "./"
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
},
"paths": {
"@src/*": ["./src/*"]
},
"keepClassNames": true
}
}
๋ก์ปฌ ํ๊ฒฝ์์์ ๋น๋ ์๋์ ํ ์คํธ ์๋๋ ํฐ ํฅ์์ด ์์์ง๋ง, ์ค์ ๋ฐฐํฌ์์๋ ํฐ ์ฐจ์ด๋ฅผ ๋๋ ์ ์์์ต๋๋ค.
Esbuild
esbuild๋ Go ์ธ์ด๋ก ์์ฑ๋ ๋น๋ํด์ ๋๋ค. serverless-esbuild๋ผ๋ ํ๋ฌ๊ทธ์ธ๋ ์์ด์ serverless-webpack์ ๋์ฒดํ ์ ์์ต๋๋ค.
serverless.yml ์ esbuild ํญ๋ชฉ ์ค์ ์ด ํ์ํฉ๋๋ค.
plugins:
- serverless-esbuild
custom:
esbuild:
bundle: true
minify: false
target: 'node16'
packager: yarn
plugins: plugins.js
external:
- '@nestjs/microservices'
- '@nestjs/websockets/socket-module'
- 'class-transformer/storage'
- 'nock'
- 'mock-aws-s3'
- 'fastify-swagger'
- 'pg-native'
- ์ฒ์์ external ์ค์ ์์ด
serverless package
๋ช ๋ น์ ์คํํ๋ฉด Error๊ฐ ๋ฐ์ํฉ๋๋ค. ํ๋์ฉ external๋ก ์ค์ ํด์ฃผ๋ฉด ์ ๋์ํฉ๋๋ค.
esbuild๋ decorator ์ง์์ด ๋์ง ์์์, esbuild-plugin-tsc๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
๋ .env ํ์ผ์ ๋น๋ ์์ ์ ํฌํจ์ํค๊ธฐ ์ํ plugin๋ ํ์ํ์ต๋๋ค.
plugins.js
const esbuildPluginTsc = require('esbuild-plugin-tsc');
module.exports = serverless => {
const envCopyPlugin = {
name: 'env-copy',
setup(build) {
build.onEnd(() => {
const fs = require('fs');
const path = require('path');
fs.cpSync(`.env.${serverless.service.provider.stage}`, path.join('.esbuild/.build', '.env'), {
force: true,
dereference: true
});
});
}
};
return [esbuildPluginTsc(), envCopyPlugin];
};
๋ก์ปฌ ๋น๋๋ฅผ ์ํ esbuild.js ํ์ผ์ ๋ง๋ค์ด์ค๋๋ค.
const esbuild = require('esbuild');
const path = require('node:path');
const esbuildPluginTsc = require('esbuild-plugin-tsc');
const cwd = process.cwd();
const outfile = path.resolve(cwd, 'dist/src/main.js');
const tsconfig = path.resolve(cwd, 'tsconfig.json');
const entryPoints = [path.resolve(cwd, 'src/main.ts')];
const config = {
platform: 'node',
target: ['node16'],
bundle: true,
keepNames: true,
plugins: [esbuildPluginTsc()],
tsconfig,
entryPoints,
outfile,
external: ['./node_modules/*']
};
(async () => {
await esbuild.build(config);
})();
package.json
"build:esbuild": "node esbuild.js",
nest build | swc | esbuild | |
๋น๋ ์๊ฐ | 10.41s | 0.67s | 1.1s |
๋น๋ ์๊ฐ์ swc๋ณด๋ค ์ฝ๊ฐ ๋๋ฆฌ์ง๋ง, ๊ธฐ์กด
nest build
์ ๋น๊ตํ๋ฉด ์์ฒญ ๋นจ๋ผ์ง ๊ฑธ ๋ณผ ์ ์์ต๋๋ค.
๋ ํ๋์ ํจ๊ณผ๋ ๋ฒ๋ค๋ง ์ฉ๋์ด ๊ต์ฅํ ์ค์ด๋ค์์ต๋๋ค.
NestJS ์ด์
https://github.com/nestjs/nest-cli/issues/731#issuecomment-772330860
๋น๋ ์๊ฐ์ด ๋ง์ด ๋จ์ถ๋์ง๋ง, swc์ esbuild ๋ชจ๋ type checking์ด ๋์ง ์๊ธฐ ๋๋ฌธ์, nest์์ ๊ณต์์ ์ผ๋ก ์ง์ํ์ง ์๋๋ค๊ณ ํฉ๋๋ค.
Webpack vs Esbuild
์ ํฌ API ์๋น์ค๋ค์ ๋๋ฉ์ธ ๋ณ๋ก ๋ถ๋ฆฌ๊ฐ ๋์ด ์๋๋ฐ, ๊ทธ ์ค ๊ฐ๋จํ ๋๋ฉ์ธ ํ๋๋ฅผ ๋น๊ตํด๋ณด๊ฒ ์ต๋๋ค.
serverless-webpack (ts-loader) | serverless-webpack (swc-loader) | serverless-esbuild | |
๋น๋+๋ฐฐํฌ ์๊ฐ (serverless deploy) | 82s | 82s | 61s |
ํ ์คํธ(57 tests) ์๊ฐ | 16s (ts-jest) | 5s (swc-jest) | 5s (swc-jest) |
์ฉ๋ | 14.9MB | 14.9MB | 2.9MB |
- ํ
์คํธ ํ๊ฒฝ
- MacBook Pro 2019
- 2.6 GHz 6-Core Intel Core i7
- 16 GB 2667 MHz DDR4
- macOS Ventura 13.0
๋ง๋ฌด๋ฆฌ
๋น๋ ์๊ฐ์ ํฐ ์ฐจ์ด๋ ๋์ง ์์์ง๋ง, ๋ฒ๋ค๋ง๋ ์ฉ๋์ด ํฌ๊ฒ ์ค์ด๋ ํจ๊ณผ๊ฐ ์์ด์ ์ต์ข
์ ์ผ๋ก serverless-esbuild
์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ๊ฒ ๋์์ต๋๋ค.
test ํด๋ esbuild๋ก ๊ฐ๋ฅํ๊ฒ ์์๊น ํด์ esbuild-jest๋ฅผ ์๋ํด๋ดค์ง๋ง, ์ค์ ์ ์ด๋ ค์์ ๊ฒช๋ค๊ฐ ์ด๋ฏธ ์ ์ฌ์ฉํ๊ณ ์๋ swc-jest
๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
์ฌ๋ด์ด์ง๋ง ์๋๋ esbuild ๋์
์ ์ฐ์ฐํ ์ด๋ฃจ์ด์ก์ต๋๋ค. ์ฒ์ ๋ชฉํ๋ ์๋ yarn berry์ PnP
๋์
์ด ๋ชฉ์ ์ด์๊ณ , webpack์์ yarn berry ์ค์ ์ ์ด๋ ค์์ ๊ฒช๋ค๊ฐ esbuild๊ฐ yarn berry ์ง์์ด ์๋๋ค๊ณ ํด์ esbuild๋ฅผ ํ
์คํธํด๋ณด๊ฒ ๋์์ต๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก yarn berry ๋์
์ ์คํจํ์ต๋๋ค. ๋น๋์ ๋ฐฐํฌ๊น์ง ์ฑ๊ณตํ์ง๋ง, runtime์์ ํด๊ฒฐํ์ง ๋ชปํ ์ค๋ฅ๋ค์ด ๊ณ์ ๋ฐ์ํ์ต๋๋ค.
ํ์ง๋ง ๋๋ถ์ esbuild๋ฅผ ํ
์คํธํด ๋ณธ ๊ณ๊ธฐ๊ฐ ๋๊ณ , ๋ฒ๋ค๋ง ์ฉ๋์ด ํฌ๊ฒ ์ค์ด๋ ํจ๊ณผ๋ฅผ ๋ณผ ์ ์์ด์ ์ฝ์ง์ ์๊ฐ๋ค์ด ํ๋์ง ์์๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋๊น์ง ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค~ ๐