제퍼넷 로고

esbuild 번들러 소개 — SitePoint

시간

에스빌드 JavaScript, TypeScript, JSX 및 CSS 코드를 최적화할 수 있는 빠른 번들러입니다. 이 기사는 esbuild를 빠르게 익히는 데 도움이 되며 다른 의존성 없이 자신만의 빌드 시스템을 만드는 방법을 보여줍니다.

차례
  1. 에스빌드는 어떻게 작동합니까?
  2. 왜 번들인가요?
  3. 에스빌드를 사용하는 이유
  4. 왜 에스빌드를 피해야 할까요?
  5. 매우 빠른 시작
  6. 예시 프로젝트
  7. 사업 개요
  8. 에스빌드 구성
  9. 자바스크립트 번들링
  10. CSS 번들링
  11. 보고, 재건하고, 서빙하기
  12. 요약

에스빌드는 어떻게 작동합니까?

다음과 같은 프레임워크 물다 esbuild를 채택했지만 자신의 프로젝트에서 독립 실행형 도구로 esbuild를 사용할 수 있습니다.

  • esbuild 번들 JavaScript 코드 다음과 같은 번들러와 유사한 방식으로 단일 파일로 롤업. 이것은 esbuild의 주요 기능으로, 모듈을 해결하고, 구문 문제를 보고하고, 사용하지 않는 기능을 제거하기 위한 "트리 셰이크", 로깅 및 디버거 문을 지우고, 코드를 축소하고, 소스 맵을 제공합니다.

  • esbuild 번들 CSS 코드 단일 파일로. 다음과 같은 전처리기를 완전히 대체할 수는 없습니다. 말대꾸 or 포스트 CSS, 그러나 esbuild는 부분, 구문 문제, 중첩, 인라인 자산 인코딩, 소스 맵, 자동 접두사 및 축소를 처리할 수 있습니다. 그게 당신이 필요한 전부일 수 있습니다.

  • esbuild는 로컬 개발 서버도 제공합니다. 자동 번들링 및 핫 리로딩을 사용하므로 새로고침할 필요가 없습니다. 에서 제공하는 모든 기능이 없습니다. 브라우저동기화, 그러나 대부분의 경우에 충분합니다.

아래 코드는 esbuild 개념을 이해하는 데 도움이 되므로 프로젝트에 대한 추가 구성 기회를 조사할 수 있습니다.

왜 번들인가요?

코드를 단일 파일로 묶으면 다양한 이점이 있습니다. 다음은 그 중 일부입니다.

  • 유지 관리가 더 쉬운 더 작고 독립적인 소스 파일을 개발할 수 있습니다.
  • 번들링 프로세스 중에 코드를 린트, 수정 및 구문 검사할 수 있습니다.
  • 번들러는 사용하지 않는 기능을 제거할 수 있습니다. 나무를 흔드는
  • 동일한 코드의 대체 버전을 묶고 이전 브라우저, Node.js, Deno 등에 대한 대상을 만들 수 있습니다.
  • 단일 파일이 여러 파일보다 빠르게 로드되며 브라우저에 ES 모듈 지원이 필요하지 않음
  • 프로덕션 레벨 번들링은 코드를 축소하고 로깅 및 디버깅 명령문을 제거하여 성능을 향상시킬 수 있습니다.

에스빌드를 사용하는 이유

JavaScript 번들러와 달리 esbuild는 강력한 병렬 처리를 구현하는 컴파일된 Go 실행 파일입니다. Rollup, Parcel 또는 Webpack보다 최대 XNUMX배 더 빠릅니다. 프로젝트 수명 동안 몇 주 동안의 개발 시간을 절약할 수 있습니다.

또한 esbuild는 다음을 제공합니다.

  • JavaScript, TypeScript, JSX 및 CSS용 내장 번들링 및 컴파일
  • 명령줄, JavaScript 및 Go 구성 API
  • ES 모듈 및 CommonJS 지원
  • 감시 모드 및 실시간 재로딩 기능이 있는 로컬 개발 서버
  • 플러그인 더 많은 기능을 추가하기 위해
  • 포괄적 인 문서온라인 실험 도구

