Пытаюсь разобраться с динамическими импортами webpack. Как это вижу я.
Допустим у меня есть роут, который в зависимости от хеша должен подключать тот или иной модуль:
changeRout(rout) {
const comp = this.routes[rout] || 'error';
import(`../components/${comp}`)
.then(({default: comp}) => {comp.render()})
.catch(err => console.log(err));
}
Для этого, как пишут гуру в своих статьях я установил
'dynamic-import-webpack'
'@babel/plugin-syntax-dynamic-import'
Хз какой именно нужен, но в доках вебпака приводят @babel/plugin-syntax-dynamic-import, в какой - то статье вычитал про dynamic-import-webpack. В общем оставил оба. Правило для обработки js файлов в конфиге выглядит так:
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', {modules: false}]],
plugins: ['@babel/plugin-syntax-dynamic-import', 'dynamic-import-webpack']
}
}
}
Так же выставил
optimization: {
splitChunks: {
chunks: 'all'
}
Все бы вроде хорошо, однако вебпак генерирует один общий файл с модулями и подключает его сразу на страницу, а хотелось бы что-бы чанки модулей были отдельны и подключались только при переходе по определенному роуту.
В итоге получаю 3 файла
vendors~main.js - здесь как я понял лежат функции всяких пагов стайл лоадеров и т.д.
0.js - здесь код всех модулей (а хотелось бы для каждого свой чанк)
main.js - ну и главный файл (точка входа)
Сам webpack понимает синтаксис динамическогого import() и ему не нужны дополнительные инструменты/трансформеры.
Все динамическая загрузка модулей в webpack доступа из коробки.
Насчет babel и плагинов, указанных в вопросе. Зачем они вообще нужны, когда сам webpack умеет делать динамический импорт?
Они необходимы для самого babel, чтобы тот не ругался на конструкции вида import и не выдавал ошибку:
SyntaxError: <filePath>:
Support for the experimental syntax 'dynamicImport' isn't currently enabled
Плагин всего лишь пометит, что конструкции import() валидны в данном контексте и работу можно продолжать дальше.
В этом можно убедиться на примере: на такой код babel будет ругаться, но если подключить @babel/plugin-syntax-dynamic-import, то все будет в порядке, причем исходный код и результирующий будут одинаковые, т.к. плагин всего лишь выставляет внутренний флаг babel, ничего не преобразуя: исходный код плагина.
@babel/plugin-syntax-dynamic-import. С ним уже должно быть понятно, еще замечу, что он упомянут в официальной документации webpack при описании кейса с async/await, которые предлагается трансформировать при помощи babel, и чтобы babel отработал корректно просят еще подключить этот плагин. Т.е. документация не говорит использовать его явно, только при необходимости.dynamic-import-webpack. Этот плагин нужен для преобразования import() в старый вебпаковский динамический импорт вида require.ensure. Уже webpack официально поддерживается import(), поэтому смысл в этом плагине на текущий момент уже нет.
К тому же данный вид не поддерживает динамическое значение import(): имя модуля должно быть явно захардкорено, т.е. нельзя писать
// ...
import(`./my-module${index}`)
// ...
необходимо вручную описать все модули
// ...
import('./my-module1')
// ...
import('./my-module2')
// ...
import('./my-module3')
// ...
А иначе, webpack возьмет и все модули с префиксом my-module поместит в один чанк.
Исходя из этого:
Если вы используете babel, вам нужно еще подключить плагин @babel/plugin-syntax-dynamic-import;
Если вы не используете babel, то вам не нужны никакие плагины.
Конкретно в вашем случае проблема возникает из-за плагина dynamic-import-webpack, если вы его удалите, все должно быть хорошо.
Также, я сделал два примера: в одном используется только webpack, в другом webpack плюс babel. Пример необходимо запустить командой
npm start
После открытия страницы нажмите на любую кнопку, и вы увидите, что скрипты загружаются динамически (вкладка network и консоль)
Пример 1
Пример 2 (с babel)
Из вопроса непонятно какой версией webpack вы пользуетесь, скорее всего последней (на текущий момент это 4).
Обновлено
Если у вас webpack версии >=4.29.0 и вы получаете ошибку вида:
Module parse failed: 'import' and 'export' may only appear at the top level
You may need an appropriate loader to handle this file type.
То скорее всего воспроизводится этот баг: https://github.com/webpack/webpack/issues/8656
Есть пара воркэраундов:
4.28.4acorn, из-за которых появляется проблема.resolutions для package.json:
"resolutions": {
"webpack/acorn": "6.1.1"
}
2) Установить к себе пакет acorn версией 6.1.1:
npm i --save-dev acorn@^6.1.1
3) Запустить npm dedupeПродвижение своими сайтами как стратегия роста и независимости