Есть ли способ сказать lerna / npm «действительно искать в моих собственных node_modules эти зависимости одноранговых узлов»? - PullRequest
4 голосов
/ 28 мая 2020

У меня есть довольно стандартный lerna monorepo, который будет выглядеть следующим образом:

packages/
    main/  - This is the main deployable application, it depends on both dep and react-dep
    dep/   - Just some pure functions, no problems here
    react-dep/ - A design system built with react, this is where we have problems. 

Итак, действительно распространенная проблема, которая возникает, - это сообщение появляется, как только вы начинаете использовать хуки в своей библиотеке зависимостей. :

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.

Это потому, что в вашем приложении есть две версии React, одна из основного приложения, а другая из зависимости.

Теперь - распространенное решение, которое я использовал и которое работает, - это объявить react и любые другие общие / одноранговые зависимости как externals в конфигурации вашего веб-пакета. Например, как предлагается здесь. или посмотрите на этот Github выдает ветку из response .

Однако я не фанат этого решения, во-первых, что, если Я не использую webpack, и, во-вторых, мне не нужно вручную отслеживать, какие зависимости мне нужно пометить как внешние.

Я думаю, что должно работать:

В react-dep Я объявляю react как в devDependencies, так и в peerDependencies. Причина, по которой я поместил его в devDependencies, заключается в том, что моя библиотека зависимостей, вероятно, использует сборник рассказов или что-то подобное для разработки компонентов, поэтому мне действительно нужно реагировать на разработку.

Я думаю, что это должно сработать, если я публикую react-dep в npm и использую скомпилированный код из npm в main, потому что будет извлечен только dependencies.

Однако я думаю, что из-за символической ссылки lerna в этом случае происходит то, что зависимость dev все еще существует, и мы получаем эту ошибку.

Есть ли способ решить эту проблему для lerna monorepo?

Вот репозиторий на github, демонстрирующий эту проблему: https://github.com/dwjohnston/lerna-react-monorepo

1 Ответ

1 голос
/ 02 июня 2020

Насколько я понимаю, эта проблема потенциально может быть решена с помощью lerna, npm, yarn или webpack.
Я хочу предложить еще одно решение webpack там, открыл pr на ваше репо. Если решение webpack вам не подходит - просто проигнорируйте этот ответ.

Это немного лучше, чем механизм externals, потому что он автоматически отслеживает перекрывающиеся зависимости одноранговых узлов.

module.exports = function(config) {
    config.plugins.push(
        new NormalModuleReplacementPlugin(re, function(resource) {
            // first, remove babel and other loaders paths
            const requestWithoutLoaderMeta = resource.request.split('!');
            const requestPath = requestWithoutLoaderMeta.length && requestWithoutLoaderMeta[requestWithoutLoaderMeta.length - 1];

            if (requestPath) {
                // looking for a dependency and package names
                const packagesPath = resolve(__dirname, '../') + '/';
                const requestPathRel = requestPath.replace(packagesPath, '');
                const [packageName, _, depName] = requestPathRel.split('/');

                // if the main package has this dependency already - just use it
                if (dependencies[packageName]) {
                    console.log('\x1b[35m%s\x1b[0m', `[REPLACEMENT]: using dependency <${depName}> from package [main] instead of [${packageName}]`);
                    resource.request = resource.request.replace(`${packageName}/node_modules/${depName}`, `main/node_modules/${depName}`)
                }
            }
        })
    );

    return config;
}

Этот код разрешит ваши одноранговые зависимости из пакета main, используя webpack.NormalModuleReplacementPlugin.

Примечание о веб-пакете: поскольку все три короля веб-интерфейса используют его в своем CLI (angular, реагируйте, vue Я думаю, вы можете легко и безопасно использовать его для таких настроек.

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

Дайте @ nrwl / nx попробовать для вашего следующего монорепозитория вместо lerna.
Главное отличие в том, что nrwl проекты обычно имеют ОДИН package.json только (с использованием опыта Google), поэтому вам нужно установить зависимости один раз для всех пакетов, и вы не столкнетесь с описанной вами проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...