Webpack разрешает псевдоним и компилирует файл под этим псевдонимом

У меня есть проект, который использует lerna (monorepo, несколько пакетов). Немногие из пакетов являются автономными приложениями.

Чего я хочу добиться, так это иметь псевдонимы для нескольких пакетов, чтобы иметь что-то вроде внедрения зависимостей. Так, например, у меня есть псевдоним @package1/backendProvider/useCheckout и в веб-пакете в моем автономном приложении я разрешаю его как ../../API/REST/useCheckout . Поэтому, когда я меняю бэкэнд-провайдера на что-то другое, я меняю его только в webpack.

Проблема

Проблема возникает, когда этот псевдоним используется каким-либо другим пакетом (не отдельным приложением). Например:

Структура каталогов выглядит следующим образом:

Project
    packageA
           ComponentA
    packageB
           API
              REST
                  useCheckout
    standalone app

ComponentA находится в packageA

useCheckout находится в packageB по пути /API/REST/useCheckout

ComponentA использует useCheckout с таким псевдонимом, как import useCheckout from '@packageA/backendProvider/useCheckout

Автономное приложение использует компонент A

Ошибка, которую я получаю, заключается в том, что Module not found: Can't resolve '@packageA/backendProvider/useCheckout

Однако, когда тот же псевдоним используется в автономном приложении (у которого есть веб-пакет с приведенной ниже конфигурацией), он работает. Проблема возникает только для зависимостей.

Возможные решения

Я знаю, что одним из решений было бы скомпилировать каждый пакет с помощью веб-пакета, но это не очень удобно. Что я думаю, выполнимо, так это сказать веб-пакету преобразовать эти псевдонимы в пути к каталогам, а затем перекомпилировать его. Первая часть (разрешение псевдонимов) выполнена.

Текущий код

Поскольку я использую NextJS, моя конфигурация веб-пакета выглядит так:

 webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
    // Fixes npm packages that depend on `fs` module
    config.node = {
      fs: "empty"
    };

    const aliases = {
    ...
      "@package1/backendProvider": "../../API/REST/"
    };

    Object.keys(aliases).forEach(alias => {
      config.module.rules.push({
        test: /\.(js|jsx)$/,
        include: [path.resolve(__dirname, aliases[alias])],
        use: [defaultLoaders.babel]
      });

      config.resolve.alias[alias] = path.resolve(__dirname, aliases[alias]);
    });

    return config;
  }

person mmmm    schedule 15.04.2020    source источник


Ответы (1)


Вам не нужно использовать псевдонимы. У меня похожая настройка, просто переключитесь на рабочие области yarn (v1), что делает довольно умный трюк, он добавляет символическую ссылку на все ваши пакеты в корневом node_modules.

Таким образом, каждый пакет может без проблем импортировать другие пакеты.

Чтобы применить рабочие области пряжи с помощью lerna:

// lerna.json
{
  "npmClient": "yarn",
  "useWorkspaces": true,
  "packages": [
    "packages/**"
  ],
}
// package.json
{
  ...
  "private": true,
  "workspaces": [
    "packages/*",
  ]
  ...
}

Это активирует рабочее пространство пряжи с lerna.

Единственное, что осталось решить, это сделать потребительский пакет для транспиляции требуемого пакета (поскольку конфигурации по умолчанию для babel и webpack игнорируют транспиляцию node_module).

В проекте Next.js это легко сделать, используйте next-transpile-modules.

// next.config.js

const withTM = require('next-transpile-modules')(['somemodule', 'and-another']); // pass the modules you would like to see transpiled
 
module.exports = withTM();

В других пакетах, которые используют webpack, вам нужно будет указать webpack транспилировать ваши потребляемые пакеты (допустим, они находятся в области npm @somescope/).

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

// webpack.config.js
{
  ...
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        include: /[\\/]node_modules[\\/]@somescope[\\/]/, // <-- instruct to transpile ts files from this path
        options: {
          allowTsInNodeModules: true, // <- this a specific option of ts-loader
          transpileOnly: isDevelopment,
          compilerOptions: {
            module: 'commonjs',
            noEmit: false,
          },
        },
      }
    ]
  }
  ...
  resolve: {
      symlinks: false, // <-- important
  }
}

Если у вас есть css, вам также нужно будет добавить раздел для css.

Надеюсь это поможет.

Бонусное преимущество: рабочие области пряжи уменьшат размер вашего node_modules, поскольку он будет устанавливать дубликаты пакетов (с той же версией semver) один раз!

person felixmosh    schedule 21.04.2020