Личное резюме по опыту webpack5

Webpack

Представляем webpck5

С момента запуска webpack5 прошло больше года, а он все еще находится в стадии бета-версии, его можно установить и использовать уже сейчас.

Способ установки

```
npm install webpack@next webpack-cli -D
yarn add webpack@next webpack-cli -D
```

HTML-плагин, совместимый с HTML

  • нужно бытьhtml-webpack-pluginОбновление до версии 4.3.0

Требования к окружающей среде

  • Последняя официальная документация требует, чтобы узел был как минимум версии 10.13.0 или выше.

Внедрение новых функций

  • постоянный кеш
  • Оптимизация идентификаторов модулей и идентификаторов блоков
  • Умнее встряхивать деревья
  • Скрипт nodeJs polyfill удален
  • Поддержка генерации кода для e6/es2015
  • SplitChunk и размер модуля
  • Module Federation

Используйте опыт

  • После начала работы webpack 5 имеет очень хороший размер пакета, непрерывную скорость компиляции и совместим с webpack 4. Module Federation также предоставляет решение для использования микроинтерфейсных приложений в проектах. Если вы столкнулись с несовместимостью в процессе обновления, вы можете перейти кжурнал изменений webpack5Проверьте это.

постоянный кеш

  • До webpack5 можно было использоватьcache-loaderЗапишите скомпилированную структуру в кеш жесткого диска, вы также можете использоватьbabel-loader,настраиватьoption.cacheDirectoryБудуbabel-loaderРезультат компиляции записывается на диск.
  • В webpack5 кеш включен по умолчанию, а кеш по умолчанию находится в памяти. Кэш можно установить
module.export={
    cache{
       type:'filesystem',  //  'memory' | 'filesystem'
        cacheDirectory: 'node_modules/.cache/webpack', // 默认将缓存存储在 node_modules/.cache/webpack
        // 缓存依赖,当缓存依赖修改时,缓存失效
        buildDependencies:{
        	// 将你的配置添加依赖,更改配置时,使得缓存失效
        	config: [__filename]
    	} 
    }
}
  • По умолчанию webpack предполагает, что каталог node_modules, в котором он находится, изменяется только менеджером пакетов, пропускает хэширование и обработку временных меток и использует только имя и версию пакета из соображений производительности.

  • Когда cache.type: "filesystem" установлен, webpack внутренне включает кэширование файловой системы и кэширование памяти в иерархическом порядке. При чтении из кеша сначала проверяется кеш памяти, и если кеш памяти не найден, он понижается до кеша файловой системы. Кэш записи будет записывать как в кеш памяти, так и в кеш файловой системы.

  • Кэш файловой системы напрямую не сериализует запросы на запись на диск. Он будет ждать завершения процесса компиляции и бездействия компилятора перед выполнением. Причина этого в том, что сериализация и запись на диск требуют больших ресурсов, и мы не хотим дополнительно затягивать процесс компиляции.

  • Разработка стратегии устранения кеша: файловый кеш хранится в node_modules/.cache/webpack.Для набора кеша максимальное количество кэшированного содержимого не должно превышать 5, а максимальное накопленное использование ресурсов не должно превышать 500 МБ.При приближении или превышении порог 500 МБ, приоритет отдается удалению самого старого кэшированного содержимого. При этом эффективная продолжительность кэша также рассчитана на 2 недели.

Оптимизация идентификаторов модулей и идентификаторов блоков

чанк и модуль

  • Чанк: webpack упаковывает окончательно сгенерированные отдельные фрагменты файлов, окончательно сгенерированные отдельные файлы, один файл соответствует одному фрагменту.
  • модуль: каждый исходный файл js фактически можно рассматривать как модуль.

Недостатки chunkId

  • веб-пакет5 улучшенmoduleIdsа такжеchunkIdsOk. До webpack5 не былоentryУпакованные файлы фрагментов будут выводиться с использованием метода именования файлов 1, 2, 3... . (Значение хеша после имени файла генерируется с помощью chunkhash)

  • Это приведет к тому, что когда файл 1.js будет удален или временно не используется, то 2.js->1.js, 3.js->2.js, что вызовет исходный онлайн 2.js Кэш будет быть признаны недействительными по запросу.
  • Также можно пройти перед webpack5webpackChunkNameрешить проблему с названием
...
<Switch>
      <Route key='/' exact path='/' component={
         Loadable({
             loader: () => import(/* webpackChunkName: "home" */ './home'),
                     loading: (<div>loadding</div>)
                 })
         }/>
         <Route key='/page1' exact path='/page1' component={
             Loadable({
                loader: () => import(/* webpackChunkName: "page1" */'./page1'),
                    loading: () => (<div>loadding</div>)
                })
         } />
        <Route key='/page2' exact path='/page2' component={
           Loadable({
              loader: () => import(/* webpackChunkName: "page2" */'./page2'),
                  loading: () => (<div>loadding</div>)
               })
         } />
</Switch>
....
  • Кажется, это решает проблему инвалидации кеша, но когда мы откроем скомпилированный файл home.js, мы обнаружим, что chunkId все еще существует. Если домашнее меню удалено, упакованный chunkId страницы 1 и страницы 2 все равно изменится.

  • Файл, упакованный page1.js
  • Файл, упакованный page1.js после удаления home.js

  • Даже если page1.js не был изменен, чанкхаши page1.js все равно изменится из-за изменения chunkId, вызванного удалением home.js, и проблема инвалидации кеша все еще существует.

