MakeFirstStep· Frontend + зеҳни сунъӣ

Дарси 17 · Абзорҳои барномасоз

Модулҳо, npm ва build бо Vite

То даме ки барномаи шумо дар як файли 300-сатра ҷой мегирад, ҳама чиз хуб аст. Аммо сайти ҳақиқӣ — ин даҳҳо файл, китобхонаҳои бегона ва ҷамъбаст пеш аз нашр аст. Имрӯз шумо ёд мегиред, ки кодро ба модулҳо тақсим кунед, бастаҳоро тавассути npm пайваст кунед, лоиҳаро бо Vite оғоз намоед — ва барномаи дарси 16-ро ба он мегузаронед.

  • export ва import навиштан: номдор, пешфарз, бо тағйири ном ва файли «витринагӣ»-и index.js
  • Роҳҳои модулҳоро дуруст нишон додан ва лоиҳаро ба папкаҳо тақсим кардан
  • package.json-ро хондан ва таҳрир кардан: майдонҳо, dependencies ва devDependencies, версияҳои ^ ва ~
  • Фармонҳоро тавассути скриптҳои npm иҷро кардан: npm run dev, npm run build
  • Лоиҳаро бо фармони npm create vite@latest эҷод кардан ва фарқи сервери dev аз build-ро фаҳмондан
  • Барномаро ба Vite гузаронидан, ба модулҳо тақсим кардан ва ба репозиторий бор кардан
Бо ин саҳифа чӣ тавр кор кардан лозим

Ин дарс дар бораи абзорҳост, бинобар ин як қисми мисолҳо — терминал ва файлҳои лоиҳа мебошанд: онҳо дар заминаи торик ҳастанд, вале бе тугмаи «Иҷро кардан». Фармонҳоро шумо дар компютери худ такрор мекунед (сарлавҳаи блок ишора мекунад: «Терминал» ё номи файл). Ҳар чизе, ки дар браузер ба таври ҳақиқӣ санҷидан мумкин аст, зинда аст: модулҳо, import-ҳо ва таҳлили package.json бо тугмаи ▶ Иҷро кардан оғоз мешаванд. Дар браузер файлҳо нестанд, барои ҳамин «файл»-и модулро дар сатр нигоҳ медорем ва бо import()-и ҳақиқӣ бор мекунем — ин ҳамон механизмест, ки браузер барои файлҳо истифода мебарад. Сатри setTimeout(() => {}, 300) дар ин мисолҳо ёрирасон аст: он аз майдончаи озмоишӣ хоҳиш мекунад, ки каме интизор шавад, то модул бор шавад. Дар лоиҳаи ҳақиқӣ он лозим нест.

01 Модулҳо барои чӣ лозиманд. export ва import

Ҳар лоиҳаи ҷиддиро кушоед — шумо дар он як script.js-и азим наменамоед. Код ба файлҳо тақсим шудааст: яке барои дархостҳо ба API масъул аст, дигаре — барои тасвир, сеюм — барои функсияҳои ёрирасон. Чунин файл модул номида мешавад.

Чаро як файл — бад аст? Аввалан, дар он ҳидоят кардан душвор аст. Дуюм, агар якчанд скрипти оддиро пай дар пай пайваст кунем, ҳамаи тағйирёбандаҳои онҳо ба як фазои умумӣ меафтанд: ду функсия бо номи format якдигарро пок мекунанд. Модул ҳарду мушкилро ҳал мекунад: он соҳаи намоии худро дорад ва ба берун танҳо он чизе мебарояд, ки шумо возеҳан иҷозат додаед.

Монандӣ аз ҳаёт

Ошхонаи чойхонаи калон. Як ошпаз палав мепазад, дигаре — кабоб, сеюм — нон. Ҳар кас мизи худ ва маҳсулоти худро дорад — ин модул бо соҳаи намоии худ аст. Аммо таоми тайёрро ошпаз тавассути тирезаи расонидан медиҳад — ин export аст. Пешхизмате, ки таомро мегирад ва ба толор мебарад, — ин import аст. Ҳар чизе ки дар сари миз монд, «корҳои шахсии» ошпаз аст, ба толор намеравад.

Экспорти номдор

Барои он ки чизеро ба берун кушоед, пеш аз эълон калимаи export-ро менависанд. Барои гирифтани онро дар файли дигар — import бо номҳо дар қавсҳои фигурӣ:

src/currency.js
const RATE = 11; // бе export — танҳо дар дохили ҳамин файл намоён аст

export function toSomoni(usd) {
  return usd * RATE;
}

export function toUsd(somoni) {
  return somoni / RATE;
}
src/main.js
import { toSomoni, toUsd } from "./currency.js";

console.log(toSomoni(100)); // → 1100
console.log(toUsd(550));    // → 50

Номҳо дар қавсҳои фигурӣ бояд бо номҳои экспортшуда айнан мувофиқ бошанд, аз ҷумла ҳарфи калон ва хурд. Тартиб муҳим нест. Агар чизеро import кунед, ки вуҷуд надорад — хато ҳанӯз пеш аз иҷрои код пайдо мешавад.

Import-и ҳақиқиро худи ҳамин ҷо иҷро мекунем

Дар ин саҳифа файлҳо дар диск нестанд, вале функсияи import() ҳаст, ки модулро аз рӯи нишонӣ бор карда метавонад. Мо «файл»-ро ба сатр печонида, ба нишонӣ табдил медиҳем (Blob ва URL.createObjectURL) ва бор мекунем. Барои шумо ин танҳо сатр дар нохунакҳои баръакс аст — тасаввур кунед, ки ин мазмуни файл аст.

Модул дар сатр: import()-и ҳақиқӣ · Ctrl + Enter
// «файл» → нишонӣ → модул
const load = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return import(URL.createObjectURL(new Blob([code], { type: "text/javascript" })));
};

const currency = await load(`
  const RATE = 11;
  export function toSomoni(usd) { return usd * RATE; }
  export function toUsd(somoni) { return somoni / RATE; }
`);

console.log(currency.toSomoni(100)); // 1100
console.log(currency.toUsd(550));    // 50
console.log(currency.RATE);          // undefined — бе export аз берун намоён нест

Натиҷаи боркунӣ — объект бо ҳар он чизе, ки модул экспорт кардааст. Собити RATE экспорт нашудааст — аз берун он нест. Ин ҳамон «махфияти» модул аст.

Модуле, ки модули дигарро import мекунад

Акнун ду «файл»: дуюмӣ якумиро бо сатри оддии import ... from пайваст мекунад. Ба ҷои роҳи "./currency.js" мо нишонии модули якумро мегузорем — дар диски ҳақиқӣ ҷои он роҳ меистод.

Ду модул: main currency-ро import мекунад · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

// файли currency.js
const currencyUrl = url(`
  const RATE = 11;
  export const toSomoni = (usd) => usd * RATE;
  export const toUsd = (somoni) => somoni / RATE;
`);

// файли main.js (дар диск: import { toSomoni } from "./currency.js")
await import(url(`
  import { toSomoni, toUsd } from "${currencyUrl}";
  console.log("100 USD =", toSomoni(100), "сомони");
  console.log("550 сомони =", toUsd(550), "USD");
`));

Import боз чӣ кор карда метавонад

Тағйири ном: as
Агар номҳо зиддият кунанд: import { format as formatDate } from "./dates.js". Акнун дар дохили файл функсия formatDate ном дорад.
Ҳамаро якбора: * as
import * as currency from "./currency.js" — як объект, ба функсияҳо тавассути нуқта муроҷиат мекунем: currency.toSomoni(5). Вақте қулай аст, ки бисёр чиз лозим аст ва мехоҳем бубинем, ки кадом чиз аз куҷост.
Экспорт бо рӯйхат
Ҳатмӣ нест, ки пеш аз ҳар сатр export гузорем — ҳамаро дар поёни файл ҷамъ кардан мумкин аст: export { toSomoni, toUsd };
Танҳо иҷро
import "./style.css" — бе ном: файл танҳо пайваст мешавад. Дар Vite услубҳоро ҳамин тавр пайваст мекунанд.
as ва * as · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const dates = url(`export function format(d) { return d.day + "." + d.month; }`);
const money = url(`export function format(n) { return n + " сомони"; }`);

await import(url(`
  import { format as formatDate } from "${dates}";
  import * as moneyUtils from "${money}";

  console.log(formatDate({ day: 15, month: 10 }));
  console.log(moneyUtils.format(250));
`));
Хатогиҳои маъмул

1) Номеро import кардан, ки модул экспорт намекунад (хатои имлоӣ, ҳарфи калон ва хурд, export-и фаромӯшшуда). 2) ./-ро дар роҳ фаромӯш кардан: "currency.js" бе нуқта — ин файли шумо не, балки баста аз npm аст (дар бораи он дар поён). 3) import-ро дар скрипти оддӣ бе type="module" навиштан.

Ин код хато медиҳад · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const shop = url(`
  export function totalPrice(a, b) { return a + b; }
`);

// ✖ модул totalPrice-ро экспорт мекунад, мо бошем calcTotal-ро металабем
await import(url(`
  import { calcTotal } from "${shop}";
  console.log(calcTotal(10, 20));
`));

Муфассалтар хонед: learn.javascript.ru — Экспорт ва import · MDN — Модулҳои JavaScript

Амал: мустаҳкам мекунем

Дар ҳамаи вазифаҳо «файл» дар сатри-қолаб ҷойгир аст. Танҳо он чиро тағйир диҳед, ки дар шарҳҳо ва шарт ишора шудааст.

ВАЗИФАИ 1.1

Аз берун чӣ намоён аст

осон

Баромадро пешгӯӣ кунед, бе иҷро: модул кадом номҳоро ба берун медиҳад (онҳо бо вергул чоп мешаванд; калидҳои модул аз рӯи алифбо меоянд, ҳарфҳои калон пеш аз хурдҳо) ва бо secret чӣ мешавад? Баъд иҷро кунед ва муқоиса намоед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const load = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return import(URL.createObjectURL(new Blob([code], { type: "text/javascript" })));
};

const city = await load(`
  export const CITY = "Душанбе";
  export function hello() { return "Салом, " + CITY; }
  const secret = "не для чужих";
  export const year = 2026;
`);

console.log(Object.keys(city).join(", "));
console.log(typeof city.secret);
Натиҷаи интизоршаванда
CITY, hello, year
undefined
Ишора 1

Ба берун танҳо он чиз мебарояд, ки бо калимаи export қайд шудааст. Чунин сатрҳоро ҳисоб кунед.

Ишора 2

Муқоисаи номҳо аз рӯи рамзи аломат мегузарад: C (калон) пеш аз h, h бошад пеш аз y меояд.

ВАЗИФАИ 1.2

export-ро илова кунед

осон

Модули currency.js навишта шудааст, аммо дар он кушодани функсияҳо ба берун фаромӯш шудааст — main.js бо хато меафтад. export-ро дар ҷое, ки лозим аст, илова кунед ва ба баромади дуруст бирасед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const currencyUrl = url(`
  const RATE = 11;
  function toSomoni(usd) { return usd * RATE; }
  function toUsd(somoni) { return somoni / RATE; }
`);

await import(url(`
  import { toSomoni, toUsd } from "${currencyUrl}";
  console.log(toSomoni(100));
  console.log(toUsd(550));
`));
Натиҷаи интизоршаванда
1100
50
Ишора 1

Хаторо хонед: дар он гуфта шудааст, ки модул экспорти чунин номро пешкаш намекунад. main.js кадом ду номро металабад?

Ишора 2

Калимаи export-ро пеш аз function toSomoni ва function toUsd гузоред. Ба собити RATE он лозим нест.

ВАЗИФАИ 1.3

Ду функсияи format

миёна

