Как загрузить все файлы в каталог с помощью webpack без инструкций require

96

В моем приложении у меня есть большое количество файлов javascript, разделенных на 4 подкаталога. Я хватаю их все и компилирую в один файл. Эти файлы не имеют функции module.exports.

Я хочу использовать веб-пакет и разбить его на 4 части. Я не хочу вручную заходить и требовать все свои файлы.

Я хотел бы создать плагин, который при компиляции просматривает деревья каталогов, затем захватывает все имена и пути файлов .js, затем запрашивает все файлы в подкаталогах и добавляет их к выходным данным.

Я хочу, чтобы все файлы в каждом каталоге были скомпилированы в модуль, который я мог бы затем запросить из моего файла точки входа или включить в ресурсы, упомянутые http://webpack.github.io/docs/plugins.html .

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

Есть ли способ сделать это с помощью webpack или плагина, который кто-то написал для этого?

Куриный мех
источник

Ответы:

119

Вот что я сделал для этого:

function requireAll(r) { r.keys().forEach(r); }
requireAll(require.context('./modules/', true, /\.js$/));
шина
источник
Есть ли способ указать какой загрузчик использовать? Мой вариант использования заключается в том, что я хочу использовать image-size-loaderдля всех изображений, чтобы создавать заполнители с правильными пропорциями.
bobbaluba
13
Не могли бы вы предоставить вам рабочий образец webpack.config.js
Ризван Патель,
2
@bobbaluba, вы можете указать загрузчик в конфигурационном файле: loaders: [ { test: /\.json$/, loader: 'json' } ]. { test: /\.json$/, loader: 'json' }добавляет загрузчик json для файлов .json, если вы установили загрузчик.
Джейк
1
Имейте в виду, что если вы попытаетесь быть СУХИМ здесь, написав функцию, которая вызывает require.context(...)вас (например, если вы пытаетесь потребовать все в нескольких папках), webpack выдаст предупреждение. Аргументы require.contextдолжны быть константами времени компиляции.
Isaac Lyman
4
@Joel npmjs.com/package/require-context был создан в 2017 году, а мой ответ - с 2015 года, поэтому трудно сказать, что он взят прямо оттуда. Также обратите внимание, что require-contextэто оболочка webpack, и ее образец взят из webpackдокументации на webpack.js.org/guides/dependency-management/#context-module-api, который был добавлен в 2016 году (в github.com/webpack/ webpack.js.org/commit/… ), также после того, как я написал свой ответ ... Может быть, мой ответ повлиял на авторов webpack. Обратите внимание, что они расширили его, чтобы иметь кеш.
splintor
38

В моем файле приложения я поставил требование

require.context(
  "./common", // context folder
  true, // include subdirectories
  /.*/ // RegExp
)("./" + expr + "")

любезно предоставлено этим сообщением: https://github.com/webpack/webpack/issues/118

Сейчас добавляются все мои файлы. У меня есть загрузчик для html и css, и он, кажется, отлично работает.

Куриный мех
источник
27
Что exprв этом примере?
twiz
2
expr- это путь к одному файлу в папке контекста. так что, если вам нужно сделать это не только для того, чтобы требовать все файлы html, это полезно. webpack.github.io/docs/context.html#context-module-api
mkoryak
18
Мне все еще неясно, что exprздесь делает аргумент based, даже после просмотра документации webpack. что означает «сделать это не только для того, чтобы требовать все файлы html»? спасибо
mikkelrd
3
Я получил Uncaught ReferenceError: expr не определен . Есть намёк на это?
CSchulz
2
Все еще нет ответа о том, что exprздесь имеется в виду
wizulus
5

Как насчет карты всех файлов в папке?

// { 
//   './image1.png':  'data:image/png;base64,iVBORw0KGgoAAAANS',
//   './image2.png':  'data:image/png;base64,iVBP7aCASUUASf892',
// }

Сделай это:

