Я часто расстраиваюсь при отладке проблем с конфигурацией. Это приводит к тому, что я совершаю глупые ошибки, бессистемно меняя параметры конфигурации в надежде, что одна из них сработает. Я решил разорвать круговорот и попытаться понять, что происходит. В этой статье я буду называть webpack-dev-server WDS.

Во-первых, следует помнить о трех важных вещах:

  1. WDS не автоматически перестраивается при изменении файлов конфигурации. Итак, если вы что-то меняете, и кажется, что ничего не меняется, это наблюдение верно
  2. WDS не просто компилирует ваш пакет, а затем обслуживает его из файлов. Скорее, он хранит ваш пакет в памяти. Это означает, что если вы пытаетесь выяснить, куда направляются ваши скомпилированные файлы, вы не увидите их в каталоге. Чтобы узнать, куда они направляются, перейдите на localhost:8080/webpack-dev-server
  3. Ничего не изменилось, хотя вы можете загрузить свой сайт и компиляция прошла успешно? Есть большая вероятность, что вы действительно обслуживаете файлы пакетов, созданные не в WDS. Если вы отлаживаете конфигурацию WDS, удалите файлы встроенного веб-пакета. Таким образом, если ваша конфигурация WDS испорчена, вы не получите никаких ложных срабатываний. Загвоздка в том, что после правильной настройки WDS вам необходимо убедиться, что ваши созданные файлы попадают в нужное место.

Документы слишком расплывчаты? Прочтите код.

Когда меня постоянно расстраивает что-то подобное, я пытаюсь заставить себя понять это на более глубоком уровне. Итак, к первоисточнику.

Больше всего меня сбивает с толку вопрос о том, где, по мнению WDS, находится ваш файл (поскольку вы не можете просто посмотреть каталог), и чем это отличается от обычной сборки.

WDS предоставляет вам эту странную страницу, которая эффективно показывает вам список каталогов ваших созданных файлов.

Похоже, что бизнес этого маршрута - writeDirectory функция, которая принимает baseUrl и basePath. Внизу мы видим, что writeDirectory вызывается с publicPath и outputPath соответственно. Эта функция получает список файлов в basePath и выполняет итерацию по ним, рекурсивно вызывая себя, если один из этих файлов на самом деле является другим каталогом.

Этот фрагмент кода показывает, как на самом деле работают пути WDS, в частности отношения между outputPath и publicPath. Во-первых, некоторые важные части моей конфигурации:

output: {
  path: path.resolve(__dirname, 'dist'),
  publicPath: 'dist'
},
plugins: [
   new HtmlWebpackPlugin({
   template: 'public/indexTemplate.html',
   filename: 'dist/index.html'
   favicon: 'favicon.ico'
 })
],
devServer: {
  historyApiFallback: {
    index:'index.html',
    rewrites: [
      { from: /list\/*/, to: 'index.html' }
    ]
  },
  https: false,
  publicPath: '/dist/'
}

Очевидно, что эта конфигурация немного запуталась, но я пришел сюда из более разумной рабочей конфигурации. Как видите, я использую html-webpack-plugin, и именно с этого началась вся эта путаница, потому что это означало, что мне нужно было получить индекс из dist вместо public.

Давайте еще раз посмотрим на отображаемую страницу:

Эта первая ссылка, мой пакет, на самом деле указывает на

http://localhost:8080/dist/da2c93b562075b4cbd7a.js

Как dist туда попал? Что ж..

res.write('<li><a href="');
res.write(baseUrl + item);
res.write('">');
res.write(item);
res.write('</a></li>');

baseUrl (помните, это publicPath) добавляется к URL-адресу, но не к тексту. Если я щелкну по этой ссылке, пакет действительно есть. В этом есть смысл, хотя, если publicPath был '/' вместо /dist/, это означает, что пакет будет построен для dist/bundle.js, но доступен в WDS в localhost:8080/bundle.js.

Исправляем конфиг

Худшая часть этой конфигурации - это то, что я использовал filename: 'dist/index.html для html-webpack-plugin конфигурации. Это означает, что файл действительно доступен по адресу localhost:8080/dist/dist/index.html. Это может быть особенно запутанным, если вы экспериментируете с конфигурацией, так как в случае publicPath: '/' у вас будет index.html, доступный по адресу localhost:8080/dist/index.html, что почти логично.

Итак, мы удаляем dist из html-webpack-plugin filename, потому что outputPath уже помещает его в dist/.

С этим изменением я теперь могу получить доступ к своему встроенному index.html по адресу localhost:8080/dist/index.html, что по-прежнему не то, что я хочу, я действительно хочу, чтобы он был по адресу /. Но если мы вспомним ту строку, в которой создается ссылка, res.write(baseUrl + item), зная, что baseUrl на самом деле publicPath, это может произойти только тогда, когда WDS publicPath будет /.

Успех! Или вроде того. Теперь я получаю index.html, просто перейдя к localhost:8080/ (который запросит index.html, потому что index обладает магическими свойствами). Тем не мение..

html-webpack-plugin генерирует URL-адрес для пакета, но включает dist в URL-адрес. Почему?

Оказывается, я изменил только publicPath в WDS. В обоих случаях должно быть /. Избавьтесь от проблем и не устанавливайте publicPath в конфигурации WDS.

СПА беды

Хорошо, теперь мы вернулись к проблеме, которая заставила меня изменить все в первую очередь. Когда я перехожу на другую страницу и обновляюсь, я получаю 404 из-за того, что это одностраничное приложение (SPA). Я установил правила перенаправления, но оказалось, что они не работают.

historyApiFallback: {
  index:'index.html',
  rewrites: [
    { from: /list\/*/, to: 'index.html' }
  ]
}

При запуске WDS он информирует нас о следующем:

Итак, если вывод поступает из / и 404 возвращается к index.html, тогда, когда я 404 на localhost:8080/list/1/1, это должно быть переписано в localhost:8080/index.html, который действительно загружает страницу. Итак, здесь происходит что-то, что не очевидно из предоставленной информации.

index: 'index.html'

Что в этом плохого? Это относительный путь. Относительно любого URL-адреса, по которому вы сейчас находитесь. Итак, когда появляется 404 для localhost:8080/list/1/1, мы фактически загружаем localhost:8080/list/1/index.html. Для меня это действительно было неочевидно. Худшая часть? Если вы посмотрите на запрос на вкладке своей сети, вы не увидите эту попытку перенаправления запроса.

Последняя ошибка

Теперь, когда publicPath равно /, html-webpack-plugin сгенерирует это в вашем index.html:

<script type="text/javascript" src="/3bf45b6412afeda22cbc.js"></script></body>

Ваш пакет построен для dist из-за outputPath, html-webpack-plugin сообщает браузеру искать его по адресу / из-за publicPath. Как с этим справиться? Либо запустите свой сервер с dist (кажется, имеет смысл), либо используйте другой publicPath в конфигурации вашего prod webpack. Вам решать.

Это как раз то, что я могу себе представить на данный момент. Если вы найдете что-нибудь, что можно улучшить, я был бы более чем счастлив услышать это.

Наконец, если вам нужен разработчик-фрилансер, я ищу работу. Я специализируюсь на современной веб-разработке с использованием новейших технологий. Я также освежаю свои навыки полного стека и пытаюсь помочь скалолазам подключиться к моему веб-приложению Letclimbstuff.com. Вы можете связаться со мной по адресу [email protected] или на Codementor.