Jak załadować wszystkie pliki w katalogu za pomocą webpacka bez wymaganych instrukcji

96

Mam dużą liczbę plików javascript podzielonych na 4 podkatalogi w mojej aplikacji. Chwytam je wszystkie i kompiluję w jednym pliku. Te pliki nie mają funkcji module.exports.

Chcę użyć webpacka i podzielić go na 4 części. Nie chcę wchodzić ręcznie i wymagać wszystkich moich plików.

Chciałbym stworzyć wtyczkę, która podczas kompilacji przechodzi przez drzewa katalogów, a następnie pobiera wszystkie nazwy plików .js i ścieżki, a następnie wymaga wszystkich plików w podkatalogach i dodaje je do wyjścia.

Chcę, aby wszystkie pliki w każdym katalogu zostały skompilowane w moduł, którego mógłbym następnie wymagać z mojego pliku punktu wejścia lub dołączyć do zasobów, o których wspomina http://webpack.github.io/docs/plugins.html .

Podczas dodawania nowego pliku chcę po prostu upuścić go w odpowiednim katalogu i wiedzieć, że zostanie dołączony.

Czy istnieje sposób, aby to zrobić za pomocą webpacka lub wtyczki, którą ktoś napisał, aby to zrobić?

ChickenFur
źródło

Odpowiedzi:

119

Oto, co zrobiłem, aby to osiągnąć:

function requireAll(r) { r.keys().forEach(r); }
requireAll(require.context('./modules/', true, /\.js$/));
drzazga
źródło
Czy istnieje sposób, aby określić, jakiego programu ładującego użyć? Mój przypadek użycia polega na tym, że chcę użyć image-size-loaderdla wszystkich obrazów, aby utworzyć symbole zastępcze z prawidłowymi współczynnikami proporcji.
bobbaluba
13
czy możesz podać działający przykładowy plik webpack.config.js
Rizwan Patel,
2
@bobbaluba można określić program ładujący w pliku konfiguracyjnym: loaders: [ { test: /\.json$/, loader: 'json' } ]. { test: /\.json$/, loader: 'json' }dodaje moduł ładujący json dla plików .json, o ile jest zainstalowany moduł ładujący.
Jake
1
Pamiętaj, że jeśli spróbujesz tutaj być SUCHY, pisząc funkcję, która require.context(...)cię wywoła (np. Jeśli próbujesz wymagać wszystkiego w kilku folderach), webpack wyśle ​​ostrzeżenie. Argumenty require.contextmuszą być stałymi czasu kompilacji.
Isaac Lyman,
4
@Joel npmjs.com/package/require-context powstał w 2017 roku, a moja odpowiedź pochodzi z 2015 roku, więc trudno powiedzieć, że jest zaczerpnięta prosto z tego. Zauważ również, że require-contextjest to otoka webpack, a jej próbka pochodzi z webpackdokumentacji pod adresem webpack.js.org/guides/dependency-management/#context-module-api - która została dodana w 2016 roku (na github.com/webpack/ webpack.js.org/commit/ ... ), także po napisaniu odpowiedzi ... Może moja odpowiedź miała wpływ na twórców webpacka . Zauważ, że rozszerzyli go, aby mieć pamięć podręczną.
splintor
38

W pliku aplikacji umieściłem wymaganie

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

dzięki uprzejmości tego posta: https://github.com/webpack/webpack/issues/118

Teraz dodaje wszystkie moje pliki. Mam program ładujący dla html i css i wygląda na to, że działa świetnie.

ChickenFur
źródło
27
Co jest exprw tym przykładzie?
twiz
2
exprto ścieżka do pojedynczego pliku w folderze kontekstu. więc jeśli chcesz to zrobić nie tylko po to, aby wymagać wszystkich plików html, jest to przydatne. webpack.github.io/docs/context.html#context-module-api
mkoryak
18
nadal nie jest dla mnie jasne, co exprrobi tu oparty argument, nawet po przejrzeniu dokumentacji pakietu webpack. co oznacza „nie rób tego tylko dla wymagania wszystkich plików html”? dziękuję
mikkelrd
3
Otrzymałem Uncaught ReferenceError: wyrażenie nie jest zdefiniowane . Jakieś wskazówki na ten temat?
CSchulz
2
Wciąż nie ma odpowiedzi na temat tego, co to exprznaczy
wizulus
5

Co powiesz na mapę wszystkich plików w folderze?

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

Zrób to:

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, /.*/));
Steven de Salas
źródło
Dzięki upuszczeniu tego przykładu. Użyłem map po prostu zwracając wartość, którą każdy z moich plików wyeksportował =).
cacoder
1

Przykład, jak uzyskać mapę wszystkich obrazów w bieżącym folderze.

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));
Alex K.
źródło
1

Wszystkie zasługi dla @splintor (dzięki).

Ale tutaj jest moja własna wersja pochodna.

Korzyści:

  • Jakie moduły są eksportowane do {module_name: exports_obj}obiektu.
    • nazwa_modułu jest budowana na podstawie jego nazwy pliku.
    • ... bez rozszerzenia i zamiany ukośników na podkreślenia (w przypadku skanowania podkatalogów).
  • Dodano komentarze ułatwiające dostosowywanie.
    • To znaczy możesz chcieć nie dołączać plików do podkatalogów, jeśli, powiedzmy, są tam, aby być ręcznie wymagane na poziomie głównym modułów .

EDYTOWAĆ: Jeśli, tak jak ja, jesteś pewien, że twoje moduły nie zwrócą niczego innego niż (przynajmniej na poziomie głównym) zwykły obiekt javascript, możesz także "zamontować" je replikując ich oryginalną strukturę katalogów (patrz Kod (wersja głęboka ) na końcu).

Kod (wersja oryginalna):

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
));

Przykład:

Przykładowe dane wyjściowe na ewentualne console.log(allModules); :

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

Drzewo katalogów:

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

Kod (wersja głęboka):

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
));

Przykład:

Wynik poprzedniego przykładu używającego tej wersji:

{
  main: { title: 'Webpack Express Playground' },
  views: {
    home: {
      greeting: 'Welcome to Something!!',
      title: 'Webpack Express Playground'
    }
  }
}
bitifet
źródło
0

to działa dla mnie:

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

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

UWAGA: rekurencyjnie może to wymagać plików .js w podkatalogach ./js/.

Jack długi
źródło