왜 에스빌드를 피해야 할까요?

작성 당시 esbuild는 버전 0.18에 도달했습니다. 신뢰할 수 있지만 아직 베타 제품입니다.

esbuild는 자주 업데이트되며 버전 간에 옵션이 변경될 수 있습니다. 그만큼 선적 서류 비치 특정 버전을 고수하는 것이 좋습니다. 업데이트할 수 있지만 구성 파일을 마이그레이션하고 새 문서를 조사하여 주요 변경 사항을 찾아야 할 수 있습니다.

또한 esbuild는 TypeScript 유형 검사를 수행하지 않으므로 여전히 다음을 실행해야 합니다. tsc -noEmit.

매우 빠른 시작

필요한 경우 다음을 사용하여 새 Node.js 프로젝트를 만듭니다. npm init그런 다음 esbuild를 개발 종속성으로 로컬에 설치합니다.

npm install esbuild --save-dev --save-exact

설치에는 약 9MB가 필요합니다. 설치된 버전을 보려면 다음 명령을 실행하여 작동하는지 확인하십시오.

./node_modules/.bin/esbuild --version

또는 이 명령을 실행하여 CLI 도움말을 봅니다.

./node_modules/.bin/esbuild --help

CLI API를 사용하여 항목 스크립트 번들(myapp.js) 및 가져온 모든 모듈을 단일 파일로 bundle.js. esbuild는 기본 브라우저 대상 즉시 호출 함수 표현식(IIFE) 형식을 사용하여 파일을 출력합니다.

./node_modules/.bin/esbuild myapp.js --bundle --outfile=bundle.js

여러분의 시간과 재능으로 다른 방법으로 esbuild 설치 Node.js를 사용하지 않는 경우.

예시 프로젝트

예제 파일을 다운로드하고 Github에서 esbuild 구성. Node.js 프로젝트이므로 다음을 사용하여 단일 esbuild 종속성을 설치합니다.

npm install

소스 파일 빌드 srcbuild 다음을 사용하여 개발 서버를 시작합니다.

npm start

이제 localhost:8000 실시간 시계를 보여주는 웹 페이지를 보려면 브라우저에서. CSS 파일을 업데이트할 때 src/css/ or src/css/partials, esbuild는 코드를 다시 묶고 스타일을 실시간으로 다시 로드합니다.

esbuild 예제 시계 프로젝트

PR 기사 Ctrl|명령 + Ctrl|명령 서버를 중지합니다.

다음을 사용하여 배포용 프로덕션 빌드를 만듭니다.

npm run build

다음에서 CSS 및 JavaScript 파일을 검사합니다. build 소스 맵 없이 축소된 버전을 볼 수 있는 디렉토리.

사업 개요

실시간 클럭 페이지는 build 소스 파일을 사용하는 디렉토리 src.

XNUMXD덴탈의 package.json 파일은 XNUMX개를 정의합니다. npm 스크립트. 첫 번째는 다음을 삭제합니다. build 예배 규칙서:

"clean": "rm -rf ./build",

번들링이 발생하기 전에 init 스크립트 실행 clean, 새로운 생성 build 디렉토리 및 사본:

  1. 정적 HTML 파일 src/html/index.htmlbuild/index.html
  2. 정적 이미지 src/images/build/images/
"init": "npm run clean && mkdir ./build && cp ./src/html/* ./build/ && cp -r ./src/images ./build",

An esbuild.config.js 파일은 JavaScript API를 사용하여 esbuild 번들링 프로세스를 제어합니다. 이는 다루기 힘들 수 있는 CLI API에 옵션을 전달하는 것보다 관리하기 쉽습니다. 안 npm bundle 스크립트 실행 init 다음 node ./esbuild.config.js:

