Come caricare tutti i file in una directory usando webpack senza istruzioni require


95

Ho una grande quantità di file javascript suddivisi in 4 sottodirectory nella mia app. In grugnito li prendo tutti e li compilo in un unico file. Questi file non hanno una funzione module.exports.

Voglio usare webpack e dividerlo in 4 parti. Non voglio entrare manualmente e richiedere tutti i miei file.

Vorrei creare un plugin che durante la compilazione percorra gli alberi delle directory, quindi prenda tutti i nomi e i percorsi dei file .js, quindi richieda tutti i file nelle sottodirectory e lo aggiunga all'output.

Voglio che tutti i file in ciascuna directory siano compilati in un modulo che potrei quindi richiedere dal mio file del punto di ingresso o includere negli asset menzionati in http://webpack.github.io/docs/plugins.html .

Quando aggiungo un nuovo file, voglio solo rilasciarlo nella directory corretta e sapere che verrà incluso.

C'è un modo per farlo con webpack o un plugin che qualcuno ha scritto per farlo?

Risposte:


119

Questo è quello che ho fatto per ottenere questo risultato:

function requireAll(r) { r.keys().forEach(r); }
requireAll(require.context('./modules/', true, /\.js$/));

C'è un modo per specificare quale caricatore usare? Il mio caso d'uso è che desidero utilizzare image-size-loaderper tutte le immagini per creare segnaposto con proporzioni corrette.
bobbaluba

13
potresti fornire un esempio funzionante webpack.config.js
Rizwan Patel

2
@bobbaluba, è possibile specificare il caricatore nel file di configurazione: loaders: [ { test: /\.json$/, loader: 'json' } ]. { test: /\.json$/, loader: 'json' }aggiunge il caricatore json per i file .json, a condizione che sia stato installato il caricatore.
Jake

1
Tieni presente che se cerchi di essere DRY qui scrivendo una funzione che ti chiama require.context(...)(ad esempio, se stai cercando di richiedere tutto in più cartelle), webpack lancerà un avviso. Gli argomenti require.contextdevono essere costanti in fase di compilazione.
Isaac Lyman

3
@Joel npmjs.com/package/require-context è stato creato nel 2017 e la mia risposta è del 2015, quindi è difficile dire che sia presa direttamente da lì. Si noti inoltre che require-contextè un wrapper webpacke il suo esempio è tratto dalla webpackdocumentazione di webpack.js.org/guides/dependency-management/#context-module-api - che è stata aggiunta nel 2016 (in github.com/webpack/ webpack.js.org/commit/… ), anche dopo aver scritto la mia risposta ... Forse gli autori di webpack sono stati influenzati dalla mia risposta. Nota che l'hanno espanso per avere la cache.
splintore

38

Nel file della mia app ho finito per mettere il require

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

per gentile concessione di questo post: https://github.com/webpack/webpack/issues/118

Ora sta aggiungendo tutti i miei file. Ho un caricatore per html e css e sembra funzionare alla grande.


27
Cosa c'è exprin questo esempio?
twiz

2
exprè un percorso a un singolo file all'interno della cartella del contesto. quindi se hai bisogno di farlo non solo per richiedere tutti i file html, questo è utile. webpack.github.io/docs/context.html#context-module-api
mkoryak

18
non mi è ancora chiaro cosa exprstia facendo qui l'argomento basato anche dopo aver guardato i documenti del webpack. cosa significa "fare questo non solo per richiedere tutti i file html"? grazie
mikkelrd

3
Ho ricevuto Uncaught ReferenceError: expr non è definito . Qualche accenno a questo?
CSchulz

2
Ancora nessuna risposta su cosa exprsignifichi qui
wizulus

5

Che ne dici di una mappa di tutti i file in una cartella?

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

Fai questo:

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, /.*/));

Grazie per aver lasciato questo esempio. Ho usato map semplicemente restituendo il valore esportato da ciascuno dei miei file =).
cacoder

1

Esempio di come ottenere una mappa di tutte le immagini nella cartella corrente.

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

Tutti i meriti a @splintor (grazie).

Ma qui è la mia versione derivata.

Benefici:

  • I moduli esportati sono raccolti in un file {module_name: exports_obj} oggetto.
    • nome_modulo viene creato dal nome del file.
    • ... senza estensione e sostituendo le barre con trattini bassi (in caso di scansione di sottodirectory).
  • Aggiunti commenti per facilitare la personalizzazione.
    • Cioè potresti voler non includere file nelle sottodirectory se, ad esempio, sono lì per essere richiesti manualmente per i moduli a livello di root .

EDIT: Se, come me, sei sicuro che i tuoi moduli non restituiranno nient'altro che (almeno a livello di root) un normale oggetto javascript, puoi anche "montarli" replicando la loro struttura di directory originale (vedi Code (Deep Version ) alla fine).

Codice (versione originale):

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

Esempio:

Esempio di output per l'eventuale console.log(allModules);:

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

Albero delle directory:

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

Codice (versione profonda):

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

Esempio:

Risultato dell'esempio precedente utilizzando questa versione:

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

0

questo funziona per me:

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

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

NOTA: questo può richiedere file .js nelle sottodirectory di ./js/ in modo ricorsivo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.