const allFiles = (ctx => {
    let keys = ctx.keys();
    let values = keys.map(ctx);
    return keys.reduce((o, k, i) => { o[k] = values[i]; return o; }, {});
})(require.context('./path/to/folder', true, /.*/));
Стивен де Салас
источник
Спасибо, что бросили этот пример. Я использовал карту, просто возвращая значение, которое экспортировал каждый из моих файлов =).
cacoder
1

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

const IMAGES_REGEX = /\.(png|gif|ico|jpg|jpeg)$/;

function mapFiles(context) {
  const keys = context.keys();
  const values = keys.map(context);
  return keys.reduce((accumulator, key, index) => ({
    ...accumulator,
    [key]: values[index],
  }), {});
}

const allImages = mapFiles(require.context('./', true, IMAGES_REGEX));
Алекс К
источник
1

Все заслуги @splintor (спасибо).

Но это моя производная версия.

Льготы:

  • Какие модули экспортируются под {module_name: exports_obj}объект.
    • module_name строится из имени файла.
    • ... без расширения и замены слэшей на символы подчеркивания (в случае сканирования подкаталогов).
  • Добавлены комментарии для упрощения настройки.
    • Т.е. вы можете не включать файлы в подкаталоги, если, скажем, они требуются вручную для модулей корневого уровня .

РЕДАКТИРОВАТЬ: Если, как и я, вы уверены, что ваши модули не будут возвращать ничего, кроме (по крайней мере, на корневом уровне) обычного объекта javascript, вы также можете «смонтировать» их, реплицируя их исходную структуру каталогов (см. Код (Глубокая версия) ) раздел в конце).

Код (исходная версия):

function requireAll(r) {
    return Object.fromEntries(
        r.keys().map(function(mpath, ...args) {
            const result =  r(mpath, ...args);
            const name = mpath
                .replace(/(?:^[.\/]*\/|\.[^.]+$)/g, '') // Trim
                .replace(/\//g, '_') // Relace '/'s by '_'s
            ;
            return [name, result];
        })
    );
};
const allModules = requireAll(require.context(
    // Any kind of variables cannot be used here
    '@models'  // (Webpack based) path
    , true     // Use subdirectories
    , /\.js$/  // File name pattern
));

Пример:

Пример вывода для возможных console.log(allModules);:

{
  main: { title: 'Webpack Express Playground' },
  views_home: {
    greeting: 'Welcome to Something!!',
    title: 'Webpack Express Playground'
  }
}

Дерево каталогов:

models
├── main.js
└── views
    └── home.js

Код (Глубокая версия):

function jsonSet(target, path, value) {
    let current = target;
    path = [...path]; // Detach
    const item = path.pop();
    path.forEach(function(key) {
        (current[key] || (current[key] = {}));
        current = current[key];
    });
    current[item] = value;
    return target;
};
function requireAll(r) {
    const gather = {};
    r.keys().forEach(function(mpath, ...args) {
        const result =  r(mpath, ...args);
        const path = mpath
            .replace(/(?:^[.\/]*\/|\.[^.]+$)/g, '') // Trim
            .split('/')
        ;
        jsonSet(gather, path, result);
    });
    return gather;
};
const models = requireAll(require.context(
    // Any kind of variables cannot be used here
    '@models'  // (Webpack based) path
    , true     // Use subdirectories
    , /\.js$/  // File name pattern
));

Пример:

Результат предыдущего примера с использованием этой версии:

{
  main: { title: 'Webpack Express Playground' },
  views: {
    home: {
      greeting: 'Welcome to Something!!',
      title: 'Webpack Express Playground'
    }
  }
}
Bitifet
источник
0

это работает для меня:

function requireAll(r) { r.keys().forEach(r); } 

requireAll(require.context('./js/', true, /\.js$/));

ПРИМЕЧАНИЕ: для этого могут потребоваться файлы .js в подкаталогах ./js/ рекурсивно.

Джек Лонг
источник