Tag: Webpack

Babel to EsBuild migration for Webpack

Recently I had some time to take a look at the performance of my pet project. One thing bothered me: the project is relatively small, but the bundle size was too big: 780 KiB. Whereas the project had only a few dependencies: react (~10 KiB), react-router (~70 KiB), react-dom (~90 KiB), dayjs (~3 KiB), lodash (~70 KiB). The bundle should not be that big for so few dependencies.

So I ran webpack-dev-analyzer and found a weird thing: the sum of the libs is 3 times smaller than the final bundle size. Then I decided to take a look at @statoscope/webpack-plugin. It was a good tool but it gave me the same result. The bundle has way too much trash.

Ok. Probably it’s just webpack wrappers over 300+ small modules.

Read more

How to migrate Javascript webpack configuration to Typescript

It turned out that the newest versions (at least 5+) of webpack support Typescript out of the box. So the algorithm is next:

  • Create tsconfig.json at the root level. Content:
    {
      "compilerOptions": {
        "module": "CommonJS",
        "target": "ES5",
        "esModuleInterop": true,
        "checkJs": false,
        "strict": true,
      }
    }
    
  • Rename all *.js files to *.ts
  • Type all of them:
    • no more ugly require, use import.
    • webpack package has typings out of the box.
      • You may find these types useful: ConfigurationRuleSetRule
      • To enable devServer write this: 
        interface Configuration extends WebpackConfiguration {
          devServer?: WebpackDevServerConfiguration;
        }
        
    • Some of the popular plugins have types too.
    • Some of them don’t have types at all:
      • Create a *.d.ts file
      • Put there something like this:
        declare module 'postcss-assets' {
          export default function postcssAssets(opts: {
            basePath: string;
            relative: boolean;
          }): unknown;
        }
        
  • Make sure your webpack.config.ts file is placed at the root level. I mean exactly at the same spot where node_modules is. Otherwise, you won’t be able to build it. No compilerOptions helped me. 
  • Run webpack. It should work.

Webpack и SCSS импорты в купе с module-resolver

С приходоим ES7 в JS пришли import-ы и export-ы. Жить стало веселее, и… сложнее. Появилось много заморочек и вообще новых проблем. Одна из таких проблем выглядит так: import some from …/…/…/…/…/some. Знакомая ситуация?

Обычно её в случае webpack-а решают при помощи модуля module-resolver. Он позволяет в .babelrc (или где вы держите конфигурацию) указывать регулярные выражения для автозамены, а также добавляет поддержку root-записей. Скажем с ним можно указать import actions from ‘@actions/header`’, где @actions`` будет алиасом к какому-нибудь пути в вашем проекте. 

Дальше встаёт вопрос инструментов. А как на это должен реагировать редактор? Как он узнает, что теперь пути в import-ах устроены хитрее. Что делать с линтингом? К счастью, для eslint есть такой плагин:  eslint-plugin-import. С редакторами ситуация может быть сложнее.

Хорошо, а что делать с SCSS\Sass? Нормальных рабочих решений с наскоку мне найти не удалось. Но как оказалось, всё можно решить относительно просто. В настройках webpack для sass-loader-а можно указать настройки. Они будут переданы как есть в пакет node-sass. А вот он, оказывается, достаточно гибкий. Если там указать метод importer, то можно навязать свою логику обработки @import-ов. Пример:

{
	loader: 'sass-loader',
	options:
	{
		sourceMap: true,
		url: false,
		importer: url => (
		{
			file: url
				.replace(...)
				.replace(...)
				.replace(...),
		}),
	},
}

Либо даже выцепить ваши настройки прямо из настроек в .babelrc.

Embedded webpack application

Возникла необходимость внедрять готовый SPA в другой проект на страницу. Проект сразу писался под это дело, но всё равно возник ряд проблем, которые нужно было решать. Напишу про 2 из них сюда как шпаргалку.

webpack & dynamic import

Что если ваш проект использует динамический импорт? Например System.import. В этом случае webpack сделает для подгружаемых файлов отдельный chunk. И грузить он его будет исходя из publicPath в настройках webpack. Но ведь embedded решения могут быть внедрены по любому пути. Как быть? Всё просто, пишем в точке входа что-нибудь типа: __webpack_public_path__ = window.myPredefinedPath и дело в шляпе. Магия. До загрузки приложения нужно определить этот window.myPredefinedPath, webpack его увидит и будет использовать. Сразу отмечу, что надо писать как есть, не window.__webpack…=, а как-будто эта переменная уже определена в коде. Если на неё ругается eslint не беда, пишем: // eslint-disable-line и он более не ругается.

webpack css & url

Возникла проблема с тем, что в стилях указаны пути к шрифтам так, что webpack их найти не может (отдельная тема почему так). Да и не должен, него его это забота. Однако он пытается от-revolve-ить все пути, что находит в css. Лечится установкой url: false в cssLoader-е. После этой настройки пути отдаются как есть без каких-либо проверок.

Что не так с Webpack server-ом и React Hot Loader-ом

Как минимум:

  • Актуальная версия RHL в какой-то глубокой бете. Некоторые инструменты, такие как onsen monaca, в итоге, прибиты ногами к конкретной версии (иначе оно попросту не работает). Даже готовые пресеты для webpack-а завязаны на конкретные версии. Обратной совместимостью там и не пахнет. Даже сообщений внятных о том, что изменилось в stack trace-ах не ждите. 
  • Webpack server довольно хитро устроен внутри, поэтому такую связку очень сложно дебажить. Попробуйте ради интереса убрать [HMR] и [WDS] сообщения. В настройках плагинов такой опции нет. Попытка вырезать их из кода руками заставит вас детально разобраться в работе этого сервера. Ну или забить. Я забил :)
  • Если ошибка произошла до первого успешного render-а, то stack trace показывает погоду на Марсе. Настоящая ошибка теряется в дебрях обёрток для ошибок.
  • Если в Chrome Developer Tools для webpack’s sourceMap-ов есть какая-то кривоватая, но поддержка, то в Firefox инструментах там просто хаос. Про stack trace-ы вообще молчу. Там просто ссылка строку в bundle.js
  • React Hot Loader по понятным причинам не перегружает обновления методов, которые были за-bind-ны в contructor-е компонента сами на себя. В итоге приходится перегружаться почти по любому поводу.
  • Любые не тривиальные случаи приводят к необходимости обновить страницу. </ul>Сложилось стойкое впечатление, что 3-ая версия React Hot Loader-а всё ещё слишком сырая, чтобы ей можно было пользоваться за пределами задач вёрстки. Но я бы не стал даже в их пределах. Этот инструмент оборачивает всё своими proxy-методами, чем сильно портит жизнь.

Поддержка sourceMap-ов тоже пока оставляет желать лучшего. Слишком часто при debug-инге проваливаешься невесть куда, не можешь поставить breakpoint, а то и вовсе наблюдаешь какие-то аномалии. Поддержка stacktrace-ов тоже пока далека от идеала. 

Всё больше склоняюсь к разработке с ссылками на настоящие ресурсы, благо поддержка es6 в браузерах очень радует. Но вот JSX, я полагаю, нам в нативном виде в них не видать никогда. Так что вопрос, “а может к чёрту его этот JSX?” для меня лично достаточно актуален :)