esbuild로 리액트 앱 만들기
How to configure esbuild to create a react app
Esbuild은 새로운 자바스크립트 번들러입니다. Go로 작성되었으며 매우 빠릅니다. 웹팩 없이 처음부터 핫 리로드 앱으로 반응을 생성하는 데 사용하겠습니다.
여기에서 코드를 확인할 수 있습니다repos.
초기화
폴더 프로젝트를 만들고 초기화합니다.
yarn init
{
"name": "esbuild-static",
"version": "1.0.0"
}
종속성 설치
yarn add esbuild dotenv react react-dom styled-components
그런 다음 devdependencies를 추가하십시오.
yarn add --dev typescript @types/react @types/react-dom @types/styled-components @types/node serve-handler @types/serve-handler
타이프스크립트 구성
tsconfig.json
파일을 추가합니다.
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"module": "commonjs",
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"moduleResolution": "node",
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"skipLibCheck": true,
"esModuleInterop": true,
"jsx": "react"
},
"include": ["src"],
"exclude": ["**/node_modules", "**/.*/"]
}
에스빌드 구성
esbuild
폴더를 만든 다음 dev.js
및 prod.js
파일을 추가합니다.
dev 구성 감시 파일이 변경되고 핫 리로드 및 정적 파일에 대한 서버를 시작합니다. 환경 변수도 추가할 수 있습니다.
const { spawn } = require('child_process');
const esbuild = require('esbuild');
const { createServer, request } = require('http');
require('dotenv').config();
const handler = require('serve-handler');
const clientEnv = { 'process.env.NODE_ENV': `'dev'` };
const clients = [];
Object.keys(process.env).forEach((key) => {
if (key.indexOf('CLIENT_') === 0) {
clientEnv[`process.env.${key}`] = `'${process.env[key]}'`;
}
});
const openBrowser = () => {
setTimeout(() => {
const op = { darwin: ['open'], linux: ['xdg-open'], win32: ['cmd', '/c', 'start'] };
if (clients.length === 0) spawn(op[process.platform][0], ['http://localhost:3000']);
}, 1000);
};
esbuild
.build({
entryPoints: ['src/index.tsx'],
bundle: true,
minify: true,
define: clientEnv,
outfile: 'dist/index.js',
sourcemap: 'inline',
watch: {
onRebuild(error) {
setTimeout(() => {
clients.forEach((res) => res.write('data: update\n\n'));
}, 1000);
console.log(error || 'client rebuilt');
},
},
})
.catch((err) => {
console.log(err);
process.exit(1);
});
esbuild.serve({ servedir: './' }, {}).then((result) => {
createServer((req, res) => {
const { url, method, headers } = req;
if (req.url === '/esbuild') {
return clients.push(
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Access-Control-Allow-Origin': '*',
Connection: 'keep-alive',
}),
);
}
const path = url.split('/').pop().indexOf('.') ? url : `/index.html`;
const proxyReq = request({ hostname: '0.0.0.0', port: 8000, path, method, headers }, (prxRes) => {
res.writeHead(prxRes.statusCode, prxRes.headers);
prxRes.pipe(res, { end: true });
});
req.pipe(proxyReq, { end: true });
return null;
}).listen(5010);
createServer((req, res) => {
return handler(req, res, { public: 'dist' });
}).listen(3000);
openBrowser();
});
const esbuild = require('esbuild');
require('dotenv').config();
const clientEnv = { 'process.env.NODE_ENV': `'production'` };
for (const key in process.env) {
if (key.indexOf('CLIENT_') === 0) {
clientEnv[`process.env.${key}`] = `'${process.env[key]}'`;
}
}
esbuild
.build({
entryPoints: ['src/index.tsx'],
bundle: true,
minify: true,
define: clientEnv,
outfile: 'dist/index.js',
})
.catch(() => process.exit(1));
Eslint 구성
에스린트를 설치합니다.
yarn add --dev eslint eslint-config-react-app @typescript-eslint/eslint-plugin @typescript-eslint/parser
.eslintrc.js
파일을 추가합니다.
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ['react-app'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 13,
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
};
스크립트
package.json에 스크립트 추가
"scripts": {
"build": "node esbuild/prod",
"type-check": "tsc --noEmit",
"lint": "eslint src/**/*.ts src/**/*.tsx",
"start": "nodemon --watch dist --exec 'yarn type-check & yarn lint' & node esbuild/dev"
},
리액트 앱
src
폴더에서 index.tsx
파일을 추가합니다.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import GlobalStyle from './globalStyle';
ReactDOM.render(
<>
<GlobalStyle />
<App />
</>,
document.getElementById('root'),
);
핫 리로드 도구
esbuild dev server reload를 수신하려면 개발용 후크를 추가해야 합니다.
import { useEffect } from 'react';
const useHMR = () => {
useEffect(() => {
if (process.env.NODE_ENV !== 'production') {
new EventSource('http://localhost:5010/esbuild').onmessage = () => window.location.reload();
}
}, []);
};
export default useHMR;
스타일 구성 요소가 있는 CSS
styled-components
로 전체 스타일 추가
import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
`;
export default GlobalStyle
앱
Fanaly는 앱 구성 요소를 만듭니다.
import React, { FC } from 'react';
import useHMR from './useHMR';
import Logo from './Logo';
const App: FC = () => {
useHMR();
return (
<div className='App'>
<header className='App-header'>
<Logo />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a className='App-link' href='https://reactjs.org' target='_blank' rel='noopener noreferrer'>
Learn React
</a>
</header>
</div>
);
};
export default App;
정적 파일
dist
폴더에 정적 파일을 추가합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="React App" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
<script src="/index.js"></script>
그런 다음 다른 파일을 만듭니다. favicon.ico
, manifest.json
, logo192.png
운영
개발 서버를 시작합니다.
yarn start
생산을 위한 빌드
yarn build
Now let's go to code
Reference
이 문제에 관하여(esbuild로 리액트 앱 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/simonboisset/create-react-app-with-esbuild-4bic
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
yarn init
{
"name": "esbuild-static",
"version": "1.0.0"
}
yarn add esbuild dotenv react react-dom styled-components
yarn add --dev typescript @types/react @types/react-dom @types/styled-components @types/node serve-handler @types/serve-handler
{
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"module": "commonjs",
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"moduleResolution": "node",
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"skipLibCheck": true,
"esModuleInterop": true,
"jsx": "react"
},
"include": ["src"],
"exclude": ["**/node_modules", "**/.*/"]
}
const { spawn } = require('child_process');
const esbuild = require('esbuild');
const { createServer, request } = require('http');
require('dotenv').config();
const handler = require('serve-handler');
const clientEnv = { 'process.env.NODE_ENV': `'dev'` };
const clients = [];
Object.keys(process.env).forEach((key) => {
if (key.indexOf('CLIENT_') === 0) {
clientEnv[`process.env.${key}`] = `'${process.env[key]}'`;
}
});
const openBrowser = () => {
setTimeout(() => {
const op = { darwin: ['open'], linux: ['xdg-open'], win32: ['cmd', '/c', 'start'] };
if (clients.length === 0) spawn(op[process.platform][0], ['http://localhost:3000']);
}, 1000);
};
esbuild
.build({
entryPoints: ['src/index.tsx'],
bundle: true,
minify: true,
define: clientEnv,
outfile: 'dist/index.js',
sourcemap: 'inline',
watch: {
onRebuild(error) {
setTimeout(() => {
clients.forEach((res) => res.write('data: update\n\n'));
}, 1000);
console.log(error || 'client rebuilt');
},
},
})
.catch((err) => {
console.log(err);
process.exit(1);
});
esbuild.serve({ servedir: './' }, {}).then((result) => {
createServer((req, res) => {
const { url, method, headers } = req;
if (req.url === '/esbuild') {
return clients.push(
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Access-Control-Allow-Origin': '*',
Connection: 'keep-alive',
}),
);
}
const path = url.split('/').pop().indexOf('.') ? url : `/index.html`;
const proxyReq = request({ hostname: '0.0.0.0', port: 8000, path, method, headers }, (prxRes) => {
res.writeHead(prxRes.statusCode, prxRes.headers);
prxRes.pipe(res, { end: true });
});
req.pipe(proxyReq, { end: true });
return null;
}).listen(5010);
createServer((req, res) => {
return handler(req, res, { public: 'dist' });
}).listen(3000);
openBrowser();
});
const esbuild = require('esbuild');
require('dotenv').config();
const clientEnv = { 'process.env.NODE_ENV': `'production'` };
for (const key in process.env) {
if (key.indexOf('CLIENT_') === 0) {
clientEnv[`process.env.${key}`] = `'${process.env[key]}'`;
}
}
esbuild
.build({
entryPoints: ['src/index.tsx'],
bundle: true,
minify: true,
define: clientEnv,
outfile: 'dist/index.js',
})
.catch(() => process.exit(1));
yarn add --dev eslint eslint-config-react-app @typescript-eslint/eslint-plugin @typescript-eslint/parser
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ['react-app'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 13,
sourceType: 'module',
},
plugins: ['react', '@typescript-eslint'],
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
};
"scripts": {
"build": "node esbuild/prod",
"type-check": "tsc --noEmit",
"lint": "eslint src/**/*.ts src/**/*.tsx",
"start": "nodemon --watch dist --exec 'yarn type-check & yarn lint' & node esbuild/dev"
},
src
폴더에서 index.tsx
파일을 추가합니다.import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import GlobalStyle from './globalStyle';
ReactDOM.render(
<>
<GlobalStyle />
<App />
</>,
document.getElementById('root'),
);
핫 리로드 도구
esbuild dev server reload를 수신하려면 개발용 후크를 추가해야 합니다.
import { useEffect } from 'react';
const useHMR = () => {
useEffect(() => {
if (process.env.NODE_ENV !== 'production') {
new EventSource('http://localhost:5010/esbuild').onmessage = () => window.location.reload();
}
}, []);
};
export default useHMR;
스타일 구성 요소가 있는 CSS
styled-components
로 전체 스타일 추가import { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
`;
export default GlobalStyle
앱
Fanaly는 앱 구성 요소를 만듭니다.
import React, { FC } from 'react';
import useHMR from './useHMR';
import Logo from './Logo';
const App: FC = () => {
useHMR();
return (
<div className='App'>
<header className='App-header'>
<Logo />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a className='App-link' href='https://reactjs.org' target='_blank' rel='noopener noreferrer'>
Learn React
</a>
</header>
</div>
);
};
export default App;
정적 파일
dist
폴더에 정적 파일을 추가합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="React App" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
<script src="/index.js"></script>
그런 다음 다른 파일을 만듭니다. favicon.ico
, manifest.json
, logo192.png
운영
개발 서버를 시작합니다.
yarn start
생산을 위한 빌드
yarn build
Now let's go to code
Reference
이 문제에 관하여(esbuild로 리액트 앱 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/simonboisset/create-react-app-with-esbuild-4bic
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="React App" />
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
<script src="/index.js"></script>
개발 서버를 시작합니다.
yarn start
생산을 위한 빌드
yarn build
Now let's go to code
Reference
이 문제에 관하여(esbuild로 리액트 앱 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/simonboisset/create-react-app-with-esbuild-4bic텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)