Skip to content

Fix modules (01-13, 3 in 1) #728

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions 1-js/13-modules/01-modules-intro/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ sayHi('Іван'); // Привіт, Іван!

Запустимо приклад у браузері.

Оскільки модулі підтримують ряд спеціальних ключових слів, таким чином вони мають ряд особливостей. Необхідно явно сказати браузеру, що скрипт є модулем, з допомогою атрибута `<script type="module">`.
Оскільки модулі підтримують ряд спеціальних ключових слів та інших особливостей, ми повинні явно сказати браузеру, що його слід сприймати як модуль. Для цього є атрибут `<script type="module">`.

Ось так:

Expand Down Expand Up @@ -90,7 +90,7 @@ sayHi('Іван'); // Привіт, Іван!
- `user.js` повинен експортувати змінну `user`.
- `hello.js` повинен імпортувати змінну з `user.js` модуля.

Іншими словами, використовуючи модулі ми користуємось import/export замість використання глобальних змінних.
Іншими словами, використовуючи модулі ми користуємось `import`/`export` замість використання глобальних змінних.

Правильний варіант:

Expand Down Expand Up @@ -304,9 +304,9 @@ sayHi(); // Ready to serve, *!*Pete*/!*!

### Атрибут async працює у вбудованих скриптах

Для немодульних скриптів атрибут `async` працює лише на зовнішніх скриптах. Скрипти з ним запускаються відразу по готовності, вони не чекають на інші скрипти або HTML-документ.
Для немодульних скриптів *атрибут* `async` (не плутати з ключовим словом `async`) працює лише з зовнішніми скриптами (підключеними через `src`). Скрипти з `async` запускаються відразу по готовності, вони не чекають на інші скрипти або HTML-документ.

`Async` також працює у вбудованих сценаріях для модулів.
А от для модульних скриптів *атрибут* `async` працює і для зовнішніх скриптів, і для вбудованих (прописаних всередині тега `<script>тут код</script>`).

Наприклад, у скрипті нижче є `async`, тому він виконається одразу після завантаження, не чекаючи інших скриптів.