"bundle": "npm run init && node ./esbuild.config.js",

마지막 두 npm 스크립트 실행 bundle 또는 production or development 전달 된 매개 변수 ./esbuild.config.js 빌드를 제어하려면:

"build": "npm run bundle -- production",
"start": "npm run bundle -- development"

인셀덤 공식 판매점인 ./esbuild.config.js 실행되면 최소화를 생성할지 여부를 결정합니다. production 파일(기본값) 또는 development 자동 업데이트, 소스 맵 및 라이브 리로딩 서버가 있는 파일. 두 경우 모두 esbuild 번들:

  • 항목 CSS 파일 src/css/main.cssbuild/css/main.css
  • 항목 JavaScript 파일 scr/js/main.jsbuild/js/main.js

에스빌드 구성

package.json 있다 "type" of "module" 그래서 모두 .js 파일은 ES 모듈을 사용할 수 있습니다. 그만큼 esbuild.config.js 스크립트 가져오기 esbuild 및 세트 productionModetrue 생산을 위해 묶을 때 또는 false 개발을 위해 번들링할 때:

import { argv } from 'node:process';
import * as esbuild from 'esbuild'; const productionMode = ('development' !== (argv[2] || process.env.NODE_ENV)), target = 'chrome100,firefox100,safari15'.split(','); console.log(`${ productionMode ? 'production' : 'development' } build`);

번들 대상

참고로 대상 변수 구성에서 사용할 브라우저 및 버전 번호의 배열을 정의합니다. 이는 번들 출력에 영향을 미치고 특정 플랫폼을 지원하도록 구문을 변경합니다. 예를 들어 esbuild는 다음을 수행할 수 있습니다.

  • 확장 네이티브 CSS 중첩 전체 선택자로(다음과 같은 경우 중첩이 유지됩니다. "Chrome115" 유일한 표적이었다)
  • 필요한 경우 CSS 공급업체 접두사 속성 추가
  • 폴리필 ?? nullish 병합 연산자
  • 제거 # 개인 클래스 필드에서

브라우저뿐만 아니라 타겟팅도 가능합니다. nodees 버전 es2020esnext (최신 JS 및 CSS 기능).

자바스크립트 번들링

번들을 생성하는 가장 간단한 API:

await esbuild.build({ entryPoints: ['myapp.js'], bundle: true outfile: 'bundle.js'
});

위에서 사용된 CLI 명령을 복제합니다.

./node_modules/.bin/esbuild myapp.js --bundle --outfile=bundle.js

예제 프로젝트는 파일 감시와 같은 고급 옵션을 사용합니다. 장기 실행 빌드가 필요합니다. 문맥 구성을 설정합니다.


const buildJS = await esbuild.context({ entryPoints: [ './src/js/main.js' ], format: 'esm', bundle: true, target, drop: productionMode ? ['debugger', 'console'] : [], logLevel: productionMode ? 'error' : 'info', minify: productionMode, sourcemap: !productionMode && 'linked', outdir: './build/js' });

