So laden Sie alle Dateien in ein Verzeichnis mit Webpack, ohne dass Anweisungen erforderlich sind

95

Ich habe eine große Menge von Javascript-Dateien in 4 Unterverzeichnisse in meiner App aufgeteilt. Im Grunzen greife ich alle und kompiliere sie zu einer Datei. Diese Dateien haben keine module.exports-Funktion.

Ich möchte Webpack verwenden und es in 4 Teile teilen. Ich möchte nicht manuell hineingehen und alle meine Dateien benötigen.

Ich möchte ein Plugin erstellen, das beim Kompilieren die Verzeichnisbäume durchläuft, dann alle .js-Dateinamen und -Pfade abruft, dann alle Dateien in den Unterverzeichnissen benötigt und zur Ausgabe hinzufügt.

Ich möchte, dass alle Dateien in den einzelnen Verzeichnissen zu einem Modul kompiliert werden, das ich dann aus meiner Einstiegspunktdatei benötigen oder in die Assets aufnehmen kann, die unter http://webpack.github.io/docs/plugins.html erwähnt werden.

Wenn ich eine neue Datei hinzufüge, möchte ich sie nur im richtigen Verzeichnis ablegen und weiß, dass sie enthalten sein wird.

Gibt es eine Möglichkeit, dies mit einem Webpack oder einem Plugin zu tun, das jemand geschrieben hat, um dies zu tun?

ChickenFur
quelle

Antworten:

119

Dies habe ich getan, um dies zu erreichen:

function requireAll(r) { r.keys().forEach(r); }
requireAll(require.context('./modules/', true, /\.js$/));
Schiene
quelle
Gibt es eine Möglichkeit anzugeben, welcher Loader verwendet werden soll? Mein Anwendungsfall ist, dass ich das image-size-loaderfür alle Bilder verwenden möchte , um Platzhalter mit korrekten Seitenverhältnissen zu erstellen.
Bobbaluba
13
Könnten Sie Ihnen ein Arbeitsbeispiel zur Verfügung stellen? webpack.config.js
Rizwan Patel
2
@bobbaluba, Sie können den Loader in der Konfigurationsdatei angeben : loaders: [ { test: /\.json$/, loader: 'json' } ]. { test: /\.json$/, loader: 'json' }Fügt den JSON-Loader für JSON-Dateien hinzu, sofern Sie den Loader installiert haben.
Jake
1
Denken Sie daran, dass das require.context(...)Webpack eine Warnung auslöst , wenn Sie versuchen, hier trocken zu sein, indem Sie eine Funktion schreiben, die Sie aufruft (z. B. wenn Sie versuchen, alles in mehreren Ordnern zu benötigen). Die Argumente require.contextmüssen Konstanten zur Kompilierungszeit sein.
Isaac Lyman
3
@Joel npmjs.com/package/require-context wurde 2017 erstellt und meine Antwort stammt aus dem Jahr 2015, daher ist es schwer zu sagen, dass es direkt von dort stammt. Beachten Sie auch, dass require-contextes sich um einen Wrapper webpackhandelt und das Beispiel aus webpackder Dokumentation unter webpack.js.org/guides/dependency-management/#context-module-api stammt, die 2016 hinzugefügt wurde (in github.com/webpack/). webpack.js.org/commit/… ), auch nachdem ich meine Antwort geschrieben habe ... Vielleicht wurden die Autoren von webpack von meiner Antwort beeinflusst. Beachten Sie, dass sie es erweitert haben, um Cache zu haben.
Schiene
38

In meiner App-Datei habe ich schließlich die Anforderung gestellt

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

Mit freundlicher Genehmigung dieses Beitrags: https://github.com/webpack/webpack/issues/118

Es werden jetzt alle meine Dateien hinzugefügt. Ich habe einen Loader für HTML und CSS und es scheint großartig zu funktionieren.

ChickenFur
quelle
27
Was ist exprin diesem Beispiel?
Twiz
2
exprist ein Pfad zu einer einzelnen Datei im Kontextordner. Wenn Sie dies nicht nur tun müssen, um alle HTML-Dateien zu benötigen, ist dies nützlich. webpack.github.io/docs/context.html#context-module-api
mkoryak
18
Es ist mir immer noch unklar, was das exprArgument hier tut, selbst nachdem ich mir die Webpack-Dokumente angesehen habe. Was bedeutet "dies nicht nur, um alle HTML-Dateien zu benötigen"? danke
mikkelrd
3
Ich habe Uncaught ReferenceError: Ausdruck ist nicht definiert . Irgendein Hinweis darauf?
CSchulz
2
Immer noch keine Antwort darüber, was exprhier bedeutet
Wizulus
5

Wie wäre es mit einer Karte aller Dateien in einem Ordner?

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

Mach das:

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
quelle
Vielen Dank, dass Sie dieses Beispiel fallen lassen. Ich habe map verwendet und einfach den Wert zurückgegeben, den jede meiner Dateien exportiert hat =).
Cacoder
1

Beispiel, wie Sie eine Karte aller Bilder im aktuellen Ordner erhalten.

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.
quelle
1

Alles Verdienst an @splintor (danke).

Aber hier ist es meine eigene abgeleitete Version.

Leistungen:

  • Welche Module exportiert werden, wird unter einem {module_name: exports_obj}Objekt gesammelt .
    • Modulname wird aus seinem Dateinamen erstellt.
    • ... ohne Erweiterung und Ersetzen von Schrägstrichen durch Unterstriche (beim Scannen von Unterverzeichnissen).
  • Kommentare hinzugefügt, um die Anpassung zu vereinfachen.
    • Das heißt, Sie möchten möglicherweise keine Dateien in Unterverzeichnisse aufnehmen, wenn diese beispielsweise für Module auf Stammebene manuell erforderlich sind.

BEARBEITEN: Wenn Sie wie ich sicher sind, dass Ihre Module nichts anderes als (zumindest auf Root-Ebene) ein reguläres Javascript-Objekt zurückgeben, können Sie sie auch "mounten", indem Sie ihre ursprüngliche Verzeichnisstruktur replizieren (siehe Code (Deep Version) ) Abschnitt am Ende).

Code (Originalversion):

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

Beispiel:

Beispielausgabe für eventuelle console.log(allModules);:

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

Verzeichnisbaum:

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

Code (Deep Version):

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

Beispiel:

Ergebnis des vorherigen Beispiels mit dieser Version:

{
  main: { title: 'Webpack Express Playground' },
  views: {
    home: {
      greeting: 'Welcome to Something!!',
      title: 'Webpack Express Playground'
    }
  }
}
Bitifet
quelle
0

das funktioniert bei mir:

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

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

HINWEIS: Dies kann rekursiv .js-Dateien in Unterverzeichnissen von ./js/ erfordern.

Jack lang
quelle