Асихнронное разделение кода

Дата обновления перевода 2021-08-10

Асихнронное разделение кода

Когда вам требуется/вы импортируете JavaScript или CSS-модуль, Webpack компилирует этот код в финвальный файл JavaScript или CSS. Обычно, это именно то место, где вам нужно. Но что, если вам нужно использовать только часть кода при определенных условиях? Например, если вы хотите использовать video.js для проигрывания видео, но только когда пользователь нажал на ссылку:

1
2
3
4
5
6
7
8
9
10
// assets/app.js

import $ from 'jquery';
// фиктивный "большой" модуль (например, внутренне импортирует video.js)
import VideoPlayer from './components/VideoPlayer';

$('.js-open-video').on('click', function() {
    // использовать больший модуль VideoPlayer
    const player = new VideoPlayer('some-element');
});

В этом примере, модуль VideoPlayer и все, что он импортирует, будет запаковано в финальный созданный файл JavaScript, даже если мало кому он реально понадобится. Лучшим решением будет использовать dynamic imports: загружать код через AJAX, когда он будет необходим:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// assets/app.js

import $ from 'jquery';

$('.js-open-video').on('click', function() {
    // здесь вы можете начать загружаемую анимацию

    // используйте import() как функцию - она вернет Promise
    import('./components/VideoPlayer').then(({ default: VideoPlayer }) => {
        // вы можете остановить загрузку анимации здесь

        // использовать больший модуль VideoPlayer
        const player = new VideoPlayer('some-element');

    }).catch(error => 'An error occurred while loading the component');
});

Используя import() в качестве функции, модуль будет загружен асинхронно, а обратный вызов .then() будет выполнен, когда загрузка будет завершена. Аргумент VideoPlayer к обратному вызову будет загруженым модулем. Другими словами, это работает как обычные вызовы AJAX! За кадром, Webpack запакует модуль VideoPlayer в отдельный файл (например, 0.js), чтобы его можно было скачать. Обо всех деталях позаботились за вас.

Часть { default: VideoPlayer } может выглядеть странно. При использовании асинхронного испорта, ваш обратный вызов .then() передается объекту, где настоящий модуль находится в ключе .default. Есть причины, по которым это так, но выглядит это странновато. Код { default: VideoPlayer } гарантирует, что модуль VideoPlayer, который мы хотим, считан из этого свойства .default.

Чтобы узнать больше деталей и опций конфигурации, см. dynamic imports в документации Webpack.