에스빌드 제공 수십 가지 구성 옵션. 여기에 사용된 것들에 대한 요약은 다음과 같습니다.

  • entryPoints 번들링을 위한 파일 진입점의 배열을 정의합니다. 예제 프로젝트에는 다음 위치에 하나의 스크립트가 있습니다. ./src/js/main.js.

  • format 출력 형식을 설정합니다. 예제는 esm하지만 선택적으로 설정할 수 있습니다. iife 오래된 브라우저 또는 commonjs Node.js의 경우.

  • bundle 로 설정 true 가져온 모듈을 출력 파일에 인라인합니다.

  • target 위에 정의된 대상 브라우저의 배열입니다.

  • drop 배열입니다 console 및 / 또는 debugger 제거할 진술. 이 경우 프로덕션 빌드는 둘 다 제거하고 개발 빌드는 유지합니다.

  • logLevel 로깅 세부 정보를 정의합니다. 위의 예는 프로덕션 빌드 중 오류와 개발 빌드 중 더 자세한 정보 메시지를 보여줍니다.

  • minify 주석과 공백을 제거하고 가능한 경우 변수와 함수의 이름을 변경하여 코드 크기를 줄입니다. 예제 프로젝트는 프로덕션 빌드 중에 축소되지만 예쁘다 개발 빌드 중 코드.

  • sourcemap 로 설정 linked (개발 모드에서만) 링크된 소스 맵을 생성합니다. .map 브라우저 개발자 도구에서 원본 소스 파일과 줄을 사용할 수 있습니다. 당신은 또한 설정할 수 있습니다 inline 번들 파일 내에 소스 맵을 포함하려면, both 둘 다 생성하거나 external ~를 생성하기 위해 .map 번들 JavaScript에서 링크가 없는 파일.

  • outdir 번들 파일 출력 디렉토리를 정의합니다.

컨텍스트 개체의 호출 rebuild() 빌드를 한 번 실행하는 방법 — 일반적으로 프로덕션 빌드의 경우:

await buildJS.rebuild();
buildJS.dispose(); 

컨텍스트 개체의 호출 watch() 실행을 유지하고 파일이 변경될 때 자동으로 다시 빌드하는 방법:

await buildJS.watch();

컨텍스트 개체는 후속 빌드가 점진적으로 처리되고 이전 빌드의 작업을 재사용하여 성능을 향상시키도록 합니다.

JavaScript 입력 및 출력 파일

항목 src/js/main.js 파일 가져오기 dom.jstime.js 의 모듈 lib 하위 폴더. 클래스가 있는 모든 요소를 ​​찾습니다. clock 텍스트 내용을 매초 현재 시간으로 설정합니다.

import * as dom from './lib/dom.js';
import { formatHMS } from './lib/time.js'; const clock = dom.getAll('.clock'); if (clock.length) { console.log('initializing clock'); setInterval(() => { clock.forEach(c => c.textContent = formatHMS()); }, 1000); }

dom.js 두 가지 기능을 내보냅니다. main.js 둘 다 가져오지만 사용 getAll():

 export function get(selector, doc = document) { return doc.querySelector(selector);
} export function getAll(selector, doc = document) { return Array.from(doc.querySelectorAll(selector));
}

time.js 두 가지 기능을 내보냅니다. main.js 수입 formatHMS(), 그러나 모듈의 다른 기능을 사용합니다.

 function timePad(n) { return String(n).padStart(2, '0');
} export function formatHM(d = new Date()) { return timePad(d.getHours()) + ':' + timePad(d.getMinutes());
} export function formatHMS(d = new Date()) { return formatHM(d) + ':' + timePad(d.getSeconds());
}

결과 개발 번들이 제거됨(나무 흔들림) get()dom.js 하지만 모두 포함 time.js 기능. 소스 맵도 생성됩니다.


function getAll(selector, doc = document) { return Array.from(doc.querySelectorAll(selector));
} function timePad(n) { return String(n).padStart(2, "0");
} function formatHM(d = new Date()) { return timePad(d.getHours()) + ":" + timePad(d.getMinutes());
} function formatHMS(d = new Date()) { return formatHM(d) + ":" + timePad(d.getSeconds());
} var clock = getAll(".clock");
if (clock.length) { console.log("initializing clock"); setInterval(() => { clock.forEach((c) => c.textContent = formatHMS()); }, 1e3);
} 

(esbuild는 고쳐 쓰기 letconstvar 정확성과 속도를 위해.)

결과 프로덕션 번들은 코드를 322자로 축소합니다.

function o(t,c=document){return Array.from(c.querySelectorAll(t))}function e(t){return String(t).padStart(2,"0")}function l(t=new Date){return e(t.getHours())+":"+e(t.getMinutes())}function r(t=new Date){return l(t)+":"+e(t.getSeconds())}var n=o(".clock");n.length&&setInterval(()=>{n.forEach(t=>t.textContent=r())},1e3);