Улучшения в webapck5

  • С новым алгоритмом в рабочем режиме эти функции включены по умолчанию.chunkIds: "deterministic", moduleIds: "deterministic".
  • Этот алгоритм присваивает короткие числовые идентификаторы (3 или 4 символа) модулям и фрагментам детерминированным образом. Это основано на компромиссе между размером пакета и долгосрочным кэшированием.
 optimization.moduleIds: 
 可选值:
 1. false  告诉webpack不应使用任何内置算法,通过插件提供自定义算法
 2.natural 按使用顺序的数字ID。
 3.named 方便调试的高可读性id
 4.deterministic 根据模块名称生成简短的hash值
 5.size 根据模块大小生成的数字id
 optimization.chunkIds: 
 可选值:
 1. false  告诉webpack不应使用任何内置算法,通过插件提供自定义算法
 2.natural 按使用顺序的数字ID。
 3.named 方便调试的高可读性id
 4.deterministic 根据模块名称生成简短的hash值
 5.size 根据请求到的初始资源size计算的id
 6..total-size:根据请求到的解析资源size计算的id

Умнее встряхивать деревья

  • Условия включения встряхивания дерева такие же, как и в webpack 4. Для включения производственной среды необходимо использовать модульность ES6.
  • пример
// a.js
export const a =22;
export const b = 33;

// b.js
import * as a from './a.js'
export {a};

// index.js
import * as b from './b.js'

console.log(b.a.a)  // 输出22
  • webpack4: при упаковке будетconst b =33также упакован в

  • webpack5: упакованный код более оптимизирован

Скрипт nodeJs polyfill удален

  • webpack
  • Хотя это упрощает написание модулей для Node.js, в пакет добавляется слишком большой полифилл. Во многих случаях эти полифилы не нужны.
import CryptoJS from 'crypto-js';
console.log(CryptoJS.MD5('123123'));
  • веб-пакет4:
  • веб-пакет5:

Поддержка генерации кода для e6/es2015

  • webpack5 недавно добавил ecmaVersion в вывод, установилoutput: { ecmaVersion: 6 }Его можно использовать, код, сгенерированный при компиляции по умолчанию в webpack, соответствует версии es5.
  • Два метода настройки:5 =< ecmaVersion <= 11 2009 =< ecmaVersion <= 2020

SplitChunk и размер модуля

  • Модули теперь могут лучше представлять размеры вместо того, чтобы показывать одно число и разные типы размеров.
  • По умолчанию обрабатываются только размеры javascript, но теперь вы можете передавать несколько значений для управления ими:
optimization{
  splitChunks{
  minSize: {
        javascript: 30000,
        style: 50000,
    }
  }
}

Module Federation

  • Федерация модулей позволяет приложению JavaScript динамически загружать код из другого приложения JavaScript при совместном использовании зависимостей. Позвольте коду напрямую делиться между проектами с помощью CDN, больше не нужно устанавливать пакет Npm локально, создавать и публиковать его!
  • Динамическая загрузка позволяет коду загружать код другого приложения по запросу во время выполнения.
  • Пример: компонент кнопки, представленный в app2, упоминается в app1.
// app1 - webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
 //....
 plugins: [
  new ModuleFederationPlugin({
   name: "app1",  // 应用名称 唯一
   library: { type: "var", name: "app1" },
   remotes: { // 需要引用远程应用,与app2中library的name字段保持一致
    app2: "app2",
   },
   shared: ["react", "react-dom"], // 先判断存不再存这个包,如果不存在就使用app2里的依赖
  }),
 ],
};
// app2 - webpack.config.js
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
 //....
 plugins: [
  new ModuleFederationPlugin({
   name: "app2", // 应用名称 唯一
   library: { type: "var", name: "app2" }, // UMD标准导出,和name保持一致即可。
   filename: "remoteEntry.js", 暴露出去的chunkname
   exposes: {  要暴露出去的模块
    "./Button": "./src/Button",
   },
   shared: ["react", "react-dom"], 与app1共享的依赖,如果app1中有,则会优先使用app1中的依赖。(注:被app1引用)时候会按照app1的/package.json中的版本要求来加载
  }),
 ],
};
// app1/index.html
// 引入app2暴露的文件
...
<head>
	<srcipt src="http://localhost:3002/remoteEntry.js"></script>
</head>
...
app1/app.js

import AppTwoButton from 'app/Button';
const App = ()=>{
	return (
		<AppTwoButton/>
	)
}

app1/bootstrap.js
ReactDOM.render(<App />, document.getElementById("root"));

app1/bootstrap.js
import("./bootstrap");

  • Понимание федерации модулей из процесса загрузки

  • Первое, что нужно загрузить, это app2/remoteEntry.js, потому что он загружается в html.Просматривая remoteEntry.js, можно увидеть, что webpakc определяет app2 в глобальной переменной, так что app1 может загружать модули в app2.

  • Загрузите упакованный main.js app1, введите bootstrap.js, чтобы найти зависимости, проанализировать
  • Затем загрузите react.js и react-dom в main.js, prop-types.js, реакция которых зависит от
  • Затем, когда я прошел через пульт, я нашел компонент Button, который зависит от app2.
  • После загрузки всех зависимостей bootstrap.js асинхронная загрузка завершается, выполняется логика then и запускается приложение.

Суммировать

  • Федерация модулей предлагает новые идеи для микроинтерфейсов, сегментации кода, общих зависимостей, загрузки по требованию и может быть загружена во время выполнения. Но недостатком являются общедоступные глобальные переменные и глобальные стили, а предоставление модулей глобальным переменным недостаточно элегантно.
  • Webpack5 все еще находится в процессе слияния кодов.Текущая версия - bate22.После выхода официальной версии webpack5 я полагаю, что функция Module Federation будет продолжать оптимизироваться. Короче говоря, после обновления webpack5 скорость сборки и объем упаковки значительно улучшились.

использованная литература