در دنیای توسعه وب، یکی از مسائل اساسی که با آن مواجه میشویم، سرعت و بهینگی در فرآیند بیلد و تولید فایلهای استاتیک است. این مشکل به خصوص در پروژههای بزرگ و پیچیده، به چالش کشیده میشود. در این مقاله، با یکی از ابزارهای جدید و کارآمد در این زمینه، یعنی esbuild باندلر در جاوااسکریپت، آشنا خواهیم شد. ما به بررسی نحوه استفاده از این ابزار قدرتمند و کارایی آن پرداخته و به شما نشان خواهیم داد که چگونه میتوانید فرآیند بیلد پروژههای وب خود را بهبود بخشید.
esbuild چیست؟
esbuild یک باندلر فوقسریع و با کارایی بالا برای جاوااسکریپت است. این ابزار توسط Evan Wallace توسعه داده شده و باعث تجربه بهتری در توسعه و بهینهسازی وبسایتها و برنامههای وب میشود. با استفاده از این باندلر، میتوانید به سرعت فایلهای جاوااسکریپت خود را باندل کرده و بهینه کنید.این باندلر می تواند کدهای JavaScript، TypeScript، JSX و CSS را بهینه کند.
esbuild چگونه کار می کند؟
فریمورک هایی مانند Vite از esbuild استفاده کرده اند، اما شما می توانید از esbuild به عنوان یک ابزار مستقل در پروژه های خود استفاده کنید.
esbuild کد جاوا اسکریپت را به روشی مشابه باندلرهایی مانند Rollup در یک فایل واحد قرار می دهد. این تابع اصلی esbuild است و ماژولها را حل میکند، مشکلات سینتکسی را گزارش میکند، «tree-shakes» را برای حذف توابع استفادهنشده، پاک میکند، عبارات ورود و اشکالزدایی را پاک میکند، کد را کوچک میکند و نقشههای منبع را ارائه میدهد.
esbuild کدهای CSS را در یک فایل واحد دسته بندی می کند. این یک جایگزین کامل برای پیش پردازندههایی مانند Sass یا PostCSS نیست، اما esbuild میتواند جزئی، مسائل سینتکس، تودرتو، رمزگذاری asset های درون خطی، نقشههای منبع، پیشوند خودکار و کوچکسازی را مدیریت کند. این ممکن است تمام چیزی باشد که شما نیاز دارید.
esbuild همچنین یک سرور توسعه محلی را با بستهبندی خودکار و بارگذاری مجدد داغ ارائه میکند، بنابراین نیازی به بهروزرسانی نیست. همه ویژگی های ارائه شده توسط Browsersync را ندارد، اما برای اکثر موارد به اندازه کافی خوب است.
در ادامه مقاله به شما در درک مفاهیم esbuild کمک می کند تا بتوانید فرصت های پیکربندی بیشتر پروژه های خود را بررسی کنید.
چرا باندل؟
بسته بندی کد در یک فایل واحد مزایای مختلفی را ارائه می دهد. در اینجا به برخی از آنها اشاره می کنیم:
- میتوانید فایلهای منبع کوچکتر و مستقل ایجاد کنید که نگهداری آنها آسانتر است.
- میتوانید کدها را در طول فرآیند بستهبندی review، زیباسازی، و سینتکس آن را بررسی کنید.
- باندلر میتواند توابع استفادهنشده را حذف کند که به tree-shakes معروف است.
- میتوانید نسخههای جایگزین همان کد را بستهبندی کنید و اهدافی را برای مرورگرهای قدیمیتر، Node.js، Deno و غیره ایجاد کنید.
- تک فایل ها سریعتر از چندین فایل بارگیری می شوند و مرورگر به پشتیبانی ماژول ES نیاز ندارد.
- بستهبندی در سطح تولید میتواند عملکرد را با کوچک کردن کد و حذف عبارات ورود و اشکالزدایی بهبود بخشد.
چرا از esbuild استفاده کنیم؟
برخلاف باندلرهای جاوا اسکریپت، esbuild یک فایل اجرایی Go کامپایل شده است که پردازش موازی سنگین را پیاده سازی می کند. این سریع و تا صد برابر سریعتر از Rollup، Parcel یا Webpack است. این می تواند هفته ها در زمان توسعه در طول عمر یک پروژه صرفه جویی کند.
علاوه بر این، esbuild همچنین ارائه می دهد:
- بستهبندی داخلی و کامپایل برای جاوا اسکریپت، TypeScript، JSX و CSS
- APIهای پیکربندی خط فرمان، جاوا اسکریپت و Go
- پشتیبانی از ماژول های ES و CommonJS
- یک سرور توسعه محلی با حالت تماشا و بارگذاری مجدد زنده
- پلاگین هایی برای افزودن قابلیت های بیشتر
- مستندات جامع و یک ابزار آزمایش آنلاین
چرا از esbuild اجتناب کنید؟
در زمان نگارش، esbuild به نسخه 0.19 رسیده است. قابل اعتماد است اما هنوز یک محصول بتا است.
esbuild اغلب به روز می شود و گزینه ها ممکن است بین نسخه ها تغییر کنند. مستندات توصیه میکنند که از یک نسخه خاص استفاده کنید. میتوانید آن را بهروزرسانی کنید، اما ممکن است لازم باشد فایلهای پیکربندی خود را منتقل کنید و در اسناد جدید جستجو کنید تا تغییرات شکستهکننده را کشف کنید.
همچنین توجه داشته باشید که esbuild بررسی نوع TypeScript را انجام نمی دهد، بنابراین همچنان باید tsc -noEmit
را اجرا کنید.
نحوه نصب esbuild
در صورت لزوم، یک پروژه Node.js جدید با npm init
ایجاد کنید، سپس esbuild را به صورت محلی به عنوان یک وابستگی توسعه نصب کنید:
npm install esbuild --save-dev --save-exact
برای نصب به حدود 9 مگابایت نیاز دارد. با اجرای این دستور بررسی کنید که کار می کند تا نسخه نصب شده را ببینید:
./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
اگر از Node.js استفاده نمی کنید، می توانید esbuild را به روش های دیگری نصب کنید.
ایجاد یک پروژه با esbuild
ابتدا vite را نصب کنید:
npm install -g create-vite
سپس برای شروع، یک پوشه جدید بسازید و به آن وارد شوید. به عنوان مثال:
create-vite my-vite-esbuild-project
cd my-esbuild-project
فایل vite.config.js
باز کنید در پوشه پروژه و تنظیمات esbuild را به آن اضافه کنید:
import { defineConfig } from 'vite'
import { viteEsbuildPlugin } from 'vite-esbuild-plugin'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [viteEsbuildPlugin()],
})
برای اجرای پروژه:
npm run dev
فایل های CSS و جاوا اسکریپت را در فهرست ساخت بررسی کنید تا نسخه های کوچک شده را بدون نقشه منبع ببینید.
در زیر ما کد های پروژه Clock ساده داریم :
//main.js
import * as dom from './lib/dom.js';
import { formatHMS } from './lib/time.js';
// get clock element
const clock = dom.getAll('.clock');
if (clock.length) {
console.log('initializing clock');
setInterval(() => {
clock.forEach(c => c.textContent = formatHMS());
}, 1000);
}
و
// DOM libary
// fetch first node from selector
export function get(selector, doc = document) {
return doc.querySelector(selector);
}
// fetch all nodes from selector
export function getAll(selector, doc = document) {
return Array.from(doc.querySelectorAll(selector));
}
و
// time library
// return 2-digit value
function timePad(n) {
return String(n).padStart(2, '0');
}
// return time in HH:MM format
export function formatHM(d = new Date()) {
return timePad(d.getHours()) + ':' + timePad(d.getMinutes());
}
// return time in HH:MM:SS format
export function formatHMS(d = new Date()) {
return formatHM(d) + ':' + timePad(d.getSeconds());
}
در فایل index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>esbuild testing</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<script type="module" src="/js/main.js"></script>
<link rel="stylesheet" href="/css/main.css" />
</head>
<body>
<header>
<h1>Realtime clock</h1>
</header>
<main>
<time class="clock"></time>
</main>
<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);
}
})
});
</script>
</body>
</html>
حال در فایل package.json می توانید پنج اسکریپت npm را تعریف کنید. اولی دایرکتوری build
را حذف می کند:
"clean": "rm -rf ./build",
قبل از اینکه هر building اتفاق بیفتد، یک اسکریپت init
و clean
اجرا میشود، یک دایرکتوری build
جدید ایجاد میکند و کپی میکند:
یک فایل HTML استاتیک از src/html/index.html
تا build/index.html
تصاویر استاتیک از src/images/
تا build/images/
"init": "npm run clean && mkdir ./build && cp
./src/html/* ./build/ && cp -r ./src/images ./build",
یک فایل esbuild.config.js
فرآیند بستهبندی esbuild را با استفاده از JavaScript API کنترل میکند. مدیریت این کار راحت تر از انتقال گزینه ها به CLI API است که ممکن است سخت شود. یک اسکریپت باندل npm در init
و سپس node ./esbuild.config.js
اجرا می شود:
"bundle": "npm run init && node ./esbuild.config.js",
دو اسکریپت آخر npm باندل اجرا میشوند که یک پارامتر تولید یا توسعه به esbuild.config.js/.
برای کنترل build ارسال شده است:
"build": "npm run bundle -- production",
"start": "npm run bundle -- development"
وقتی esbuild.config.js/.
اجرا میشود، تعیین میکند که آیا باید فایلهای تولیدی کوچک (پیشفرض) ایجاد کند یا فایلهای توسعه را با بهروزرسانیهای خودکار، نقشههای منبع، و یک سرور بارگذاری مجدد زنده ایجاد کند. در هر دو مورد، esbuild bundles:
ورودی فایل CSS درsrc/css/main.css
به build/css/main.css
ورودی فایل جاوا اسکریپت scr/js/main.js
به build/js/main.js
پیکربندی esbuild
package.json
یک "type" "ماژول" دارد، بنابراین همه فایلهای js.
میتوانند از ماژولهای ES استفاده کنند. اسکریپت esbuild.config.js
esbuild را وارد میکند و productionMode
را هنگام باندل برای تولید روی true
یا هنگام باندل شدن برای توسعه 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`);
تارگت باندل
توجه داشته باشید که متغیر target آرایه ای از مرورگرها و شماره نسخه ها را برای استفاده در پیکربندی تعریف می کند. این بر خروجی باندل تأثیر می گذارد و سینتکس را برای پشتیبانی از پلتفرم های خاص تغییر می دهد. به عنوان مثال، esbuild می تواند:
تودرتوی CSS را به انتخابگرهای کامل گسترش دهید (اگر تنها تارگت "Chrome115" باشد، تودرتو باقی می ماند)
در صورت لزوم، ویژگی های با پیشوند فروشنده CSS را اضافه کنید
پلی فیل کردن ??
عملگر nullish coalescing#
را از فیلدهای کلاس خصوصی حذف کنید
علاوه بر مرورگرها، میتوانید نسخههای node و es مانند es2020
و esnext
(آخرین ویژگیهای 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
پروژه نمونه از گزینه های پیشرفته تری مانند watch فایل استفاده می کند. این به یک زمینه ساخت طولانی مدت نیاز دارد که پیکربندی را تنظیم می کند:
// 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'
});
esbuild ده ها گزینه پیکربندی را ارائه می دهد. در اینجا خلاصه ای از موارد استفاده شده در اینجا آمده است:
enterPoints
آرایه ای از نقاط ورودی فایل را برای بسته بندی تعریف می کند. پروژه نمونه دارای یک اسکریپت در src/js/main.js/.
است.
format
خروجی را تنظیم می کند. مثال از esm
استفاده میکند، اما میتوانید به صورت اختیاری iife
را برای مرورگرهای قدیمیتر یا commonjs
را برای Node.js تنظیم کنید.
بسته نرم افزاری روی خطوط واقعی ماژول های وارد شده به فایل خروجی تنظیم می شود.
target
آرایه ای از مرورگرهای هدف است که در بالا تعریف شده است.
drop
آرایه ای از دستورات console
و/یا debugger
برای حذف است. در این حالت، ساختهای تولیدی هر دو را حذف میکنند و ساختهای توسعه آنها را حفظ میکنند.
logLevel
طولانی نویسی ورود به سیستم را تعریف می کند. مثال بالا خطاها را در طول ساختهای تولید و پیامهای اطلاعاتی پرمخاطبتر را در طول ساختهای توسعه نشان میدهد.
minify
با حذف نظرات و فضای خالی و تغییر نام متغیرها و توابع در صورت امکان، اندازه کد را کاهش می دهد. پروژه مثال در طول ساخت های تولیدی کوچک می شود اما در طول ساخت های توسعه کد را زیباتر می کند.
sourcemap
که روی linked
تنظیم شده است (فقط در حالت توسعه) یک نقشه منبع linkded را در یک فایل map.
ایجاد می کند، بنابراین فایل منبع اصلی و خط در ابزارهای توسعه دهنده مرورگر موجود است. همچنین میتوانید به صورت خطی تنظیم کنید تا نقشه منبع در داخل فایل باندل قرار گیرد، هر دو برای ایجاد هر دو، یا خارجی برای ایجاد یک فایل map.
بدون link از جاوا اسکریپت باندل.
outdir
دایرکتوری خروجی فایل باندل را تعریف می کند.
متد ()rebuild
شیء context
را فراخوانی کنید تا بیلد را یک بار اجرا کنید - معمولاً برای یک ساخت production :
await buildJS.rebuild();
buildJS.dispose(); // free up resources
برای ادامه اجرا و بازسازی خودکار زمانی که فایلهای تماشا شده تغییر میکنند، متد ()watch
را فراخوانی کنید:
await buildJS.watch();
شیء context
تضمین میکند که ساختهای بعدی به صورت تدریجی پردازش میشوند و از کار ساختهای قبلی برای بهبود عملکرد استفاده مجدد میکنند.
فایل های ورودی و خروجی جاوا اسکریپت
فایل ورودی src/js/main.js
ماژول های dom.js
و time.js
را از پوشه lib
وارد می کند. همه عناصر را با یک کلاس ساعت پیدا می کند و محتوای متن آنها را در هر ثانیه روی زمان فعلی تنظیم می کند:
import * as dom from './lib/dom.js';
import { formatHMS } from './lib/time.js';
// get clock element
const clock = dom.getAll('.clock');
if (clock.length) {
console.log('initializing clock');
setInterval(() => {
clock.forEach(c => c.textContent = formatHMS());
}, 1000);
}
dom.js
دو تابع export
می کند. main.js
هر دو را وارد می کند اما فقط از ()getAll
:
// DOM libary
// fetch first node from selector
export function get(selector, doc = document) {
return doc.querySelector(selector);
}
// fetch all nodes from selector
export function getAll(selector, doc = document) {
return Array.from(doc.querySelectorAll(selector));
}
time.js
دو تابع را export
می کند. ()main.js formatHMS
را وارد می کند، اما از توابع دیگر در ماژول استفاده می کند:
// time library
// return 2-digit value
function timePad(n) {
return String(n).padStart(2, '0');
}
// return time in HH:MM format
export function formatHM(d = new Date()) {
return timePad(d.getHours()) + ':' + timePad(d.getMinutes());
}
// return time in HH:MM:SS format
export function formatHMS(d = new Date()) {
return formatHM(d) + ':' + timePad(d.getSeconds());
}
بسته توسعه به دست آمده ()get
را از dom.js
حذف میکند اما شامل تمام توابع time.js
میشود. یک نقشه منبع نیز تولید می شود:
// src/js/lib/dom.js
function getAll(selector, doc = document) {
return Array.from(doc.querySelectorAll(selector));
}
// src/js/lib/time.js
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());
}
// src/js/main.js
var clock = getAll(".clock");
if (clock.length) {
console.log("initializing clock");
setInterval(() => {
clock.forEach((c) => c.textContent = formatHMS());
}, 1e3);
}
//# sourceMappingURL=main.js.map
بسته تولیدی به دست آمده کد را به 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 Bundling
بستهبندی CSS در پروژه نمونه از یک شی context
مشابه با جاوا اسکریپت بالا استفاده میکند:
// bundle CSS
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'
});
این یک گزینه خارجی را به عنوان آرایه ای از فایل ها و مسیرها برای حذف از ساخت تعریف می کند. در پروژه مثال بالا، فایلهای موجود در دایرکتوری src/images/
در فهرست ساخت کپی میشوند تا HTML، CSS یا جاوا اسکریپت بتوانند مستقیماً به آنها ارجاع دهند. اگر این تنظیم نشده بود، esbuild هنگام استفاده از آنها در پسزمینه تصویر یا ویژگیهای مشابه، فایلها را در فهرست خروجی build/css/
کپی میکرد.
گزینه loader
نحوه مدیریت esbuild یک فایل وارداتی را که به عنوان دارایی خارجی ارجاع نمی شود، تغییر می دهد. در این مثال:
تصاویر SVG بهعنوان URI دادهها درج میشوند
تصاویر PNG و JPG در دایرکتوری build/css/
کپی می شوند و به عنوان فایل ارجاع می شوند
فایل های ورودی و خروجی CSS
برای مثال ورودی src/css/main.css
فایل variables.css
و element.css
را در پوشه partials
وارد می کند:
/* import */
@import './partials/variables.css';
@import './partials/elements.css';
variables.css
ویژگی های سفارشی پیش فرض را تعریف می کند:
/* primary variables */
:root {
--font-body: sans-serif;
--color-fore: #fff;
--color-back: #112;
}
element.css
همه استایل ها را تعریف می کند. توجه داشته باشید:
بدنه دارای یک تصویر پس زمینه است که از فهرست تصاویر خارجی بارگیری شده استh1
در داخل هدر تو در تو قرار داردh1
دارای یک SVG پس زمینه است که به صورت خطی خواهد بود
مرورگرهای هدف نیازی به پیشوند فروشنده ندارند
/* element styling */
*, *::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;
}
/* nested elements with inline icon */
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 را درون خطی میکند و یک نقشه منبع تولید میکند:
/* src/css/partials/variables.css */
:root {
--font-body: sans-serif;
--color-fore: #fff;
--color-back: #112;
}
/* src/css/partials/elements.css */
*,
*::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;
}
/* src/css/main.css */
/*# sourceMappingURL=main.css.map */
بسته تولید به دست آمده کد را به 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}
Watching، Rebuilding، و Serving
باقیمانده اسکریپت esbuild.config.js
یکبار برای بیلدهای production قبل از خاتمه بسته می شود:
if (productionMode) {
// single production build
await buildCSS.rebuild();
buildCSS.dispose();
await buildJS.rebuild();
buildJS.dispose();
}
در طول ساختهای توسعه، اسکریپت به اجرا ادامه میدهد، تغییرات فایل را مشاهده میکند و دوباره بهطور خودکار بستهبندی میشود. زمینه buildCSS یک وب سرور توسعه با /build
به عنوان دایرکتوری ریشه راه اندازی می کند:
else {
// watch for file changes
await buildCSS.watch();
await buildJS.watch();
// development server
await buildCSS.serve({
servedir: './build'
});
}
ساخت توسعه را با:
npm start
برای مشاهده صفحه به localhost:8000
بروید.
برخلاف Browsersync، برای بارگذاری مجدد زنده باید کد خود را به صفحات توسعه اضافه کنید. هنگامی که تغییرات رخ می دهد، esbuild اطلاعات مربوط به به روز رسانی را از طریق یک رویداد ارسال شده توسط سرور ارسال می کند. ساده ترین گزینه این است که وقتی هر تغییری رخ می دهد صفحه را به طور کامل بارگیری کنید:
new EventSource('/esbuild').addEventListener('change', () => location.reload());
پروژه مثال از شی زمینه CSS برای ایجاد سرور استفاده می کند. دلیلش این است که ترجیح میدهم بهطور دستی تغییرات جاوا اسکریپت را بازخوانی کنم - و به این دلیل که نتوانستم راهی برای 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 در حال حاضر از بارگیری مجدد جاوا اسکریپت پشتیبانی نمی کند - به هر حال من به آن اعتماد کنم!
نتیجه
با کمی پیکربندی، esbuild می تواند برای رسیدگی به تمام نیازهای ساخت و توسعه پروژه شما کافی باشد.
اگر به عملکرد پیشرفته تری نیاز دارید، مجموعه ای جامع از افزونه ها وجود دارد. توجه داشته باشید که این ابزارها اغلب شامل Sass، PostCSS یا ابزارهای ساخت مشابه هستند، بنابراین آنها به طور موثر از esbuild به عنوان یک task runner استفاده می کنند. اگر به گزینه های سفارشی و سبک وزن بیشتری نیاز دارید، همیشه می توانید افزونه های خود را ایجاد کنید.