CSS 번들링

예제 프로젝트의 CSS 번들링은 위의 JavaScript와 유사한 컨텍스트 객체를 사용합니다.


const buildCSS = await esbuild.context({ entryPoints: [ './src/css/main.css' ], bundle: true, target, external: ['/images/*'], loader: { '.png': 'file', '.jpg': 'file', '.svg': 'dataurl' }, logLevel: productionMode ? 'error' : 'info', minify: productionMode, sourcemap: !productionMode && 'linked', outdir: './build/css' });

그것은 정의 external 파일 및 경로의 배열로서의 옵션 제외 빌드에서. 예제 프로젝트에서 src/images/ 디렉토리가 build HTML, CSS 또는 JavaScript에서 직접 참조할 수 있도록 합니다. 이것이 설정되지 않은 경우 esbuild는 파일을 출력에 복사합니다. build/css/ 디렉토리에서 사용할 때 background-image 또는 이와 유사한 속성.

XNUMXD덴탈의 loader 옵션은 esbuild가 파일로 참조되지 않은 가져온 파일을 처리하는 방법을 변경합니다. external 유산. 이 예에서:

  • SVG 이미지는 데이터 URI로 인라인됩니다.
  • PNG 및 JPG 이미지가 build/css/ 디렉토리 및 파일로 참조

CSS 입력 및 출력 파일

항목 src/css/main.css 파일 가져오기 variables.csselements.css 인사말 partials 하위 폴더:


@import './partials/variables.css';
@import './partials/elements.css';

variables.css 기본 사용자 지정 속성을 정의합니다.


:root { --font-body: sans-serif; --color-fore: #fff; --color-back: #112;
}

elements.css 모든 스타일을 정의합니다. 메모:

  • 전에, body 외부에서 로드된 배경 이미지가 있습니다. images 예배 규칙서
  • 전에, h1 안에 내포되어 있다 header
  • 전에, h1 인라인될 배경 SVG가 있습니다.
  • 대상 브라우저에는 공급업체 접두사가 필요하지 않습니다.

*, *::before, ::after { box-sizing: border-box; font-weight: normal; padding: 0; margin: 0;
} body { font-family: var(--font-body); color: var(--color-fore); background: var(--color-back) url(/images/web.png) repeat; margin: 1em;
} header { & h1 { font-size: 2em; padding-left: 1.5em; margin: 0.5em 0; background: url(../../icons/clock.svg) no-repeat; } } .clock { display: block; font-size: 5em; text-align: center; font-variant-numeric: tabular-nums;
}

결과 개발 번들은 중첩된 구문을 확장하고 SVG를 인라인하고 소스 맵을 생성합니다.


:root { --font-body: sans-serif; --color-fore: #fff; --color-back: #112;
} *,
*::before,
::after { box-sizing: border-box; font-weight: normal; padding: 0; margin: 0;
}
body { font-family: var(--font-body); color: var(--color-fore); background: var(--color-back) url(/images/web.png) repeat; margin: 1em;
}
header h1 { font-size: 2em; padding-left: 1.5em; margin: 0.5em 0; background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>*{fill:none;stroke:%23fff;stroke-width:1.5;stroke-miterlimit:10}</style></defs><circle cx="12" cy="12" r="10.5"></circle><circle cx="12" cy="12" r="0.95"></circle><polyline points="12 4.36 12 12 16.77 16.77"></polyline></svg>') no-repeat;
}
.clock { display: block; font-size: 5em; text-align: center; font-variant-numeric: tabular-nums;
} 

생성된 프로덕션 번들은 코드를 764자로 축소합니다(여기서는 SVG가 생략됨).