Модулҳои dates.js ва money.js ҳарду функсияеро бо номи format экспорт мекунанд. Ҳардуро дар main.js тавре import кунед, ки онҳо зиддият накунанд: санаҳо — ҳамчун formatDate, пул — ҳамчун formatMoney.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const datesUrl = url(`export function format(d) { return d.day + "." + d.month + "." + d.year; }`);
const moneyUrl = url(`export function format(n) { return n + " сомони"; }`);

await import(url(`
  // ҳарду функсияро бо номҳои гуногун import кунед
  import { format } from "${datesUrl}";

  console.log(formatDate({ day: 15, month: 10, year: 2026 }));
  console.log(formatMoney(250));
`));
Натиҷаи интизоршаванда
15.10.2026
250 сомони
Ишора 1

Сохтори { ном as номиНав } номро дар дохили файли ҷорӣ иваз мекунад. Ду сатри import лозим аст — барои ҳар модул яктоӣ.

Ишора 2

import { format as formatDate } from "${datesUrl}"; — ва ҳамин гуна сатр барои moneyUrl бо номи formatMoney.

ВАЗИФАИ 1.4

Модули сабад аз сифр

миёна

Модули cart.js-ро нависед: он массиви items (се нарх: 15, 40, 5) ва функсияи total(list)-ро, ки маҷмӯъро бармегардонад, экспорт мекунад. Баъд дар main.js ҳарду чизро import кунед ва натиҷаро чоп намоед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const cartUrl = url(`
  // нависед: export const items = [...]; ва export function total(list) { ... }
`);

await import(url(`
  // items ва total-ро аз "${cartUrl}" import кунед

  console.log("Товаров:", items.length);
  console.log("Итого:", total(items));
`));
Натиҷаи интизоршаванда
Товаров: 3
Итого: 60
Ишора 1

Дар модул: export const items = [15, 40, 5]; ва export function total(list) { ... }.

Ишора 2

Маҷмӯъ: return list.reduce((sum, p) => sum + p, 0);. Дар main.js: import { items, total } from "${cartUrl}";

02 Экспорти пешфарз, реэкспорт, роҳҳо ва папкаҳо

export default

Модул метавонад як экспорти «асосӣ» дошта бошад — export default. Ҳангоми import он бе қавсҳои фигурӣ ва бо ҳар номе, ки худатон меандешед, гирифта мешавад:

src/ui/greet.js
export default function greet(name) {
  return `Салом, ${name}!`;
}

export const LANG = "tg"; // экспорти номдорро ҳам дар паҳлӯ нигоҳ доштан мумкин аст
src/main.js
import greet, { LANG } from "./ui/greet.js";   // default — бе қавс, боқӣ — дар қавс
import hello from "./ui/greet.js";              // айнан ҳамон, ном худамон интихоб мекунем

console.log(greet("Мадина"), LANG);
Экспорти номдорЭкспорти пешфарз
Навиштexport function f() {}export default function f() {}
Importimport { f } from "./a.js"import f from "./a.js"
Барои як модул чандтоБа қадри лозимНа зиёда аз як
Ном ҳангоми importБояд мувофиқ бошад (ё as)Ҳар кадом
Кай интихоб карданПешфарз — ҷустуҷӯ ва пурраи худкор қулайтар астМодули «дар бораи як чиз»: компонент, класс, танзимот
Маслиҳат

Дар коди худ экспортҳои номдор-ро авлотар шуморед: ном дар ҳамаи файлҳо яксон аст ва муҳаррир худаш import-ро пешниҳод мекунад. default-ро шумо ба ҳар ҳол вомехӯред — дар ҷавобҳои зеҳни сунъӣ, дар ҳуҷҷатҳои китобхонаҳо ва дар React (компонентҳоро бештар бо пешфарз экспорт мекунанд).

default ва named дар як модул · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const greetUrl = url(`
  export default function greet(name) { return "Салом, " + name + "!"; }
  export const LANG = "tg";
`);

await import(url(`
  import hello, { LANG } from "${greetUrl}";   // hello — номи мо барои default
  console.log(hello("Мадина"), LANG);
`));

// бубинем, ки дар модул чӣ ҳаст: default — ин танҳо калид бо номи "default" аст
const mod = await import(greetUrl);
console.log(Object.keys(mod).join(", "));

Реэкспорт: файли витринагии index.js

Вақте дар папка бисёр модул ҳаст, навиштани панҷ сатри import аз панҷ файли гуногун нокулай аст. Одат шудааст, ки дар папка файли index.js мегузоранд, ки ҳар чизи лозимаро ҷамъ мекунад ва тавассути як тиреза медиҳад — мисли витрина дар мағоза. Барои ин экспорти «интиқолдиҳанда» ҳаст:

src/api/index.js
export { getUsers, getPosts } from "./users.js";   // номҳои алоҳида
export * from "./products.js";                      // ҳамаи номдорҳо якбора
export { default as http } from "./http.js";        // default → номдор
src/main.js
// аз берун муҳим нест, ки дар кадом файл чӣ ҳаст: роҳ ба папка мебарад
import { getUsers, searchProducts, http } from "./api/index.js";
Монандӣ аз ҳаёт

Бозори Корвон. Шумо ба ҳар анбор намеравед — ба қатори даркорӣ меравед, ки дар он фурӯшанда фармоишро мегирад ва худаш аз анборҳои гуногун мол мебарорад. index.js — ҳамон фурӯшанда аст: харидор (модули дигар) танҳо қаторро медонад, на анборҳоро.

Қоидаҳое, ки донистанашон лозим аст

  1. Модул як бор иҷро мешавад. Ҳар қадар файл онро import кунад ҳам, код дар дохили он як бор оғоз мешавад, ва ҳама як ҳолати ягона (ҳисобкунак, кэш, танзимот)-ро мегиранд.
  2. Соҳаи намоии худ. Тағйирёбандаҳои модул ба window намеафтанд. Барои ҳамин дар лоиҳаи Vite шумо тасодуфан тағйирёбандаи бегонаро аз нав навишта наметавонед.
  3. Реҷаи қатъӣ худ аз худ фаъол аст. Навиштани "use strict" лозим нест.
  4. import — танҳо дар боло аз файл ва на дар дохили if ё функсия. Барои боркунӣ «ҳангоми ниёз» import() ҳаст — маҳз онро мо дар ин саҳифа истифода мебарем.
  5. Давраҳоро манъ кардан лозим нест, вале аз онҳо худдорӣ кардан даркор. Агар a.js файли b.js-ро import кунад, b.js бошад — a.js-ро, дар тартиби иҷро ошуфтагӣ пайдо мешавад. Ҳал: чизи умумиро ба файли сеюм баровардан.
Модул як бор иҷро мешавад · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const counterUrl = url(`
  console.log("counter.js загружен");   // ин сатрро чанд бор мебинем?
  export let count = 0;
  export function inc() { count++; }
`);

await import(url(`import { inc } from "${counterUrl}"; inc(); inc();`));
await import(url(`import { count } from "${counterUrl}"; console.log("count в b:", count);`));

Роҳҳо дар import

"./api.js"
Файли ҳамсоя бо файли ҷорӣ (дар ҳамон папка).
"../api.js"
Як папка боло. Ду папка боло — "../../api.js".
"./api/index.js"
Файл дар зерпапка. Хати моил ҳамеша рост аст: /, ҳатто дар Windows.
"dayjs"
Бе ./ ва ../ — ин баста аз npm аст. Vite онро дар папкаи node_modules меёбад.
Васеъкунии .js
Дар браузер ва дар Vite онро ҳамеша менависем: "./api.js", на "./api".
Ҳарфи калон/хурд ва Windows

Дар Windows ва macOS файли Api.js-ро ба иштибоҳ чун "./api.js" import кардан мумкин аст — ва дар маҳал ҳама чиз кор мекунад. Аммо сервере, ки шумо сайтро ба он бор мекунед (GitHub Pages, Netlify), ба ҳарфи калон ва хурд ҳассос аст: дар он ҷо хатои 404 мешавад. Файлҳоро бо як услуб номгузорӣ кунед — kebab-case ё camelCase бо ҳарфи хурд — ва роҳро ҳарф ба ҳарф нависед.

Модулро дар саҳифа чӣ тавр пайваст кардан

index.html
<!-- type="module" — ва main.js метавонад import-ро истифода барад -->
<script type="module" src="./src/main.js"></script>

