Используйте механизм Plug'n'Play Yarn (v1.12+) вместо node_modules. В настоящее время это экспериментальная функция.
Оригинальная ссылка:Может ли Yarn Plug'n'Play помочь вам избавиться от проблем с node_modules?
задний план
node_modules
Объекты, которые давно были национальной рвотой, а разработчики других языков видят Node_Modules, чтобы увидеть узел,
Используйте слово, чтобы описать «вес!».
Если вы не понимаете механизм поиска модулей Node, нажмитеинтерпретация исходного кода require()
Простой интерфейсный проект (create-react-app) и количество файлов:
И macOS/Library
Размер каталога с количеством файлов:
одна линияhello world
Вам необходимо установить более 130 МБ зависимых модулей, а количество файлов32,313, В отличие от macOS/Library
занимает 9,02 ГБ места, а количество файлов всего в два раза больше, чем у прежнего (67,890Таким образом, можно увидеть, что характеристики node_modules:
- Структура дерева каталогов сложна
- Количество файлов велико, и они относительно малы
- Зависимостей много, простому проекту нужно установить несколько тонн зависимостей
Так что node_modules — это кошмар для механических жестких дисков, я помню, как однажды коллега удалил node_modules и не получил его весь день.
Для фронтенд-разработчиков у нас есть N потребностейnpm install
проект 😹.
Кроме того, модульный механизм Node имеет следующиенедостаток:
-
Сам узел не имеет концепции модулей, он ищет и загружает их во время выполнения.Этот недостаток аналогичен *'Сравнению плюсов и минусов динамических языков и статических языков'*, Возможно, вы работаете нормально в среде разработки, но не можете работать онлайн, потому что модуль не был добавлен в package.json.
-
Стратегия поиска модулей Node очень расточительна, этот недостаток можно оптимизировать в большинстве фронтенд-проектов, Например, webpack может ограничить поиск только node_modules в корневом каталоге проекта, но для вложенных зависимостей все равно требуется более 2 поисков.
-
node_modules не может эффективно обрабатывать дубликаты пакетов Два пакета с одинаковым именем, но разными версиями не могут сосуществовать в одном каталоге. Таким образом, это приведет к вложенным модулям node_modules, и эти «зависимости» проекта не могут быть разделены с проектами или другими зависимостями:
# ① 假设项目依赖a,b,c三个模块, 依赖树为: # +- a # +- react@15 # +- b # +- react@16 # +- c # +- react@16 # yarn安装时会按照项目被依赖的次数作为权重, 将依赖提升(hoisting), # 安装后的node_modules结构为: . └── node_modules ├── a │ ├── index.js │ ├── node_modules │ │ └── react # @15 │ └── package.json ├── b │ ├── index.js │ └── package.json ├── c │ ├── index.js │ └── package.json └── react # @16 被依赖了两次, 所以进行提升 # ② 现在假设在①的基础上, 根项目依赖了react@15, 对于项目自己的依赖肯定是要放在node_modules根目录的, # 由于一个目录下不能存在同名目录, 所以react@16没有的提升机会. # 安装后node_moduels结构为 . └── node_modules ├── a │ ├── index.js │ └── package.json # react@15 提升 ├── b │ ├── index.js │ ├── node_modules │ │ └── react # @16 │ └── package.json ├── c │ ├── index.js │ ├── node_modules │ │ └── react # @16 │ └── package.json └── react # @15 # 上面的结果可以看出, react@16出现了重复
Пряжа интегрированаPlug'n'Play
(называемый pnp), китайское имя можно назвать «подключи и работай», чтобы решить «ад» node_modules.
Фундаментальный
Согласно обычному последующему процессу, Yarn создаст каталог node_modules, а затем Node будет искать в каталоге node_modules в соответствии со своими правилами поиска модулей. Но на самом деле Node не знает, что это за модуль, он ищет в node_modules, если не находит, то ищет в node_modules в родительском каталоге и так далее. Эта эффективность очень низкая.
Но как менеджер пакетов, Yarn знает дерево зависимостей вашего проекта.Может ли Yarn сообщить Node?Пусть он идет прямо в каталог для загрузки модулей.
Таким образом можно повысить эффективность поиска модулей Node, а также уменьшить количество копий файла node_modules.Plug'n'Play
основной принцип.
В режиме pnp Yarn не создает каталог node_modules, вместо этого.png.js
файл, который является программой узла,
Этот файл содержит информацию о дереве зависимостей проекта, алгоритм поиска модулей, а также код исправления для средства поиска модулей (в Node переопределяет метод Module._load).
Следующее с использованием механизма pnpпреимущество:
- избавиться от node_modules.
- Время: по сравнению с работой в среде горячего кэша.
yarn install
Экономьте 70% своего времени - Space: в режиме pnp все модули npm будут храниться в каталоге глобального кеша, дерево зависимостей сглажено, а копирование и повторение исключены.
- Время: по сравнению с работой в среде горячего кэша.
- Повышение эффективности загрузки модулей.Node должен вызывать много системных вызовов stat и readdir, чтобы найти модули. pnp получает информацию о модуле через Yarn и напрямую находит модуль
- Больше не ограничивается node_modules, разные версии модулей с одинаковыми именами не могут находиться в одном каталоге.
Скорость установки Yarn под Mac очень высока, а при горячем кеше это занимает всего несколько секунд, причина в механизме копирования при записи SSD + APFS. Это позволяет копии файла не занимать места, что эквивалентно созданию ссылки, поэтому скорость копирования и удаления очень высока. Но сложная структура каталогов и слишком много файлов node_modules по-прежнему требуют большого количества системных вызовов, что также замедлит процесс установки.
💡 Если вы считаете pnp громоздким или ненадежным, то быстро используйте SSD с файловой системой, поддерживающей копирование при записи.
используя pnpриск:
Различные инструменты в сообществе интерфейсов в настоящее время полагаются на механизм поиска модулей node_modules.
- Node
- Электрон, электрон-строитель и т.д.
- Webpack
- Typescript: найти файл объявления типа
- Babel: таргетинг на плагины и пресеты
- Eslint: таргетинг на плагины и пресеты, правила
- Jest
- Редактор, например VsCode
- ...😿
pnp — это совершенно новая вещь, появившаяся в сентябре 2018 г. Было непросто интегрировать эти инструменты с pnp, и эти инструменты И pnp, и pnp постоянно повторяются, pnp нестабилен и может измениться в будущем, что также повлечет за собой некоторые трудности с обслуживанием.
В дополнение к механизму поиска модулей есть некоторые инструменты, которые делают другие вещи непосредственно в node_modules, такие как кэширование, хранение временных сертификатов, например.cache-loader
, webpack-dev-server
включить pnp
Если это простой проект Node, процесс миграции относительно прост.package.json
Включить режим установки pnp:
{
"installConfig": {
"pnp": true
}
}
Затем установите зависимости:
yarn add express
После установки появится корневая директория проекта.pnp.js
Затем напишите код:
// index.js
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Следующим шагом является запуск кода Node, если вы напрямуюnode index.js
будет сообщеноError: Cannot find module 'express'
аномальный.
Это связано с тем, что для patch Node еще нет средства поиска модулей, которое можно запустить с помощью следующей команды:
yarn node
# 或者
node --require="./.pnp.js" index.js
.pnp.js
Файл не должен помещаться в репозиторий, этот файл содержит жестко заданную директорию кеша. Будет рефакторинг в Yarn v2.
Как интегрироваться в существующий проект?
интеграция pnp - это не что иное, как повторная реализация механизма поиска модулей существующих инструментов.С развитием фронтенд-инжиниринга фронтенд-проект будет интегрировать множество инструментов, Если эти инструменты не могут быть адаптированы, можно сказать, что pnp трудно двигаться вперед, однако это не то, что pnp может контролировать, и требует сотрудничества разработчиков этих инструментов.
Многие проекты в сообществе интегрировали pnp:
Node
Для Node pnp не входит в стандартную комплектацию, используйте его напрямую--require="./.pnp.js"
импорт.pnp.js
файл,.pnp.js
Он исправит объект модуля Node и повторно реализует механизм поиска модуля.
Webpack
Средство поиска модулей, используемое Webpack,enhanced-resolve
, способный пройтиpnp-webpack-plugin
плагин для расширенияenhanced-resolve
для поддержки пнп.
const PnpWebpackPlugin = require(`pnp-webpack-plugin`);
module.exports = {
resolve: {
// 扩展模块查找器
plugins: [PnpWebpackPlugin],
},
resolveLoader: {
// 扩展loader模块查找器.
plugins: [PnpWebpackPlugin.moduleLoader(module)],
},
};
jest
jestподдержка черезresolver
Чтобы настроить искатель:
module.exports = {
resolver: require.resolve(`jest-pnp-resolver`),
};
Typescript
Typescript также использует свой собственный поиск модулей.По соображениям производительности команда TS временно не разрешает сторонним инструментам расширять поиск.Временно недоступен.
в этотissue, было предложено использовать"moduleResolution": "yarnpnp"
или используйте что-то вродеts-loader
изresolveModuleName
способ поддержки поиска модуля pnp.
Ответ от команды TS: pnp (или tink для npm) все еще находится на ранней стадии и может измениться в будущем, например..pnp.js
файл, он явно не подходит для входа в яму так рано.
Кроме того, чтобы оптимизировать и контролировать производительность компилятора, TS не планирует предоставлять интерфейсы для выполнения стороннего кода во время компиляции.
Итак, теперь Typescript не имеет механизма плагинов, подобного babel, если вы, например, не реализуете «хост компилятора TS».ts-loader
Он сам по себе расширяет механизм подключаемых модулей и механизм поиска модулей для поддержки аналогичныхts-import-pluginи т.д. плагины, поэтомуts-loader
pnp теперь поддерживается:
const PnpWebpackPlugin = require(`pnp-webpack-plugin`);
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
loader: require.resolve('ts-loader'),
options: PnpWebpackPlugin.tsLoaderOptions(),
},
],
},
};
Суммировать,Typescript
В настоящее время не поддерживается, а плана развития в ближайшее время нет, так чтоVsCode
На это тоже не рассчитывайте.fork-ts-checker-webpack-plugin
Пока не догнал.Видимо Typescript первый камень преткновения для pnp
Другие инструменты
- rollup-plugin-pnp-resolve
- resolve: babel, gulp
- eslint: до v6Идеальная поддержка.
- flow
- create-react-apppnp поддерживается, но не в режиме Typescript
- электрон: Пока нет связанных новостей. Для электронного приложения зависимости являются автономными, поэтому pnp может не подходить для этого сценария.
Суммировать
Подводя итог, pnp является хорошим решением, которое может решить проблемы эффективности использования пространства и времени модульного механизма Node, но на данном этапе оно еще не созрело, есть Есть много ям, на которые нужно наступить, и много проблем в интеграции с различными инструментами в сообществе, поэтому не рекомендуется использовать его в производственной среде.
Так что на данном этапе для обычных разработчиков, если вы хотите улучшить скорость установки npm, вам все равно придется использовать SSD+Copy-On-Write!😂
Ниже представлена интеграция различных проектов (✅(поддерживается)|🚧(запланировано или несовершенно)|❌(не поддерживается)):
проект | |
---|---|
Webpack | ✅ |
rollup | ✅ |
browserify | ✅ |
gulp | ✅ |
jest | ✅ |
Node | ✅ |
Typescript/VScode IntelliSense | ❌ |
eslint | 🚧 |
flow | 🚧 |
create-react-app | 🚧 |
ts-loader | ✅ |
fork-ts-checker-webpack-plugin | 🚧 |
Ссылаться на
- Plug'n'Play WhitepaperПНП диссертация
- Как избавиться от node_modules с помощью Yarn Plug'n'Play
- Официальная документация по пряже
- pnp-sample-appофициальный пример pnp
- Yarn's Future - v2 and beyond
- Hacker News Discussion
Связанные вопросы:
- Yarn Plug 'N Play should generate a static manifest file, not
.pnp.js
- Typescript: Add new moduleResolution option:
yarn-pnp
- fork-ts-checker-webpack-plugin: Custom resolveModuleName
Другие варианты
- npm tink: a dependency unwinder for javascript
- pnpm Fast, disk space efficient package manager
- Yarn WorkspacesНесколько проектов имеют общие зависимости