Expand Down
34 changes: 17 additions & 17 deletions 1-js/13-modules/02-import-export/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
```

````smart header="Не потрібно ставити крапку з комою після експорту класу чи функції"
Зверніть увагу, `export` перед класом чи функцією не перетворює її в [функціональний вираз](info:function-expressions). Це все ще оголошення функції, хоч і експортованої.
Зверніть увагу, `export` перед класом чи функцією не робить її [функціональним виразом](info:function-expressions). Це все ще оголошення функції (function declaration), хоч і екпортовуваної.

Більшість стилів JavaScript коду не рекомендують ставити крапку з комою після оголошення функції та класу.

Expand Down Expand Up @@ -99,7 +99,7 @@ say.sayBye('Іван');
```smart header="Не бійтеся імпортувати занадто багато"
Сучасні інструменти збірки, такі як [webpack](https://webpack.js.org/) та інші, об’єднують модулі разом і оптимізують їх для прискорення завантаження. Вони також видаляють імпорти, що не використовуються.

Наприклад, якщо ви `import * as library` з величезної бібліотеки коду, а потім використаєте лише кілька методів, тоді невикористані методи [не будуть включені](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) у оптимізований бандл.
Наприклад, якщо ви зробите `import * as library` з величезної бібліотеки коду, а потім використаєте лише кілька методів, тоді невикористані методи [не будуть включені](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) у оптимізований бандл.
```

## Імпорт "as"
Expand Down Expand Up @@ -142,12 +142,12 @@ say.*!*bye*/!*('Іван'); // Бувай, Іван!

## Типовий експорт

На практиці існує два головних типи модулів.
На практиці існує два основних види модулів.

1. Модулі, що містять бібліотеку -- набір функцій, як `say.js` вище.
1. Модулі, що містять бібліотеку (набір функцій), як `say.js` вище.
2. Модулі, що визначають єдину сутність, тобто модуль `user.js` експортує тільки `class User`.

Переважно, надавати перевагу потрібно другому підходу, таким чином усі "сутності" знаходяться у власних модулях.
Загалом другий спосіб більш бажаний, бо так усі "сутності" знаходяться у власних модулях.

Очевидно, що це вимагає великої кількості файлів, щоб усе мало власні модулі, але це зовсім не проблема. Насправді, навігація в коді полегшується, якщо всі файли мають вдалу назву та структуровані в теках.

Expand Down Expand Up @@ -210,7 +210,7 @@ export default ['Jan', 'Feb', 'Mar','Apr', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
Такий експорт без `default` згенерує помилку:

```js
export class { // Помилка! (типовий експорт потребує імені)
export class { // Помилка! (нетиповий експорт потребує імені)
constructor() {}
}
```
Expand Down Expand Up @@ -254,7 +254,7 @@ import {*!*default as User*/!*, sayHi} from './user.js';
new User('Іван');
```

Урешті-решт, якщо імпортувати всі `*` як об'єкт, тоді властивість `default` матиме значення типового імпорту:
І наостанок, якщо імпортувати всі сутності `*` як об'єкт, тоді значення типового імпорту буде знаходитись у властивості `default`:

```js
// 📁 main.js
Expand All @@ -275,12 +275,12 @@ import {User} from './user.js';
// import {MyUser} не спрацює, оскільки ім’я повинно бути {User}
```

...В той час, як для типового імпорту нам завжди потрібно обрати ім’я:
...В той час, як для типового імпорту нам завжди потрібно обрати ім’я самим:

```js
import User from './user.js'; // спрацює
import MyUser from './user.js'; // спрацює теж
// можна навіть import Anything... і це все одно ще спрацює
// можна навіть import Anything... і це все одно спрацює
```

Таким чином різні члени команд можуть використовувати різні імена для імпорту однакових сутностей і це не дуже добре.
Expand Down Expand Up @@ -310,7 +310,7 @@ export {default as User} from './user.js'; // реекспорт default

Навіщо нам це може знадобитися? Розглянемо практичний спосіб використання.

Уявімо, що нам потрібно написати "пакунок": директорію з багатьма модулями, що експортує певний функціонал (інструменти як NPM дозволяють публікувати та розповсюджувати такі пакунки, але ми не зобов’язані їх використовувати). Багато таких пакунків використовуються в ролі допоміжних, для внутрішнього використання всередині інших модулів.
Уявімо, що нам потрібно написати "пакет" (package): директорію з багатьма модулями, що експортує певний функціонал (інструменти як NPM дозволяють публікувати та розповсюджувати такі пакети, але ми не зобов’язані їх використовувати). Багато таких пакетів використовуються в ролі допоміжних, для внутрішнього використання всередині інших модулів.

Файлова структура може мати такий вигляд:
```
Expand All @@ -326,21 +326,21 @@ auth/
...
```

Для доступу до функціоналу пакунку ззовні ми б хотіли створити єдину точку входу.
Для доступу до функціоналу пакета ззовні ми б хотіли створити єдину точку входу.

Інакше кажучи, користувачі для використання функціоналу нашого пакунку повинні імпортувати тільки "головний файл" `auth/index.js`.
Інакше кажучи, користувачі для використання функціоналу нашого пакета повинні імпортувати тільки "головний файл" `auth/index.js`.

Наприклад:

```js
import {login, logout} from 'auth/index.js'
```

"Головний файл" `auth/index.js` експортує весь функціонал, що ми б хотіли надати з цим пакунком.
"Головний файл" `auth/index.js` експортує весь функціонал, що ми б хотіли надати з цим пакетом.

Ідея полягає в тому, щоб інші програмісти, хто буде використовувати наш пакунок, не матимуть змогу втрутитися у внутрішню структуру. Ми експортуємо тільки те, що необхідно з `auth/index.js` та тримаємо решту прихованим від допитливих очей.
Ідея полягає в тому, щоб інші програмісти, які будуть використовувати наш пакет, не мали змоги втрутитися у внутрішню структуру. Ми експортуємо тільки те, що необхідно з `auth/index.js` та тримаємо решту прихованим від допитливих очей.

Оскільки, функціональність, до якої ми хочемо надати доступ, може знаходитися в різних частинах пакунку, ми можемо імпортувати її та повторно експортувати в `auth/index.js`:
Оскільки, функціональність, до якої ми хочемо надати доступ, може знаходитися в різних частинах пакета, ми можемо імпортувати її та повторно експортувати в `auth/index.js`:

```js
// 📁 auth/index.js
Expand All @@ -355,7 +355,7 @@ export {User};
...
```

Тепер користувачі нашого пакунку зможуть виконати `import {login} from "auth/index.js"`.
Тепер користувачі нашого пакета зможуть виконати `import {login} from "auth/index.js"`.

Синтаксис `export ... from ...` - просто скорочений запис для імпорту-експорту:

Expand All @@ -373,7 +373,7 @@ export {default as User} from './user.js';

### Реекспорт типового експорту

Для реекспорту типового експорту потрібна спеціальна обробка.
Для реекспорту типового експорту потрібна окрема обробка.

Скажімо, у нас є `user.js` з якого ми хочемо реекспортувати клас `User`:

Expand Down
2 changes: 1 addition & 1 deletion 1-js/13-modules/03-modules-dynamic-imports/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

По-перше, ми не можемо динамічно задавати ніякі з параметрів `import`.

Шлях до модуля має бути строковим примітивом і не може бути викликом функції. Ось так працювати не буде:
Шлях до модуля має бути рядком і не може бути викликом функції. Ось так працювати не буде:

```js
import ... from *!*getModuleName()*/!*; // Помилка, має бути рядок
Expand Down