:root{--font-body: sans-serif;--color-fore: #fff;--color-back: #112}*,*:before,:after{box-sizing:border-box;font-weight:400;padding:0;margin:0}body{font-family:var(--font-body);color:var(--color-fore);background:var(--color-back) url(/images/web.png) repeat;margin:1em}header h1{font-size:2em;padding-left:1.5em;margin:.5em 0;background:url('data:image/svg+xml,<svg...></svg>') no-repeat}.clock{display:block;font-size:5em;text-align:center;font-variant-numeric:tabular-nums}

보고, 재건하고, 서빙하기

나머지 esbuild.config.js 종료하기 전에 프로덕션 빌드를 위해 한 번 스크립트 번들:

if (productionMode) { await buildCSS.rebuild(); buildCSS.dispose(); await buildJS.rebuild(); buildJS.dispose(); }

개발 빌드 중에 스크립트는 계속 실행되고 파일 변경 사항을 감시하며 자동으로 다시 번들됩니다. 그만큼 buildCSS 컨텍스트는 다음과 함께 개발 웹 서버를 시작합니다. build/ 루트 디렉토리로:

else { await buildCSS.watch(); await buildJS.watch(); await buildCSS.serve({ servedir: './build' }); }

다음을 사용하여 개발 빌드를 시작합니다.

npm start

그런 다음 localhost:8000 페이지를 보려면 .

Browsersync와 달리 실시간으로 다시 로드하려면 개발 페이지에 자체 코드를 추가해야 합니다. 변경 사항이 발생하면 esbuild는 다음을 통해 업데이트에 대한 정보를 보냅니다. 서버 전송 이벤트. 가장 간단한 옵션은 변경 사항이 발생할 때 페이지를 완전히 다시 로드하는 것입니다.

new EventSource('/esbuild').addEventListener('change', () => location.reload());

예제 프로젝트는 CSS 컨텍스트 개체를 사용하여 서버를 만듭니다. JavaScript 변경 사항을 수동으로 새로 고치는 것을 선호하기 때문입니다. esbuild가 CSS와 JS 업데이트 모두에 대한 이벤트를 보내는 방법을 찾을 수 없었기 때문입니다! HTML 페이지에는 전체 페이지 새로 고침(핫 리로드) 없이 업데이트된 CSS 파일을 대체하는 다음 스크립트가 포함되어 있습니다.

<script type="module">
// esbuild server-sent event - live reload CSS
new EventSource('/esbuild').addEventListener('change', e => { const { added, removed, updated } = JSON.parse(e.data); // reload when CSS files are added or removed if (added.length || removed.length) { location.reload(); return; } // replace updated CSS files Array.from(document.getElementsByTagName('link')).forEach(link => { const url = new URL(link.href), path = url.pathname; if (updated.includes(path) && url.host === location.host) { const css = link.cloneNode(); css.onload = () => link.remove(); css.href = `${ path }?${ +new Date() }`; link.after(css); } }) });

esbuild는 현재 JavaScript 핫 리로딩을 지원하지 않습니다 — 어쨌든 나는 그것을 믿을 것입니다!

요약

약간의 구성으로 esbuild는 모든 프로젝트의 개발 및 생산 빌드 요구 사항을 처리하기에 충분할 수 있습니다.

포괄적 인 세트가 있습니다. 플러그인 고급 기능이 필요한 경우. 여기에는 종종 Sass, PostCSS 또는 유사한 빌드 도구가 포함되므로 esbuild를 작업 실행기로 효과적으로 사용합니다. 당신은 항상 할 수 있습니다 나만의 플러그인 만들기 더 가벼운 맞춤형 옵션이 필요한 경우.

esbuild를 사용한지 XNUMX년이 되었습니다. 유사한 번들러에 비해 속도가 놀랍고 새로운 기능이 자주 나타납니다. 유일한 사소한 단점은 유지 관리가 필요한 주요 변경 사항입니다.

esbuild는 통합된 올인원 빌드 도구라고 주장하지 않지만 아마도 그 목표에 더 가깝습니다. 로마.

spot_img

최신 인텔리전스

spot_img