Агар чунин index.html-ро танҳо бо дукарата зер кардан кушоед (нишонӣ бо file:// оғоз мешавад), браузер модулҳоро бор карданро рад мекунад. Ба онҳо сервер лозим аст, нишонӣ мисли http://localhost:5173. Барои таҳия сервер Vite медиҳад — дар поён шумо онро оғоз мекунед.

Лоиҳаро ба папкаҳо чӣ тавр тақсим кардан

Қонуни ягона нест, вале барои барномаҳои дарси 15–16 чунин тарҳ хуб кор мекунад:

my-shop/ ├─ index.html саҳифа, src/main.js-ро пайваст мекунад ├─ package.json шиноснома ва фармонҳои лоиҳа ├─ .gitignore чиро ба Git нафиристодан ├─ public/ файлҳо «чунон ки ҳастанд»: favicon, расмҳо └─ src/ ├─ main.js нуқтаи вуруд: танҳо «ҷамъ кардан»-и барнома ├─ api/ │ └─ products.js дархостҳо ба API (fetch) ├─ ui/ │ └─ render.js тасвир: рӯйхат, ҳолатҳои loading / error ├─ utils/ │ └─ debounce.js ёрирасонҳои хурд бе вобастагӣ ба саҳифа └─ styles/ └─ style.css
  • Як модул — як вазифа. Агар дар файл ҳам fetch, ҳам кор бо DOM ва ҳам ҳисобҳо бошад — вақти тақсим кардан расидааст.
  • main.js — «роҳбари оркестр». Он дигаронро пайваст ва банд мекунад: «аз api маълумот гирифтем → ба ui додем». Мантиқи худи он қариб нест.
  • Вобастагиҳо ба як тараф мераванд: main дар бораи api ва ui медонад, онҳо дар бораи main — не.
  • utils дар бораи барнома намедонанд. debounce ба ҳар лоиҳа мувофиқ аст — яъне ҷояш дар utils аст.

Муфассалтар хонед: learn.javascript.ru — Модулҳо, муқаддима · MDN — export

Амал: мустаҳкам мекунем

ВАЗИФАИ 2.1

Салом ёфт нашуд

осон

Модул greet-ро «бо пешфарз» экспорт мекунад, main.js бошад онро ҳамчун номдор металабад — хато мешавад. Танҳо import-ро дар main.js ислоҳ кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const greetUrl = url(`
  export default function greet(name) { return "Салом, " + name + "!"; }
  export const LANG = "tg";
`);

await import(url(`
  import { greet, LANG } from "${greetUrl}";
  console.log(greet("Мадина"));
  console.log(LANG);
`));
Натиҷаи интизоршаванда
Салом, Мадина!
tg
Ишора 1

Экспорти пешфарз бе қавсҳои фигурӣ import мешавад, номдор — дар қавс. Дар ин ҷо ҳам яке, ҳам дигаре якбора лозим аст.

Ишора 2

import greet, { LANG } from "${greetUrl}";

ВАЗИФАИ 2.2

Як модул — як ҳолат

миёна

Аввал пешгӯӣ кунед, ки код чӣ чоп мекунад («counter.js загружен» чанд бор пайдо мешавад ва count дар import-кунандаи дуюм ба чӣ баробар аст). Баъд такмил диҳед: ба counter.js функсияи reset()-ро илова кунед, ки ҳисобкунакро сифр мекунад, ва import-кунандаи сеюмро бинависед, ки reset()-ро даъват карда, count после reset: 0-ро чоп мекунад.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const counterUrl = url(`
  console.log("counter.js загружен");
  export let count = 0;
  export function inc() { count++; }
  // export function reset() ... илова кунед
`);

await import(url(`import { inc } from "${counterUrl}"; inc(); inc();`));
await import(url(`import { count } from "${counterUrl}"; console.log("count в b:", count);`));
// import-кунандаи сеюм — дар ин ҷо
Натиҷаи интизоршаванда
counter.js загружен
count в b: 2
count после reset: 0
Ишора 1

Нишонии counterUrl як аст, барои ҳамин модул як бор бор ва иҷро мешавад, ва ҳолат барои ҳамаи import-кунандаҳо умумӣ аст.

Ишора 2

Import-кунандаи сеюм: await import(url(`import { count, reset } from "${counterUrl}"; reset(); console.log("count после reset:", count);`)); Қимати count «зинда» аст: пас аз reset() он аллакай сифр аст.

ВАЗИФАИ 2.3

Витринаи index.js

душвор

Лоиҳаи хурд аз се модул ҷамъ шудааст. Мазмуни файли index.js (indexUrl)-ро тавре нависед, ки он интиқол диҳад: функсияи getUsers-ро аз api.js, ҳамаи экспортҳои номдорро аз format.js ва default-ро аз store.js бо номи store. main.js-ро тағйир додан лозим нест.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const apiUrl = url(`export function getUsers() { return ["Рустам", "Зарина"]; }`);
const formatUrl = url(`
  export const upper = (s) => s.toUpperCase();
  export const exclaim = (s) => s + "!";
`);
const storeUrl = url(`
  const items = [];
  export default { add(x) { items.push(x); }, size() { return items.length; } };
`);

const indexUrl = url(`
  // ҳар чизи заруриро аз apiUrl, formatUrl ва storeUrl реэкспорт кунед
`);

await import(url(`
  import { getUsers, upper, exclaim, store } from "${indexUrl}";
  for (const user of getUsers()) {
    console.log(exclaim(upper(user)));
    store.add(user);
  }
  console.log(store.size());
`));
Натиҷаи интизоршаванда
РУСТАМ!
ЗАРИНА!
2
Ишора 1

Се сатр ба услуби export ... from "...": яке бо қавсҳои фигурӣ, яке бо ситорача, яке бо default as. Нишониҳо чун "${apiUrl}" гузошта мешаванд.

Ишора 2

export { getUsers } from "${apiUrl}";
export * from "${formatUrl}";
export { default as store } from "${storeUrl}";

ВАЗИФАИ 2.4

Роҳ ба куҷо мебарад

миёна

Функсияи resolveImport(from, spec)-ро нависед: он роҳи файли import-кунанда ва сатри аз import-ро мегирад ва роҳи файли даркориро аз решаи лоиҳа, бе хати моили аввал, бармегардонад. URL-и дарунсохт кор меояд: new URL(spec, base).pathname, ки дар он base — нишонии шартии сайт ва роҳи файл аст.

Таҳрир кардан мумкин аст · Ctrl + Enter
function resolveImport(from, spec) {
  // ишора: base = "http://app/" + from
}

console.log(resolveImport("src/ui/render.js", "./card.js"));
console.log(resolveImport("src/ui/render.js", "../api.js"));
console.log(resolveImport("src/ui/render.js", "../../package.json"));
Натиҷаи интизоршаванда
src/ui/card.js
src/api.js
package.json
Ишора 1

new URL("../api.js", "http://app/src/ui/render.js").pathname /src/api.js-ро бармегардонад. Роҳи нисбӣ аз папкаи файл ҳисоб карда мешавад.

Ишора 2

Дар натиҷаи pathname хати моили аввал ҳаст — онро ҳазф кунед: .slice(1).

03 Node.js, npm ва package.json

Node.js — ин JavaScript берун аз браузер аст: он кодатонро бевосита дар компютер иҷро мекунад. Мо онро на барои сайтҳо, балки барои абзорҳо лозим дорем: Vite, форматкунандаҳо ва санҷиши код худашон бо JavaScript навишта шудаанд ва дар Node кор мекунанд. Бо Node якҷоя npm насб мешавад — мудири бастаҳо: барномае, ки коди бегонаро (бастаҳоро) аз феҳристи азими npmjs.com зеркашӣ мекунад ва ба лоиҳаи шумо пайваст менамояд.

Монандӣ аз ҳаёт

Бозори масолеҳи сохтмон. Шумо хона месозед ва хиштро худатон намерезед — тайёрашро мегиред. npm — ин ҳам бозор, ҳам расонидан аст: мегӯед «фалон баста лозим», ва онро ба папкаи node_modules меоранд. package.json бошад — рӯйхати харидҳои лоиҳа: дақиқ чӣ ва кадом версия ба шумо лозим аст. Ин рӯйхатро ба таҳиягари дигар диҳед — ва ӯ бо як фармон айнан ҳамон масолеҳро дар назди худ ҷамъ мекунад.

Насб ва санҷиш (Windows ва macOS)

  1. Node.js LTS-ро зеркашӣ кунед аз nodejs.org (тугмаи «LTS» — версия бо дастгирии дароз). Windows — насбкунандаи .msi, macOS — насбкунандаи .pkg. Ҳама ҷо бо танзимоти пешфарз розӣ шавед.
  2. Терминалро пӯшед ва аз нав кушоед. Ин муҳим аст: тирезаҳои кӯҳна барномаҳои навро намебинанд. Осонтар аз ҳама — терминал бевосита дар VS Code: меню Terminal → New Terminal (дар клавиатура Ctrl+`).
  3. Версияҳоро санҷед. Барои Vite-и муосир Node.js 20.19+ ё 22.12+ лозим аст.
Терминал
node -v
# v22.14.0   ← у вас может быть другая, главное не ниже 20.19

npm -v
# 10.9.2
Windows: «иҷрои скриптҳо хомӯш карда шудааст»

Агар дар PowerShell фармони npm бо хато дар бораи npm.ps1 ва «execution policy» ҷавоб диҳад — иҷозаи иҷрои скриптҳоро барои корбари худ бо як фармон диҳед: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned (ва Y-ро тасдиқ кунед). Варианти дигар — сатри фармони оддии cmd ё Git Bash-ро кушодан. Дар macOS чунин мушкил нест.

package.json-и аввал

Дар папкаи холии лоиҳа npm init -y-ро иҷро кунед — package.json эҷод мешавад. Баъд бастаро насб кунед:

Терминал
mkdir demo-npm
cd demo-npm
npm init -y            # создать package.json с ответами по умолчанию
npm install dayjs      # библиотека для дат → попадёт в "dependencies"
npm install -D vite    # инструмент разработки → попадёт в "devDependencies"

Дар папка чӣ пайдо шуд:

demo-npm/ ├─ package.json рӯйхати харид: ба Git commit мекунем ├─ package-lock.json версияҳои дақиқи ҳар чизи насбшуда: онро ҳам commit мекунем └─ node_modules/ коди зеркашишуда: ҳазорҳо файл, ба Git НАМЕГУЗОРЕМ

package.json аз чӣ иборат аст

package.json
{
  "name": "mfs-shop",
  "version": "1.2.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "dayjs": "^1.11.13"
  },
  "devDependencies": {
    "vite": "^8.3.0"
  }
}
name, version
Ном ва версияи лоиҳа. Ном — бо ҳарфҳои хурди лотинӣ, бе фосила.
private: true
«Ин барнома аст, на китобхонаи нашр». Аз фиристодани тасодуфии он ба npm муҳофизат мекунад.
type: "module"
Файлҳои .js-и лоиҳа ҳамчун модулҳои ES ҳисоб мешаванд — яъне import/export дар абзорҳои Node ҳам кор мекунанд.
scripts
Фармонҳои худӣ: ном → чӣ иҷро шавад. Муфассалтар каме поён.
dependencies
Бастаҳое, ки коди барномаи шумо истифода мебарад: масалан, dayjs, ки дар main.js import мекунед.
devDependencies
Бастаҳо барои таҳиягар: ҷамъкунанда, санҷиши код, форматкунанда. Дар коди барнома онҳоро import намекунанд.
Маслиҳат

Дар лоиҳаи Vite ҳар чизе ки import мекунед, ҳангоми build ба файлҳои ниҳоӣ печонида мешавад, барои ҳамин дар сайт сарҳади байни ду рӯйхат намоён нест. Вале одат лозим аст: вақте лоиҳаи бегонаро кушоед, аз рӯи ин рӯйхатҳо фавран мефаҳмед, ки «барнома ба чӣ ниёз дорад» ва «бо чӣ сохта мешавад». Қоида оддӣ аст: дар import дар дохили src/ лозим бошад — ин dependencies аст (npm install ном), танҳо барои кор бо лоиҳа лозим бошад — devDependencies (npm install -D ном).

Версияҳо: ^ ва ~ чӣ маъно доранд

Версияи баста аз се рақам иборат аст: MAJOR.MINOR.PATCH, масалан 1.11.13. Ин қарордод semver номида мешавад:

  • PATCH (1.11.13) — хаторо ислоҳ карданд, чизе вайрон нашуд;
  • MINOR (1.11.13) — имкониятҳо илова карданд, коди кӯҳна кор мекунад;
  • MAJOR (1.11.13) — тағйироте, ки кодатонро метавонанд вайрон кунанд.
НавиштЧӣ иҷозат астМисол барои 1.4.2
"1.4.2"Танҳо ҳамин версиятанҳо 1.4.2
"~1.4.2"Навсозиҳои PATCHаз 1.4.2 то 1.4.x (1.5.0 дигар не)
"^1.4.2"Навсозиҳои MINOR ва PATCH (npm install ба таври пешфарз ҳамин тавр насб мекунад)аз 1.4.2 то 1.x.x (2.0.0 дигар не)

Муҳим: рақамҳо ҳамчун рақам муқоиса мешаванд, на ҳамчун матн. Версияи 1.10.0 аз 1.9.0 навтар аст — гарчанде ҳамчун сатр "1.10.0" аз "1.9.0" хурдтар аст. Месанҷем:

Версияҳо — рақаманд, на сатр · Ctrl + Enter
console.log("1.10.0" > "1.9.0");   // false — муқоиса ҳамчун матн хато аст!

const parse = (v) => v.split(".").map(Number);
console.log(parse("1.10.0"));      // [1, 10, 0]
console.log(parse("1.10.0")[1] > parse("1.9.0")[1]); // true — 10 аз 9 калонтар аст

package-lock.json бошад, муқаррар мекунад, ки кадом версияҳо воқеан насб шуданд. Барои ҳамин дар назди шумо ва ҳамкоратон пас аз npm install як код пайдо мешавад, ҳатто агар дар феҳрист версияи нав баромада бошад. Ин файлро бо даст таҳрир кардан лозим нест.

Фармонҳои асосии npm

ФармонЧӣ кор мекунад
npm install (ё npm i)Ҳар чизи дар package.json навишташударо насб кардан. Пас аз git clone иҷро мекунем.
npm install номБастаро ба dependencies илова кардан.
npm install -D номБастаро ба devDependencies илова кардан.
npm uninstall номБастаро хориҷ кардан.
npm run номСкриптро аз scripts иҷро кардан.
npm outdatedБастаҳоеро нишон додан, ки барояшон версияҳои нав баромадаанд.

Скриптҳои npm: фармонҳои худии лоиҳа

Дар блоки scripts шумо ба фармонҳои дароз номҳои кӯтоҳ медиҳед. Ба ҷои он ки ба ёд гиред, ҷамъкунанда чӣ тавр оғоз мешавад, ҳама як чизро менависанд: npm run dev. Ҳар кӣ лоиҳаро кушояд — як сол баъд ё таҳиягари дигар — дар package.json мебинад, ки кадом фармонҳо дастрасанд.

package.json (қисмат)
"scripts": {
  "dev": "vite",                // npm run dev      → сервери таҳияро оғоз кардан
  "build": "vite build",        // npm run build    → сайтро ба папкаи dist ҷамъ кардан
  "preview": "vite preview"     // npm run preview  → сайти ҷамъшударо дидан
}

Шарҳҳои //-ро дар JSON-и ҳақиқӣ навиштан мумкин нест — дар ин ҷо онҳо танҳо барои тавзеҳанд.

  • Барои калимаҳои start ва test калимаи run-ро нанависед ҳам мешавад: npm start, npm test. Барои боқӣ (dev, build) — ҳатмист: npm run dev.
  • Фармонҳоро тавассути && якҷоя кардан мумкин аст: "check": "npm run build && npm run preview" — дуюмӣ танҳо дар сурате оғоз мешавад, ки якум бо муваффақият анҷом ёбад.
  • Скриптҳо дар ҳамаи системаҳо кор мекунанд, ба шарте ки барномаҳои байнисистемавӣ истифода баред. Фармонҳое мисли rm -rf dist дар Windows-и оддӣ кор намекунанд — барои чунин ҳолатҳо бастаҳо мегиранд (масалан, rimraf).
  • npx ном — як бор зеркашӣ ва иҷро кардани барнома, бе насб кардан ба лоиҳа. Маҳз ҳамин тавр npm create vite@latest кор мекунад (дар асл ин npx create-vite@latest аст).
Бастаҳоро бодиққат насб кунед

Насби баста — ин иҷрои коди бегона дар компютери шумост. Пеш аз он ки бо маслиҳати интернет ё зеҳни сунъӣ npm install иҷро кунед, дар npmjs.com санҷед: оё ном дуруст навишта шудааст, баста дар як ҳафта чанд маротиба зеркашӣ шудааст, муаллиф кист, навсозии охирин кай буд. Зеҳни сунъӣ гоҳо бастаҳоеро меандешад, ки вуҷуд надоранд, ва қаллобон бастаҳо бо номҳои монанд қайд мекунанд (reacct ба ҷои react). Агар ном ба шумо ношинос бошад — аз муаллим пурсед.

Муфассалтар хонед: npm Docs — package.json · npm Docs — Semantic versioning

Амал: мустаҳкам мекунем

Дар ин ҷо мо бо package.json ҳамчун бо маълумоти оддӣ кор мекунем: ин объекти JSON аст ва шумо аллакай онҳоро таҳлил карда метавонед.

ВАЗИФАИ 3.1

package.json-и вайроншуда

осон

Матни package.json хатоҳои формати JSON дорад ва JSON.parse меафтад. Матн-ро ислоҳ кунед (бе тағйири коди зери он): дар JSON танҳо нохунакҳои дукарата ва пас аз унсури охирин вергул набояд бошад.

Таҳрир кардан мумкин аст · Ctrl + Enter
const text = `{
  "name": 'mfs-shop',
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
  }
}`;

const pkg = JSON.parse(text);
console.log(pkg.name, pkg.version);
console.log(Object.keys(pkg.scripts).join(", "));
Натиҷаи интизоршаванда
mfs-shop 1.0.0
dev, build
Ишора 1

Хатоҳо дутоанд. Аввалӣ — нохунакҳои яккарата дар гирди mfs-shop: дар JSON танҳо дукарата иҷозат аст.

Ишора 2

Дуюм — вергули зиёдатӣ пас аз "build": "vite build". Онро хориҷ кунед.

ВАЗИФАИ 3.2

Шиносномаи лоиҳа

осон

Объекти pkg дода шудааст — package.json-и таҳлилшуда. Се сатрро аз рӯи намунаи натиҷаи интизоршаванда бо истифода аз маълумоти объект чоп кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const pkg = {
  name: "mfs-shop",
  version: "1.2.0",
  scripts: { dev: "vite", build: "vite build", preview: "vite preview" },
  dependencies: { dayjs: "^1.11.13", nanoid: "^5.0.7" },
  devDependencies: { vite: "^8.3.0", eslint: "^9.0.0", prettier: "^3.3.0" },
};

// 1) Проект: ном@версия
// 2) Скриптов: чанд
// 3) Библиотек в приложении: номҳо бо вергул
// 4) Инструментов разработки: чанд
Натиҷаи интизоршаванда
Проект: mfs-shop@1.2.0
Скриптов: 3
Библиотек в приложении: dayjs, nanoid
Инструментов разработки: 3
Ишора 1

Object.keys(obj) массиви номҳои хосиятҳоро бармегардонад. Он length ва методи join(", ") дорад.

Ишора 2

Сатри якум: console.log(`Проект: ${pkg.name}@${pkg.version}`);. Китобхонаҳои барнома — калидҳои pkg.dependencies ҳастанд, абзорҳо — pkg.devDependencies.

ВАЗИФАИ 3.3

Кадом версия навтар аст

миёна

Функсияи compareVersions(a, b)-ро нависед: агар версияи a аз b кӯҳнатар бошад, -1, агар навтар бошад 1 ва агар баробар бошанд 0 бармегардонад. Версияҳо — сатрҳои намуди "1.10.0"; бояд рақамҳо муқоиса шаванд, на сатрҳо.

Таҳрир кардан мумкин аст · Ctrl + Enter
function compareVersions(a, b) {
  // ҳарду версияро ба рақамҳо таҷзия кунед ва навбатӣ муқоиса намоед: major, minor, patch
}

console.log(compareVersions("1.4.2", "1.4.10"));
console.log(compareVersions("2.0.0", "1.99.99"));
console.log(compareVersions("1.2.3", "1.2.3"));
console.log(compareVersions("1.10.0", "1.9.0"));
Натиҷаи интизоршаванда
-1
1
0
1
Ишора 1

a.split(".").map(Number) "1.10.0"-ро ба массиви [1, 10, 0] табдил медиҳад. Баъд бо давра аз се мавқеъ гузаред.

Ишора 2

Дар давра: агар pa[i] < pb[i] бошад — фавран return -1; агар калонтар бошад — return 1; агар баробар бошанд — ба рақами навбатӣ мегузарем. Пас аз давра — return 0.

ВАЗИФАИ 3.4

Оё версия мувофиқ аст

душвор

satisfies(version, range)-ро нависед. Диапазон метавонад чунин бошад: версияи дақиқ "1.2.3"; "^1.2.3" — ҳамон версияи major ва на пасттар аз нишондодашуда; "~1.2.3" — ҳамон major ва minor ва на пасттар аз нишондодашуда. Функсияи compareVersions аз вазифаи гузашта аллакай омода аст. Ҳисоб мекунем, ки major на камтар аз 1 аст.

Таҳрир кардан мумкин аст · Ctrl + Enter
function compareVersions(a, b) {
  const pa = a.split(".").map(Number);
  const pb = b.split(".").map(Number);
  for (let i = 0; i < 3; i++) {
    if (pa[i] !== pb[i]) return pa[i] < pb[i] ? -1 : 1;
  }
  return 0;
}

function satisfies(version, range) {
  // 1) навъи диапазонро аз рӯи аломати аввал муайян кунед
  // 2) аломати ^ ё ~-ро бурида, муқоиса кунед
}

const checks = [
  ["1.5.0", "^1.2.3"],
  ["2.0.0", "^1.2.3"],
  ["1.2.2", "^1.2.3"],
  ["1.2.9", "~1.2.3"],
  ["1.3.0", "~1.2.3"],
  ["1.2.3", "1.2.3"],
  ["1.2.4", "1.2.3"],
];
for (const [v, r] of checks) console.log(v, r, satisfies(v, r));
Натиҷаи интизоршаванда
1.5.0 ^1.2.3 true
2.0.0 ^1.2.3 false
1.2.2 ^1.2.3 false
1.2.9 ~1.2.3 true
1.3.0 ~1.2.3 false
1.2.3 1.2.3 true
1.2.4 1.2.3 false
Ишора 1

Се ҳолат: диапазон бо ^, бо ~ ё бе аломат оғоз мешавад (версияи дақиқ — compareVersions(...) === 0 кифоя аст). Барои ду ҳолати аввал қисмҳои версия ҳамчун рақам лозиманд.

Ишора 2

Барои ^: major-и версия бо major-и диапазон баробар аст ва compareVersions(version, base) >= 0, ки дар он base = range.slice(1). Барои ~ — ҳамон, илова бар ин minor ҳам баробар аст.

ВАЗИФАИ 3.5

Mini-npm run

миёна

runScript(name)-ро амалӣ кунед, ки худро ба ҷои npm run вонамуд мекунад. Агар скрипт бошад — ду сатр чоп мекунад: > ном@версия скрипт ва > фармон. Агар набошад — як сатри npm error Missing script: "ном".

Таҳрир кардан мумкин аст · Ctrl + Enter
const pkg = {
  name: "mfs-shop",
  version: "1.2.0",
  scripts: { dev: "vite", build: "vite build" },
};

function runScript(name) {
  // ...
}

runScript("dev");
runScript("build");
runScript("deploy");
Натиҷаи интизоршаванда
> mfs-shop@1.2.0 dev
> vite
> mfs-shop@1.2.0 build
> vite build
npm error Missing script: "deploy"
Ишора 1

Фармонро гиред: const command = pkg.scripts[name];. Агар скрипт набошад, дар он undefined мешавад.

Ишора 2

Санҷиш: if (!command) { console.log(`npm error Missing script: "${name}"`); return; } — ва баъд ду console.log бо сатрҳои қолабӣ.

ВАЗИФАИ 3.6

Чӣ ба куҷо навиштан лозим

осон

Барои ҳар баста маълум аст, ки ба куҷо лозим аст: "app" (дар коди барнома import мешавад) ё "tools" (абзори таҳия). Онҳоро ба ду рӯйхат тақсим кунед, аз рӯи алифбо мураттаб намоед ва мисли намуна чоп кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const packages = [
  { name: "dayjs", usedIn: "app" },
  { name: "vite", usedIn: "tools" },
  { name: "nanoid", usedIn: "app" },
  { name: "prettier", usedIn: "tools" },
  { name: "eslint", usedIn: "tools" },
];

// dependencies — usedIn "app", devDependencies — usedIn "tools"
Натиҷаи интизоршаванда
dependencies: dayjs, nanoid
devDependencies: eslint, prettier, vite
Ишора 1

filter, баъд map(p => p.name) ва sort()-ро истифода баред.

Ишора 2

packages.filter(p => p.usedIn === "app").map(p => p.name).sort().join(", ") — ва ҳамин гуна барои "tools".

04 Vite: сервери таҳия ва build

Vite (ба забони фаронсавӣ «зуд» маъно дорад, «вит» хонда мешавад) — абзоре, ки ду вазифаро ҳал мекунад. Аввалан, сервери маҳаллиро оғоз мекунад, то модулҳо ҳангоми таҳия кор кунанд ва саҳифа фавран пас аз нигоҳ доштани файл навсозӣ шавад. Дуюм, лоиҳаро ҷамъ мекунад ба сайти тайёр: бисёр модулҳоро ба якчанд файл часпонда, фишурда ба папкаи dist мегузорад.

Монандӣ аз ҳаёт

Ошхона ва расонидан. То даме ки шумо мепазед (таҳия мекунед), ҳама маҳсулот дар сари миз дар қуттиҳои қулай меистанд: гирифтӣ, чашидӣ, ислоҳ кардӣ — ин dev-сервер аст. Аммо ба муштарӣ шумо миз бо қуттиҳоро намефиристед, балки фармоиши ботартиб бастабандишударо: ҳама дар як баста, бе чизи зиёдатӣ — ин build (build) аст. Бастаро ба ҳар хостинг гузоштан мумкин аст.

Dev-сервер ва build: фарқ дар чист

Dev-сервер (npm run dev)Build (npm run build)
Барои чӣКод навиштан ва фавран натиҷаро диданСайтро барои нашр тайёр кардан
ФайлҳоМодулҳои шумо қариб «чунон ки ҳастанд», бо дархости браузер дода мешавандБа якчанд файл часпонда ва фишурда шудаанд, бо «хэш» дар ном
НатиҷаНишонии http://localhost:5173, ба диск чизе навишта намешавадПапкаи dist/ бо сайти тайёр
Кор мекунадТо даме ки терминал кушода аст; қатъ кардан — Ctrl+CЯк бор, дар як-ду сония, ва ба анҷом мерасад
НавсозӣСаҳифа пас аз нигоҳ доштан худаш тағйир меёбад (HMR)Бояд аз нав ҷамъ кард

Дастури қадам ба қадам: лоиҳа эҷод мекунем

Дар компютери худ якҷоя бо муаллим иҷро кунед. Папкаро барои лоиҳаҳо бе кириллица ва фосила дар роҳ интихоб кунед, масалан C:\dev дар Windows ё ~/dev дар macOS. Лоиҳаро дар дохили папкаҳои «ҳамоҳангшаванда» (OneDrive, iCloud Drive) эҷод накунед: ҳазорҳо файли node_modules ҳамоҳангсозиро суст мекунанд.

  1. Терминалро дар папкаи даркорӣ кушоед. macOS: барномаи «Терминал» ё терминали VS Code. Windows: PowerShell ё терминали VS Code (дар проводник дар сатри нишонии папка powershell навиштан мумкин аст).
  2. Лоиҳаро эҷод кунед. Фармон якчанд савол медиҳад — бо тирчаҳо интихоб кунед, бо Enter тасдиқ намоед.
  3. Ба папкаи лоиҳа гузаред ва вобастагиҳоро насб кунед.
  4. Сервери таҳияро оғоз кунед ва нишонии аз терминалро дар браузер кушоед.
  5. Серверро қатъ кунед — Ctrl+C дар терминал (ҳам дар Windows, ҳам дар macOS).
Терминал
npm create vite@latest
# Project name: → my-shop
# Select a framework: → Vanilla
# Select a variant: → JavaScript
# если спросят про дополнительные опции — оставьте значения по умолчанию

cd my-shop
npm install
npm run dev

Ҳамон чиз бо як сатр, бе саволҳо (---и дукарата лозим аст, то ки npm опсияҳоро минбаъд ба create-vite диҳад):

Терминал
npm create vite@latest my-shop -- --template vanilla

Пас аз npm run dev шумо тақрибан чунин чизеро мебинед:

Терминал — баромад
> my-shop@0.0.0 dev
> vite

  VITE v8.3.4  ready in 95 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

http://localhost:5173/-ро дар браузер кушоед. Рақами версия дар назди шумо метавонад дигар бошад. Агар порти 5173 банд бошад (шумо аллакай Vite-ро дар тирезаи дигар оғоз кардаед), Vite худаш навбатиро — 5174-ро мегирад ва дар ин бора менависад. Дар лоиҳа ягон матнро дар src/main.js тағйир диҳед ва нигоҳ доред: саҳифа бе бозбор кардан навсозӣ мешавад. Ин HMR (Hot Module Replacement) номида мешавад.

Агар чизе хато шуд

«npm: command not found» / «не является внутренней или внешней командой» — Node.js насб нашудааст ё терминал пеш аз насб кушода шудааст: онро пӯшед ва аз нав кушоед. Хато дар бораи версияи Node — Node.js-ро то LTS навсозӣ кунед. Windows, тирезаи «Брандмауэр» — дастрасиро барои Node.js дар шабакаи хусусӣ иҷозат диҳед: вагарна саҳифа кушода намешавад. Саҳифаи сафед — DevTools (F12) → ҷадвали Console-ро кушоед: дар он навишта шудааст, ки кадом файл ёфт нашуд.

Vite чӣ эҷод кард

my-shop/ ├─ index.html саҳифаи асосӣ — нуқтаи вуруди тамоми сайт ├─ package.json скриптҳои dev / build / preview, vite дар devDependencies ├─ .gitignore node_modules ва dist-ро аллакай дорад ├─ public/ файлҳое, ки «чунон ки ҳастанд» дода мешаванд (favicon) └─ src/ ├─ main.js файли аввали JS: коди худро дар ин ҷо менависем ├─ counter.js мисоли модул — онро хориҷ кардан мумкин аст ├─ style.css услубҳо, тавассути import пайваст мешаванд └─ assets/ расмҳое, ки аз JS import мешаванд

Чизи асосӣ дар ин сохтор — index.html аст. Бар хилофи ҷамъкунандаҳои кӯҳна, дар ин ҷо он дар реша меистад ва худаш кодатонро пайваст мекунад:

index.html (қисмат)
<body>
  <div id="app"></div>
  <script type="module" src="/src/main.js"></script>
</body>

Дар src/main.js import-ҳои шинос намоёнанд. Услубҳо ва расмҳо низ тавассути import пайваст мешаванд — Vite худаш мефаҳмад, ки бо онҳо чӣ кор кунад:

src/main.js (қисмат)
import './style.css'                          // услубҳо — танҳо import бе ном
import viteLogo from './assets/vite.svg'      // расм → нишонии ниҳоии он
import { setupCounter } from './counter.js'   // модули мо

Build ва дидани натиҷа

Терминал
npm run build
npm run preview     # локальный просмотр собранного сайта
Терминал — баромади build (қисмат)
vite v8.3.4 building client environment for production...
✓ 9 modules transformed.
dist/index.html                  0.45 kB │ gzip: 0.29 kB
dist/assets/vite-BF8QNONU.svg    8.70 kB │ gzip: 1.60 kB
dist/assets/hero-CLDdwZDr.png   13.05 kB
dist/assets/index-CsUDhMuy.css   4.10 kB │ gzip: 1.46 kB
dist/assets/index-CAoPt-vL.js    4.05 kB │ gzip: 1.77 kB
✓ built in 273ms
  • Нӯҳ модул ба як файли JS (index-….js) ва як CSS табдил ёфтанд. Файлҳо камтар — боркунӣ зудтар.
  • Дар номи файлҳо хэш пайдо шуд (CAoPt-vL). Код тағйир ёфт — хэш иваз шуд, браузер файли тозаро зеркашӣ мекунад, на кӯҳнаро аз кэш мегирад.
  • Папкаи dist-ро ба ҳар хостинги статикӣ гузоштан мумкин аст. Онро ба Git commit намекунанд — он бо фармони build аз сарчашмаҳо ҳосил мешавад.
  • Агар сайт на дар решаи домен, балки дар нишонии намуди username.github.io/my-shop/ (GitHub Pages) зиндагӣ кунад, бояд vite.config.js эҷод карда, base: "/my-shop/"-ро нишон диҳед. Инро мо ҳангоми расидан ба нашр дида мебароем.

Тағйирёбандаҳои муҳит: чӣ дар браузер намоён аст

Нишонии API ва дигар танзимотро дар файли .env дар решаи лоиҳа ҷудо кардан қулай аст:

.env
VITE_API_URL=https://dummyjson.com
VITE_APP_TITLE=MakeFirstStep Shop
DB_PASSWORD=12345
src/api/products.js (қисмат)
const API_URL = import.meta.env.VITE_API_URL;   // Vite қиматро ҳангоми build ҷойгузин мекунад
console.log(import.meta.env.DB_PASSWORD);       // undefined — тағйирёбанда бе префикси VITE_ пинҳон аст
Дар коди браузерӣ сирр вуҷуд надорад

Ба коди сайт танҳо тағйирёбандаҳо бо префикси VITE_ меафтанд — ва пас аз build ҳар боздидкунанда онҳоро дар DevTools мебинад. Бинобар ин дар онҳо парол ва калидҳои хусусиро нигоҳ доштан mumkin нест: калидро дар фронтенд «пинҳон кардан» ғайриимкон аст. Дар лоиҳа бо API-и умумидастрас бе калид (мисли дарсҳои мо) ин даҳшатнок нест, вале одатро аз ҳамон аввал бояд парвариш кард. Файли .env.local-ро Vite тавассути .gitignore аллакай аз Git хориҷ кардааст; файли .env бо танзимоти умумиро commit кардан мумкин аст.

Муфассалтар хонед: Vite — Getting Started · Vite — Env Variables and Modes · learn.javascript.ru — Модулҳо

Амал: мустаҳкам мекунем

ВАЗИФАИ 4.1

Оғози аввали Vite

осон

Ин вазифа дар компютери шумо иҷро мешавад, онро худкор санҷидан мумкин нест — вақте анҷом додед, дастӣ қайд кунед. Лоиҳаи vite-test-ро эҷод кунед (қолаби vanilla), вобастагиҳоро насб намуда, npm run dev-ро оғоз кунед. Сарлавҳаи h1-ро дар src/main.js ба номи худатон иваз кунед ва боварӣ ҳосил намоед, ки саҳифа худаш навсозӣ шуд. Баъд npm run build-ро иҷро кунед ва дар терминал андозаи калонтарин файлро дар dist ёбед. Барои худ сабт кунед: версияи Vite, нишонии dev-сервер ва ин андоза.

Ишора 1

Пайдарпайӣ: npm create vite@latest vite-test -- --template vanilla, баъд cd vite-test, npm install, npm run dev.

Ишора 2

Версияи Vite ва нишонӣ дар баромади npm run dev навишта шудаанд. Андозаи файлҳо — дар баромади npm run build, сутуни чапи «gzip».

ВАЗИФАИ 4.2

Таҳлили баромади build

миёна

Матне дода шудааст, ки npm run build чоп кардааст. Онро дар код таҳлил кунед: ҳамаи сатрҳои бо файлҳои аз dist-ро ёбед, вазнинтаринро муайян намоед (аз рӯи андоза то gzip) ва андозаи умумиро ҳисоб кунед. Се сатрро мисли намуна чоп кунед. Маҷмӯъро то ду рақами баъд аз вергул тавассути toFixed(2) мудаввар кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const output = `
vite v8.3.4 building client environment for production...
✓ 9 modules transformed.
dist/index.html                  0.45 kB │ gzip: 0.29 kB
dist/assets/vite-BF8QNONU.svg    8.70 kB │ gzip: 1.60 kB
dist/assets/hero-CLDdwZDr.png   13.05 kB
dist/assets/index-CsUDhMuy.css   4.10 kB │ gzip: 1.46 kB
dist/assets/index-CAoPt-vL.js    4.05 kB │ gzip: 1.77 kB
✓ built in 273ms
`;

// 1) Файлов: чанд
// 2) Самый тяжёлый: ном (андоза kB)
// 3) Всего: маҷмӯъ kB
Натиҷаи интизоршаванда
Файлов: 5
Самый тяжёлый: dist/assets/hero-CLDdwZDr.png (13.05 kB)
Всего: 30.35 kB
Ишора 1

Файлҳо — сатрҳое ҳастанд, ки бо dist/ оғоз мешаванд. Матнро аз рӯи \n ҷудо кунед, бо startsWith("dist/") филтр намоед.

Ишора 2

Аз ҳар сатр ном ва рақами аввалро пеш аз «kB» гиред: line.match(/^(\S+)\s+([\d.]+) kB/) ном дар m[1] ва андозаро дар m[2] медиҳад (Number-ро фаромӯш накунед).

ВАЗИФАИ 4.3

Чӣ ба браузер мерасад

миёна

Функсияи publicEnv(env)-ро нависед: он объекти навро бармегардонад, ки дар он танҳо тағйирёбандаҳои бо VITE_ оғозшаванда мондаанд — маҳз чунинҳоро Vite ба коди сайт медиҳад. Баъд онҳоро яктоӣ бо формати НОМ=қимат чоп кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const env = {
  VITE_API_URL: "https://dummyjson.com",
  DB_PASSWORD: "12345",
  VITE_APP_TITLE: "MakeFirstStep Shop",
  SECRET_KEY: "abc",
};

function publicEnv(env) {
  // ...
}

const result = publicEnv(env);
// ҳар ҷуфтро бо формати НОМ=қимат чоп кунед
Натиҷаи интизоршаванда
VITE_API_URL=https://dummyjson.com
VITE_APP_TITLE=MakeFirstStep Shop
Ишора 1

Object.entries(env) массиви ҷуфтҳои [калид, қимат]-ро медиҳад, онро бо методи startsWith филтр кардан мумкин аст.

Ишора 2

Object.fromEntries(Object.entries(env).filter(([key]) => key.startsWith("VITE_"))). Чоп: давраи for (const [k, v] of Object.entries(result)).

05 Амал дар дарс: барномаро ба Vite мегузаронем

Барномаи дарси 16-ро мегирем — ҷустуҷӯ аз рӯи API бо ҳолатҳои боркунӣ, натиҷаи холӣ ва хато ва бо debounce — ва ба Vite мегузарем. Дар поён — намунаи меъёрӣ дар феҳристи маҳсулоти dummyjson.com. Дар назди шумо номи функсияҳо ва файлҳо метавонанд фарқ кунанд — ин муқаррарист: ғоя-и ҷудокунӣ муҳим аст, на ҳарф ба ҳарф.

Нақшаи гузариш

1) Версияи кӯҳнаро дар Git нигоҳ медорем. 2) Лоиҳаро дар Vite эҷод мекунем. 3) Нишонгузорӣ (разметка)-ро ба index.html, услубҳоро — ба src/styles/ мегузаронем. 4) JS-ро ба модулҳо тақсим мекунем: api, ui, utils, main. 5) npm run dev-ро оғоз мекунем ва месанҷем, ки ҳама мисли пештара кор мекунад. 6) npm run build-ро иҷро мекунем. 7) Commit ва push ба GitHub. Қоидаи гузариш: рафтори барнома тағйир намеёбад — танҳо сохтори код.

Қадами 1. Лоиҳаи нав

Терминал
# в папке рядом со старым проектом, не внутри него
npm create vite@latest products-vite -- --template vanilla
cd products-vite
npm install
npm run dev

Қадами 2. Қолабро тоза мекунем

  • src/counter.js, папкаи src/assets/ ва ҳар чизи дар public/-ро хориҷ кунед, ба ҷуз нишонча, агар ба шумо лозим бошад. Дар index.html истиноди favicon.svg-ро ҳазф кунед, агар файлро хориҷ карда бошед.
  • Дар index.html мундариҷаи <body>-ро бо нишонагузории барномаи худ иваз кунед. Сатри <script type="module" src="/src/main.js">-ро гузоред.
  • Папкаҳои src/api, src/ui, src/utils, src/styles-ро эҷод кунед. CSS-и лоиҳаи кӯҳнаро ба src/styles/style.css гузоред (файли src/style.css-и қолабро хориҷ кунед).
index.html
<!doctype html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Каталог товаров</title>
  </head>
  <body>
    <main class="app">
      <h1>Каталог товаров</h1>
      <input id="search" type="search" placeholder="Например, phone" />
      <p id="status">Введите запрос</p>
      <ul id="list"></ul>
    </main>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

Қадами 3. Кодро ба модулҳо тақсим мекунем

Ҳар файл — як масъулият. Аввал api: танҳо дархост ва санҷиши ҷавоб, ҳеҷ DOM нест.

src/api/products.js
const API_URL = "https://dummyjson.com";

export async function searchProducts(query, signal) {
  const url = `${API_URL}/products/search?q=${encodeURIComponent(query)}&limit=10`;
  const response = await fetch(url, { signal });

  if (!response.ok) {
    throw new Error(`Ошибка сервера: ${response.status}`);
  }

  const data = await response.json();
  return data.products;
}

Баъд utils: debounce дар бораи барномаи мо чизе намедонад, бинобар ин дар ҳар лоиҳа зиндагӣ карда метавонад.

src/utils/debounce.js
export function debounce(fn, delay = 300) {
  let timerId;
  return (...args) => {
    clearTimeout(timerId);
    timerId = setTimeout(() => fn(...args), delay);
  };
}

ui танҳо барои он чизе масъул аст, ки корбар мебинад: ҳолатро нишон медиҳад ва рӯйхатро тасвир мекунад.

src/ui/render.js
const statusEl = document.querySelector("#status");
const listEl = document.querySelector("#list");

export function showStatus(text) {
  statusEl.textContent = text;
}

export function renderProducts(products) {
  const items = products.map((product) => {
    const li = document.createElement("li");
    li.textContent = `${product.title} — ${product.price} $`;
    return li;
  });
  listEl.replaceChildren(...items);
}

Ва ниҳоят, main.js — роҳбари оркестр: худаш ҳеҷ чиз намекунад, аммо медонад, ки киро ва бо кадом тартиб даъват кунад.

src/main.js
import "./styles/style.css";
import { searchProducts } from "./api/products.js";
import { renderProducts, showStatus } from "./ui/render.js";
import { debounce } from "./utils/debounce.js";

let controller;

async function search(query) {
  controller?.abort();                 // дархости пештараро бекор мекунем
  controller = new AbortController();

  if (!query.trim()) {
    showStatus("Введите запрос");
    renderProducts([]);
    return;
  }

  showStatus("Загрузка...");
  try {
    const products = await searchProducts(query, controller.signal);
    renderProducts(products);
    showStatus(products.length ? `Найдено: ${products.length}` : "Ничего не найдено");
  } catch (error) {
    if (error.name === "AbortError") return;   // инро худамон бекор кардем — хато нест
    showStatus(`Ошибка: ${error.message}`);
  }
}

document
  .querySelector("#search")
  .addEventListener("input", debounce((event) => search(event.target.value), 300));
Монандӣ аз ҳаёт

Мудири чойхона (main.js) худаш намепазад ва зарфҳоро намешӯяд. Ӯ фармоиш мегирад, ба ошпаз (api) мегӯяд «пазед», ба пешхизмат (ui) — «биёред», ба ёрдамчӣ (utils) — «интизор шав, то меҳмон гапашро тамом кунад». Пешхизматро иваз кардан мумкин аст, бе даст задан ба ошхона — ва баръакс. Маҳз ҳамин ҳадафи модулҳост.

Қадами 4. Месанҷем

  1. npm run dev-ро оғоз кунед ва ҳамаи сенарияҳои дарси 16-ро такрор намоед: дархости холӣ, ҷустуҷӯи муқаррарӣ, дархост бе натиҷа, хомӯш кардани шабака (DevTools → Network → Offline). Ҳама бояд мисли пештара кор кунад.
  2. Агар саҳифаи сафед бошад — DevTools (F12) → Console-ро кушоед. Бештар ин хатои роҳ аст: «Failed to resolve import», хатои имлоӣ дар номи файл ё .js-и фаромӯшшуда.
  3. npm run build-ро иҷро кунед, баъд npm run preview — барнома бояд аз версияи ҷамъшуда ҳам кор кунад.

Қадами 5. Git ва GitHub

Қолаби Vite аллакай .gitignore-ро бо node_modules ва dist эҷод кардааст. Инро санҷед: пас аз git status ин папкаҳо дар рӯйхат набояд бошанд.

Терминал
git init
git status                       # node_modules и dist в списке быть не должно
git add .
git commit -m "init vite project"
# на github.com создайте пустой репозиторий (без README и .gitignore) и скопируйте его адрес
git remote add origin https://github.com/ВАШ_ЛОГИН/products-vite.git
git branch -M main
git push -u origin main

Агар Git ҳанӯз насб нашудааст: дар Windows Git for Windows-ро аз git-scm.com зеркашӣ кунед, дар macOS фармони git ҳангоми оғози аввал худаш насби абзорҳои таҳиягарро пешниҳод мекунад. Минбаъд ҳангоми гузариш commit-ҳои хурд кунед: move html to vite, split code into modules — таърих дар репозиторий намоён мешавад.

Дому дастҳои маъмули гузариш

1) Дар import ./ ё .js нест. 2) Скрипт дар index.html бе type="module" пайваст шудааст — он гоҳ import дар main.js кор намекунад. 3) Дар render.js унсурҳо аз рӯи id ҷустуҷӯ мешаванд, ки дар index.html-и нав нест — ҳангоми гузаронидани нишонагузорӣ id-ро гум накунед. 4) Ба Git папкаи node_modules афтод: онро бо фармони git rm -r --cached node_modules аз индекс хориҷ кунед ва сатрро ба .gitignore илова намоед.

Муфассалтар хонед: Vite — Features · MDN — import()-и динамикӣ

Амал: модулҳоро дар майдончаи озмоишӣ ҷамъ мекунем

Дар браузер файлҳо нестанд, вале мо метавонем ҳамин ҷамъкунии модулҳоро машқ кунем. Дар вазифаҳо — ҳамон нақшҳо: api, ui, utils, main. Дар дохили «файлҳо»-и ин вазифаҳо сатрҳои оддиро бо + истифода баред (бе сатрҳои қолабии ${…}), вагарна онҳо бо қолабе, ки «файл» дар он ҷойгир аст, омехта мешаванд.

ВАЗИФАИ 5.1

Роҳбари оркестр main.js

миёна

Модулҳои api.js (ҷустуҷӯи маҳсулот, ҷавоб пас аз 30 мс меояд) ва render.js омодаанд. Функсияи search(query)-ро дар main.js нависед: ҳолати «Загрузка...»-ро нишон диҳед, маҳсулотро гиред, баъд ё «Ничего не найдено», ё «Найдено: N» ва рӯйхатро. Барои дархостҳои интихобшуда search-ро пай дар пай даъват кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const apiUrl = url(`
  const DB = [
    { title: "Телефон", price: 2500 },
    { title: "Чехол для телефона", price: 80 },
    { title: "Наушники", price: 300 },
  ];
  export async function searchProducts(query) {
    await new Promise((resolve) => setTimeout(resolve, 30));
    return DB.filter((p) => p.title.toLowerCase().includes(query.toLowerCase()));
  }
`);

const renderUrl = url(`
  export function showStatus(text) { console.log("[статус] " + text); }
  export function renderProducts(list) {
    for (const p of list) console.log("- " + p.title + " — " + p.price + " сомони");
  }
`);

await import(url(`
  import { searchProducts } from "${apiUrl}";
  import { showStatus, renderProducts } from "${renderUrl}";

  async function search(query) {
    // 1) showStatus("Загрузка...")
    // 2) маҳсулотро гирифтан: await searchProducts(query)
    // 3) холӣ → "Ничего не найдено", вагарна "Найдено: N" ва renderProducts
  }

  await search("телефон");
  await search("xyz");
`));
Натиҷаи интизоршаванда
[статус] Загрузка...
[статус] Найдено: 2
- Телефон — 2500 сомони
- Чехол для телефона — 80 сомони
[статус] Загрузка...
[статус] Ничего не найдено
Ишора 1

Функсияи search ғайримуттаҳид (async) аст — дар дохили он await навиштан мумкин аст. Аввал ҳолат, баъд дархост, баъд шохаи if.

Ишора 2

const products = await searchProducts(query); — баъд: if (products.length === 0) { showStatus("Ничего не найдено"); return; }, ва пас аз он showStatus("Найдено: " + products.length); renderProducts(products);

ВАЗИФАИ 5.2

Модули debounce

душвор

Модули debounce.js-ро нависед: функсияи debounce(fn, delay)-ро экспорт кунед, ки даъвати fn-ро ба delay мс ба таъхир меандозад ва агар онро аз нав даъват кунанд, таймерро аз сифр мекунад. Дар main.js «корбар» зуд менависад (ҳарфҳо пас аз 10 мс меоянд) ва пас аз таваққуф боз менависад. Бояд дақиқан ду даъват шавад — барои ҳар «силсила»-и ворид кардан яктоӣ.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const debounceUrl = url(`
  // export function debounce(fn, delay) { ... }
`);

await import(url(`
  import { debounce } from "${debounceUrl}";

  const search = debounce((q) => console.log("поиск: " + q), 50);

  search("к");
  setTimeout(() => search("ку"), 10);
  setTimeout(() => search("кур"), 20);
  setTimeout(() => search("курут"), 150);   // пас аз таваққуф — силсилаи нав
`));
Натиҷаи интизоршаванда
поиск: кур
поиск: курут
Ишора 1

Таймерро байни даъватҳо бояд ҷое нигоҳ дошт: тағйирёбандаи timerId-ро дар функсияи debounce эълон кунед, ва функсияи навро баргардонед, ки онро истифода мебарад (closure).

Ишора 2

export function debounce(fn, delay) { let id; return (...args) => { clearTimeout(id); id = setTimeout(() => fn(...args), delay); }; }

ВАЗИФАИ 5.3

Аз порчаи дароз ба функсияҳо

миёна

Код ҳисоби як мизро ҳисоб ва чоп мекунад. Акнун бояд ҳисоби мизи дуюмро ҳам чоп кард — нусха бардоштани код хато мебуд. Онро ба функсияҳои хурд бознависед (масалан, lineTotal, orderTotal, printReport(title, orders)) ва барои ҳарду миз даъват кунед. Ин ҳамон усулест, ки ҳангоми тақсим ба модулҳо: як блок — як вазифа.

Таҳрир кардан мумкин аст · Ctrl + Enter
const table1 = [
  { name: "Самбуса", price: 5, qty: 10 },
  { name: "Курутоб", price: 35, qty: 2 },
  { name: "Чой", price: 3, qty: 4 },
];
const table2 = [
  { name: "Шашлык", price: 25, qty: 3 },
  { name: "Лепёшка", price: 4, qty: 5 },
];

// --- коди кӯҳна (танҳо барои мизи якум) ---
console.log("== Стол 1 ==");
let sum = 0;
for (const o of table1) {
  const line = o.price * o.qty;
  console.log(o.name + " x" + o.qty + " = " + line + " сомони");
  sum += line;
}
console.log("Итого: " + sum + " сомони");
Натиҷаи интизоршаванда
== Стол 1 ==
Самбуса x10 = 50 сомони
Курутоб x2 = 70 сомони
Чой x4 = 12 сомони
Итого: 132 сомони
== Стол 2 ==
Шашлык x3 = 75 сомони
Лепёшка x5 = 20 сомони
Итого: 95 сомони
Ишора 1

Тамоми «коди кӯҳна»-ро ба функсияи printReport(title, orders) печонед: сарлавҳа ва массив параметр мешаванд, дар дохил table1 бо orders иваз мешавад.

Ишора 2

Баъд ҳисобро ба lineTotal(order) ва orderTotal(orders) баред, даъватҳоро бошад ду сатр кунед: printReport("== Стол 1 ==", table1); ва ҳамин гуна барои table2.

06 Блоки ЗС: аз ӯ мепурсем, ки кодро ба модулҳо тақсим кунад

Тақсим кардани файл ба модулҳо — вазифаи маъмули ЗС аст: он механикӣ аст ва натиҷаро бо иҷро санҷидан мумкин аст. Аммо маҳз дар ин ҷо ЗС бештар чизҳои хурдро «вайрон мекунад»: default ва экспорти номдорро омехта мекунад, .js-ро дар роҳ фаромӯш мекунад, бастаҳоеро меандешад, ки дар лоиҳа нестанд. Барои ҳамин имрӯз маҳоратро машқ мекунем: дақиқ пурсидан ва то сатри охир санҷидан.

Қоидаҳои курс, ки дар ин ҷо махсусан муҳиманд

1. Аввал 15 дақиқа худатон кӯшиш мекунед: дар коғаз нақша кашед, ки кадом файлҳо ва папкаҳо ба шумо лозиманд ва дар ҳар кадом чӣ меистад. 2. Фақат баъд ба ЗС муроҷиат мекунед ва бо варианти худатон муқоиса менамоед. 3. Ба лоиҳа кодеро намегузоред, ки сатр ба сатр фаҳмонида наметавонед — хусусан import ва export: барои ҳар кадом бигӯед, аз куҷо ва чӣ гирифта мешавад. 4. Бастаҳоеро, ки ЗС пешниҳод кардааст, бе санҷиш дар npmjs.com насб накунед. 5. Бо иҷро санҷед: npm run dev ва npm run build.

Чӣ тавр пурсидан: бад ва хуб

Формулаи промпти курс: контекст → вазифа → маҳдудиятҳо → формати ҷавоб → санҷиш.

кодро ба модулҳо тақсим кун
Ман JavaScript меомӯзам, лоиҳаи таълимиро дар Vite месозам (қолаби vanilla, бе фреймворкҳо). Ҳоло тамоми код дар як файли src/main.js аст — онро дар поён мегузорам: [код]. Онро ба модулҳои ES тақсим кун ва сохтори папкаҳоро пешниҳод намо: api (дархостҳо ба dummyjson.com), ui (тасвир), utils (ёрирасонҳои хурд), main.js танҳо боқиро пайваст мекунад. Маҳдудиятҳо: рафтори барнома тағйир наёбад, бастаҳои нави npm илова нашаванд, экспортҳои номдор истифода шаванд, дар ҳамаи роҳҳо васеъкунии .js навишта шавад. Формати ҷавоб: аввал дарахти папкаҳо, баъд барои ҳар файл як блоки код бо сарлавҳа-роҳ, баъд рӯйхати «чӣ аз куҷо import мешавад» дар намуди ҷадвал. Санҷиш: дар охир 3 ҷойеро номбар кун, ки ман ҳангоми гузариш метавонам хато кунам (роҳҳо, id дар нишонагузорӣ, тартиби import-ҳо).

Промпти хубро нусха бардоред, ба ҷои [код] коди худро гузоред. Баъд — ҷавобро месанҷем. Чек-листи санҷиши ҷавоби ЗС оид ба модулҳо:

  • ☐ Ба ҳар import export-и воқеӣ бо ҳамон ном (ва бо ҳамон тарз: default ё номдор) мувофиқ аст.
  • ☐ Ҳамаи роҳҳо бо ./ ё ../ оғоз мешаванд, дар охир — .js, ҳарфи калон ва хурд бо номи файл мувофиқ аст.
  • ☐ import-и бастаҳое нест, ки дар package.json нестанд (lodash, axios ва ғ.). Агар лозим бошад — шумо инро бошуурона ҳал мекунед.
  • ☐ Давра нест: api ва ui файли main.js-ро import намекунанд.
  • ☐ Рафтор яксон аст: бо версияи пеш аз тақсим дар ҳамаи сенарияҳо муқоиса кунед.
  • ☐ npm run build бе хато анҷом меёбад.
Маслиҳат

Агар ЗС натиҷаеро баргардонд, ки кор намекунад, «ислоҳ кун» напурсед. Матни хаторо аз консол нусха бардоред, файле, ки дар он рух дод, илова кунед ва бипурсед: «Ин хато чӣ маъно дорад ва дар кадом сатр сабаб аст?» Аввал фаҳмед — баъд ислоҳ кунед.

Амал: мустаҳкам мекунем

ВАЗИФАИ 6.1

Ҷавоби ЗС-ро санҷед

миёна

ЗС ду модул ва main.js-ро пешниҳод кард, аммо кодашро иҷро кардан мумкин нест: дар он ду хато ҳаст, ки барои ҷавобҳои ЗС маъмуланд. Онҳоро ёбед ва танҳо дар main.js ислоҳ кунед, бе тағйири utils.js: маҳсулот бояд аз арзон ба гарон чоп шаванд, нарх — бо тахфифи 10%. Баста lodash дар лоиҳа насб нашудааст.

Таҳрир кардан мумкин аст · Ctrl + Enter
const url = (code) => {
  setTimeout(() => {}, 300); // танҳо ин саҳифа ба он ниёз дорад: майдончаи озмоишӣ интизор мешавад, то модул бор шавад
  return URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
};

const utilsUrl = url(`
  export default function formatPrice(p) { return p + " сомони"; }
  export function discount(price, percent) { return price - price * percent / 100; }
`);

await import(url(`
  import { formatPrice, discount } from "${utilsUrl}";
  import { sortBy } from "lodash";

  const products = [
    { name: "Курутоб", price: 35 },
    { name: "Самбуса", price: 5 },
    { name: "Чой", price: 3 },
  ];

  for (const p of sortBy(products, "price")) {
    console.log(p.name + ": " + formatPrice(discount(p.price, 10)));
  }
`));
Натиҷаи интизоршаванда
Чой: 2.7 сомони
Самбуса: 4.5 сомони
Курутоб: 31.5 сомони
Ишора 1

Хатои якум: formatPrice «бо пешфарз» экспорт мешавад, аммо дар қавсҳои фигурӣ import мешавад. Дуюм — баста lodash, ки вуҷуд надорад: sortBy-ро бо мураттабсозии дарунсохт иваз кунед.

Ишора 2

import formatPrice, { discount } from "${utilsUrl}"; ва ба ҷои sortBy(products, "price") — [...products].sort((a, b) => a.price - b.price).

07 Муаллим чӣ нишон медиҳад: Claude Code

Claude Code — ёрдамчии ЗС, ки дар терминал, бевосита дар папкаи лоиҳаи шумо кор мекунад. Вай, бар хилофи чат, файлҳои лоиҳаро мебинад, метавонад таҳрирро фавран дар якчанд файл пешниҳод кунад ва фармонҳоро иҷро намояд (npm run build, git diff). Аммо ҳар амал — таҳрири файл ё фармон — ро танҳо пас аз иҷозати шумо мекунад. Муаллим кори онро дар лоиҳаи ҳамин дарс нишон медиҳад; насб кардани Claude Code ба шумо имрӯз лозим нест. Вазифаи шумо — тамошо кардан ва сабт кардан, ки вазифа чӣ тавр гузошта мешавад ва натиҷа чӣ тавр санҷида мешавад.

Монандӣ аз ҳаёт

Ин ёрдамчии ошхонаи чойхона аст: вай зуд буридан ва тайёр карданро медонад, вале таомро барои ӯ шумо «мечашед». Гуфтед «пиёзро ҳалқа-ҳалқа бур» — ҳалқаҳо гирифтед. Гуфтед «чизе тайёр кун» — ногаҳонӣ гирифтед. Супориш ҳар қадар дақиқтар ва санҷиш пеш аз пешниҳод ҳар қадар диққатнокона бошад, натиҷа ҳамон қадар беҳтар мешавад.

Рафти намоиш

  1. Нуқтаи бозгашт. Пеш аз оғоз лоиҳа commit шудааст: git status «тоза»-ро нишон медиҳад. Агар ЗС кодро вайрон кунад — бо як фармон бармегардем.
  2. Оғоз дар папкаи лоиҳа. Муаллим терминалро дар решаи лоиҳа мекушояд ва claude-ро оғоз мекунад.
  3. Гузоштани вазифа. Вазифа аз рӯи формулаи курс навишта мешавад: контекст, вазифа, маҳдудиятҳо, формат, санҷиш (мисол дар поён).
  4. Нақша пеш аз таҳрирҳо. Аввал мепурсем, ки нақшаро нишон диҳад: кадом файлҳо эҷод ва тағйир дода мешаванд. Нақшаро тағйир додан осонтар аз ислоҳи таҳрирҳои тайёр аст. Дар Claude Code барои ин реҷаи нақша ҳаст (бо Shift+Tab иваз мешавад).
  5. Иҷозатҳо. Барои ҳар таҳрир ва фармон Claude Code мепурсад «мешавад?». Мо мехонем, ки дақиқан чӣ кор карданӣ аст ва танҳо баъд розӣ мешавем.
  6. Таҳлили натиҷа. git status, git diff-ро мебинем, npm run dev ва npm run build-ро иҷро мекунем. Аз рӯи чек-листи поён месанҷем.
  7. Қарор. Хубро — бо паёми фаҳмо commit мекунем. Бадро — бозгашт мекунем ва вазифаро дақиқ менамоем.

Вазифа чӣ тавр таҳия мешавад

Ин лоиҳаи таълимӣ дар Vite (vanilla JS) аст: ҷустуҷӯи маҳсулот аз рӯи dummyjson.com. Ҳоло тамоми код дар src/main.js аст. Онро ба модулҳо тақсим кун: src/api/products.js (дархостҳо), src/ui/render.js (тасвир), src/utils/debounce.js; main.js танҳо пайваст ва банд мекунад. Маҳдудиятҳо: рафтор тағйир наёбад, ба index.html ва package.json даст назан, бастаҳои нав насб накун, экспортҳои номдор, васеъкунии .js дар роҳҳо. Аввал нақшаро аз рӯи файлҳо нишон деҳ, тасдиқи маро интизор шав, баъд таҳрир ворид кун. Дар охир npm run build-ро иҷро кун ва натиҷаро хабар деҳ.

Ба се усул диққат диҳед: ба чӣ даст задан мумкин нест (index.html, package.json, бастаҳо), «аввал нақша, баъд таҳрирҳо» ва санҷиш дар охир (npm run build).

Натиҷаро чӣ тавр дидан: фармонҳо

Терминал
git status          # какие файлы изменены и какие появились
git diff --stat     # сколько строк изменено в каждом файле
git diff            # сами изменения построчно (q — выйти из просмотра)
npm run build       # собирается ли проект
npm run dev         # работает ли приложение в браузере
Терминал — агар натиҷа мувофиқ наомад
git restore .       # вернуть изменённые файлы к последнему коммиту
git clean -n        # показать, какие НОВЫЕ файлы Git удалил бы (только показать!)
git clean -fd       # удалить новые файлы — только если список выше вас устроил

Ба чӣ диққат додан лозим

  • ☐ Оё файлҳои дуруст дастхӯрда шудаанд. Дар бораи src/ хоҳиш кардед — аммо дар diff package.json ё index.html пайдо шуд? Бипурсед, барои чӣ.
  • ☐ Вобастагиҳои нав. Сатр дар dependencies — сабаби истодан ва санҷидани баста дар npmjs.com аст.
  • ☐ Коди хориҷшуда. Сатрҳои сурхро (-) ҳамон қадар бодиққат хонед, ки сабзҳоро: оё санҷиши хато ё бекор кардани дархост гум нашудааст.
  • ☐ Сирҳо. Дар diff калидҳо, паролҳо, мазмуни .env набояд бошанд.
  • ☐ Партов. console.log-ҳои монда, коди шарҳшуда, файлҳои зиёдатӣ.
  • ☐ Diff-и аз ҳад калон. Агар тағйирот садҳо сатр дар даҳҳо файл бошад — вазифа хеле васеъ гузошта шудааст. Бозгашт кунед ва ба қадамҳо тақсим намоед.
  • ☐ Шумо ҳар сатрро фаҳмонда метавонед. Агар не — хоҳиш кунед, ки фаҳмонад, баъд бо суханони худ бознависед. Ин қоидаи курс аст.
  • ☐ Мисли пештара кор мекунад. Агент мегӯяд «тайёр» — ин далел нест. Далел — иҷрои шумост.
Агент фаҳмишро иваз намекунад

Claude Code корҳои оддиро тезонад — масалан, гузаронидани 5 файл ба папкаҳо. Аммо интихоби сохтори лоиҳа, пай бурдани коркарди хатои гумшуда ва ҷавобгар будан барои натиҷа — кори шумост. Дар санҷишҳо ЗС хомӯш аст: фаҳмише, ки худатон ба даст наовардаед, дар он ҷо кумак намекунад.

Муфассалтар хонед: Ҳуҷҷатҳои Claude Code · Git — git diff

Амал: мустаҳкам мекунем

ВАЗИФАИ 7.1

Ревюи diff

миёна

Функсияи reviewDiff(lines)-ро нависед, ки diff-ро аз назар мегузаронад ва огоҳиҳо чоп мекунад. Сатрҳои бо + — иловашуда, бо - — хориҷшуда, боқиро намегирем. Рақами сатр — рақами он дар массив, аз 1 оғоз мешавад. Қоидаҳо (бо тартиб санҷида мешаванд, барои як сатр на зиёда аз як огоҳӣ):

  • сатри иловашуда бо console.log → строка N: оставлен console.log;
  • сатри иловашуда, ки дар он API_KEY = (ё password =) ҳаст, → строка N: похоже на секрет;
  • сатри иловашуда бо намуди "ном": "^рақам…" (сабти вобастагӣ) → строка N: новая зависимость;
  • сатри хориҷшуда бо export → строка N: удалён export.

Агар чизе ёфт нашавад — Замечаний нет-ро чоп кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const diff = [
  "diff --git a/src/api/products.js b/src/api/products.js",
  "@@ -1,5 +1,8 @@",
  '+const API_KEY = "sk-12345";',
  " export async function searchProducts(query) {",
  "-  const response = await fetch(url);",
  '+  const response = await fetch(url + "?key=" + API_KEY);',
  "+  console.log(response);",
  "diff --git a/package.json b/package.json",
  '+    "lodash": "^4.17.21"',
  "-export function debounce(fn, delay) {",
];

function reviewDiff(lines) {
  // ...
}

reviewDiff(diff);
Натиҷаи интизоршаванда
строка 3: похоже на секрет
строка 7: оставлен console.log
строка 9: новая зависимость
строка 10: удалён export
Ишора 1

Бо давраи for (let i = 0; i < lines.length; i++) гузаред. Ҳарфи аввали сатр: line[0] — ин "+" ё "-" аст. Сатрҳои diff --git ва @@ бо аломатҳои дигар оғоз мешаванд.

Ишора 2

Барои сатри иловашуда line.includes("console.log"), /(API_KEY|password) =/.test(line) ва /"[^"]+": "\^\d/.test(line)-ро истифода баред. Барои хориҷшуда — line.includes("export"). Рақам: i + 1. Ҳисобкунаки огоҳиҳои ёфтшуда лозим аст, то дар охир «Замечаний нет»-ро чоп кунед.

08 Вазифаи хонагӣ

Барномаи дарси 16-и худро ба Vite гузаронед, кодро ба модулҳо тақсим кунед ва натиҷаро ба репозиторий дар GitHub бор намоед.

Чӣ кор кардан лозим

  • ☐ Лоиҳаро бо фармони npm create vite@latest (қолаби vanilla) эҷод кунед, нишонагузорӣ, услубҳо ва коди барномаро гузаронед. Ҳар чизи зиёдатиро аз қолаб хориҷ кунед (counter.js, расмҳо).
  • ☐ JS-ро ҳадди аққал ба се модул дар папкаҳои api, ui, utils (ё сохтори мантиқии худатон) тақсим кунед; main.js танҳо пайваст ва банд мекунад.
  • ☐ import/export-ро бо роҳҳои намуди ./…js истифода баред. Файли витринагии index.js ё import … as-ро истифода баред, агар асоснок бошад (ихтиёрӣ).
  • ☐ Барнома мисли дарси 16 кор мекунад: ҳолатҳои боркунӣ, натиҷаи холӣ ва хато, debounce, ҷустуҷӯ.
  • ☐ Дар package.json скриптҳои dev, build, preview ҳастанд; npm run build бе хато мегузарад.
  • ☐ Дар репозиторий node_modules ва dist нестанд (.gitignore-ро санҷед), вале package-lock.json ҳаст.
  • ☐ На камтар аз 3 commit-и бомаъно (init vite project, move app to vite, split code into modules — аз рӯи таърихи шумо).
  • ☐ Дар README.md: ин кадом барнома аст, чӣ тавр оғоз кардан (npm install, npm run dev), сохтори папкаҳо ва 2–3 ҷумла бо суханони худатон: кадом модул чӣ экспорт мекунад ва кӣ онро import мекунад.
  • ☐ Агар ЗС истифода кардед — дар README қайд кунед, ки дар кадом қадам ва чӣ пас аз санҷиш ислоҳ карда шуд.

Чӣ супоридан лозим

Истиноди репозиторийро ба чати гурӯҳ (Telegram) фиристед. Дар паём нависед: ин кадом барнома аст, аз чанд модул иборат аст ва кадом хато ҳангоми гузариш аз ҳама ғайримунтазир буд.

Вазифаи хонагӣ чӣ тавр баҳо дода мешавад (0–10)

Чиро месанҷемХолҳо
Лоиҳа дар Vite, npm install ва npm run dev барномаро оғоз мекунанд, npm run build мегузарад2
На камтар аз 3 модул бо нақшҳои фаҳмо, main.js бе мантиқи «зиёдатӣ», роҳҳо ва экспортҳо дурустанд3
Барнома мисли дарси 16 кор мекунад (ҳолатҳо, debounce, ҷустуҷӯ)2
.gitignore бе node_modules ва dist, на камтар аз 3 commit-и бомаъно1
README: оғоз, сохтор, шарҳи экспортҳо бо суханони худатон2

✓ Варақаи кӯмакии дарс

  • Модул — файл бо соҳаи намоии худ. Ба берун танҳо он чиз мебарояд, ки бо export қайд шудааст.
  • Экспорти номдор: export function f() {} → import { f } from "./a.js". Номҳо мувофиқ мешаванд; тағйири ном: { f as g }; ҳамаро якбора: import * as a.
  • Пешфарз: export default … → import ҳарНом from "./a.js" (бе қавс). Дар модул он яктост.
  • Витрина: export { f } from "./a.js", export * from "./b.js" дар index.js — як тиреза барои папка.
  • Роҳҳо: ./ — ҳамсоя, ../ — боло, ном бе нуқта — баста аз npm. Васеъкунии .js-ро менависем, хати моил ҳамеша рост аст, ҳарфи калон ва хурд муҳим аст.
  • Модул як бор иҷро мешавад, барои ҳамаи import-кунандаҳо ҳолати умумӣ аст. Аз import-ҳои давриҳо худдорӣ мекунем.
  • Сохтор: src/api, src/ui, src/utils, src/main.js. Як модул — як вазифа, main.js — роҳбари оркестр.
  • package.json: scripts, dependencies (ба коди барнома лозиманд), devDependencies (абзорҳо). node_modules-ро ба Git намегузорем, package-lock.json-ро — мегузорем.
  • semver: MAJOR.MINOR.PATCH. ^1.4.2 — то 2.0.0, ~1.4.2 — то 1.5.0. Рақамҳоро ҳамчун рақам муқоиса мекунем.
  • Фармонҳо: npm install, npm install -D ном, npm run dev | build | preview.
  • Vite: npm create vite@latest → cd → npm install → npm run dev. Dev-сервер — барои кор (HMR), build — сайти тайёр дар dist/, preview — дидани ҷамъбаст.
  • Тағйирёбандаҳои .env: ба браузер танҳо VITE_… меафтанд ва онҳоро ҳар кас мебинад — сирр дар он ҷо нест.
  • ЗС ва Claude Code: вазифаи дақиқ аз рӯи формула, «аввал нақша», иҷозатҳоро мехонем, натиҷаро тавассути git diff ва иҷро месанҷем; бастаҳоро дар npmjs.com месанҷем.