Нажмите на разрешение / загрузчик веб-пакета, чтобы добавить запасной вариант. - PullRequest
0 голосов
/ 23 января 2019

У меня есть приложение реакции (студенческий портал).

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

\- build
  - webpack.config.js
\- src
  - App.js
  - components\
    - Login\
      - Login.scss
      - Login.js
    - Dashboard\
    - Register\
  - redux\
  - helpers\ 

Мой веб-пакет довольно стандартен.

 var path = require('path');
 var webpack = require('webpack');
 module.exports = {
     entry: './src/app.js',
     output: {
         path: path.resolve(__dirname, 'build'),
         filename: 'app.bundle.js'
     },
     module: {
         loaders: [
             {
                 test: /\.js$/,
                 loader: 'babel-loader',
                 query: {
                     presets: ['es2015']
                 }
             }
         ]
     },
     stats: {
         colors: true
     },
     devtool: 'source-map'
 };

Я хочу построить поверх этого приложения.Так что я опубликовал это приложение в npm (местный).Моя структура папок теперь:

\- node_modules
  - student-portal\
\ - src\
\ - build\

. Мне бы хотелось иметь возможность заменять / расширять существующие компоненты и не нужно копировать существующие файлы.

Итак, если я создаю новыйфайл, я хочу, чтобы веб-пакет использовал его.Если этот файл не существует, он должен просмотреть node_modules/student-portal\src.

Таким образом, веб-пакет должен сначала изучить файл src, а затем - node_modules\student-portal\src.

Я попытался создать преобразовательфункция:

var MyResolver = {
  apply: function(resolver) {
    resolver.plugin('module', function(request, callback) {
      console.log(request.request); // this only consoles node_modules not .js files
    });
  }
};


Но это не утешает файлы .js.Я также поиграл с множеством других плагинов, таких как NormalModuleReplacementPlugin, ResolverPlugin и т. Д., Но безуспешно.

Любой указатель на то, как я могу подключиться к разрешению и замене пути в веб-пакете, если файл не существует, будет очень признателен.В идеале я хотел бы расширить существующие компоненты и сделать так, чтобы веб-пакет заменял путь к старому компоненту на путь к новому компоненту.

1 Ответ

0 голосов
/ 23 января 2019

Я думаю, вы могли бы использовать опции resolve.modules, так как он делает то, что вы описываете. Однако, поскольку речь идет о плагине для разрешения проблем, я постараюсь написать и его.

Resolve.modules

Вот пример с lodash в качестве целевого модуля. Мы можем настроить структуру следующим образом:

node_modules
  `--lodash
src
  |--lodash
  |    `-- zip.js
  `-index.js

zip.js может быть чем-то вроде export default () => 'local zip'

В нашем webpack.config.js делаем

module.exports = {
  ...
  resolve: {
    modules: [path.resolve(__dirname, 'src'), 'node_modules'],
  },
  ...
}

В нашем index.js давайте импортируем zip и isObject.

// src/index.js
import zip from 'lodash/zip';
import isObject from 'lodash/isObject';

console.log(zip()); // 'local zip'
console.log(isObject({ a: 100 }));  // 'true'

Это, по сути, то, что вы хотите, но вместо записи относительного пути к вашим пользовательским компонентам, вместо этого вы пишете путь к модулю.

Разрешить плагин

Но поскольку вопрос касается плагина, давайте попробуем! Я прокомментировал ваши вопросы раньше, но затем обнаружил, что система плагинов изменилась в веб-пакете 4. Я нахожусь на узле v10, поэтому некоторые синтаксисы могут не работать в более старых версиях.

Структура каталогов:

node_modules
  `--lodash
src
  |--components
  |    `-- zip.js
  `-index.js

Сначала краткий обзор плагина разрешения. Webpack позволяет нам использовать несколько хуков в конвейере разрешения ( полный список вы можете увидеть здесь ). Мы особенно заинтересованы в resolve, parsedResolve и module. Наш план:

1. Tap into the `resolve` hook  
2. Is the resolve request points to our 'components' folder?  
   - If not, go to **step 3**.  
   - If yes, is there something there it can use?  
       - If not, point it to `lodash` module instead.  
       - If yes, go to **step 3**.  
3. Continue to the next hook in the pipeline (`parsedResolve`).

Когда мы подключаемся к крючку, мы получим очень полезный request объект с этими опорами:

  • context: содержит эмитента (абсолютный путь к index.js)
  • path: каталог эмитента (абсолютный путь к src)
  • request: строка запроса ('./components/zip')

С этим мы можем написать наш плагин:

const path = require('path');
const fs = require('fs');

class CustomResolverPlugin {
  constructor ({ dir, moduleName }) {
    this.dir = dir;  // absolute path to our 'components' folder
    this.moduleName = moduleName; // name of the module, 'lodash' in this case
  }
  apply(resolver) {
    resolver.getHook('resolve').tapAsync('CustomResolverPlugin', (request, resolveContext, callback) => {

      // 1. check if the request is point to our component folder
      // resolver.join is same as path.join, but memoized
      const { dir } = path.parse(resolver.join(request.path, request.request));
      const match = dir === this.dir;

      if (match) {

        // 2. get the name of the file being requested & check if it exists.
        // in import zip from `./src/components/zip`, 'zip' is the name.
        const { name } = path.parse(request.request);
        const pathExist = fs.existsSync(path.join(this.dir, `${name}`));
        if (!pathExist) {

          // create a new request object.
          // we'll swap the request to something like 'lodash/zip'
          const _request = {
            ...request,
            request: `${this.moduleName}/${name}`
          }
          // swap the target hook to 'module' to resolve it as a module.
          const _target = resolver.ensureHook('module');
          return resolver.doResolve(_target, _request, null, resolveContext, callback);
        }
      }

      // 3. otherwise continue to the next hook
      const target = resolver.ensureHook('parsedResolve');
      return resolver.doResolve(target, request, null, resolveContext, callback);
    });
  }
}

Использование в webpack.config.js

module.exports = {
  ...
  resolve: {
    plugins: [
      new CustomResolverPlugin({
        dir: path.resolve(__dirname, './src/components'),
        moduleName: 'lodash',
      }),
    ],
  },
  ...
}

В вашем index.js:

import zip from './components/zip';
import isObject from './components/isObject';

console.log(zip(['a', 'b'], [1, 2])); // 'local zip'
console.log(isObject({ a: 100 }));    // true

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

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