Comment charger tous les fichiers dans un répertoire à l'aide de Webpack sans instructions require

95

J'ai une grande quantité de fichiers javascript divisés en 4 sous-répertoires dans mon application. En grognant, je les attrape tous et les compile dans un seul fichier. Ces fichiers n'ont pas de fonction module.exports.

Je veux utiliser webpack et le diviser en 4 parties. Je ne veux pas entrer manuellement et exiger tous mes fichiers.

Je voudrais créer un plugin qui, lors de la compilation, parcourt les arborescences de répertoires, puis saisit tous les noms et chemins de fichiers .js, puis requiert tous les fichiers des sous-répertoires et les ajoute à la sortie.

Je veux que tous les fichiers de chaque répertoire soient compilés dans un module que je pourrais ensuite exiger de mon fichier de point d'entrée, ou inclure dans les actifs mentionnés par http://webpack.github.io/docs/plugins.html .

Lors de l'ajout d'un nouveau fichier, je veux simplement le déposer dans le bon répertoire et savoir qu'il sera inclus.

Existe-t-il un moyen de faire cela avec webpack ou un plugin que quelqu'un a écrit pour le faire?

PouletFourrure
la source

Réponses:

119

Voici ce que j'ai fait pour y parvenir:

function requireAll(r) { r.keys().forEach(r); }
requireAll(require.context('./modules/', true, /\.js$/));
éclat
la source
Existe-t-il un moyen de spécifier quel chargeur utiliser? Mon cas d'utilisation est que je souhaite utiliser image-size-loaderpour toutes les images afin de créer des espaces réservés avec des proportions correctes.
bobbaluba
13
pourriez-vous vous fournir un exemple de travail webpack.config.js
Rizwan Patel
2
@bobbaluba, vous pouvez spécifier le chargeur dans le fichier de configuration: loaders: [ { test: /\.json$/, loader: 'json' } ]. { test: /\.json$/, loader: 'json' }ajoute le chargeur json pour les fichiers .json, tant que vous avez installé le chargeur.
Jake
1
Gardez à l'esprit que si vous essayez d'être DRY ici en écrivant une fonction qui vous appelle require.context(...)(par exemple si vous essayez de tout exiger dans plusieurs dossiers), webpack lancera un avertissement. Les arguments require.contextdoivent être des constantes à la compilation.
Isaac Lyman
3
@Joel npmjs.com/package/require-context a été créé en 2017 et ma réponse date de 2015, il est donc difficile de dire qu'elle est tirée directement de là. Notez également qu'il require-contexts'agit d'un wrapper webpack, et que son exemple est tiré de webpackla documentation de webpack.js.org/guides/dependency-management/#context-module-api - qui a été ajoutée en 2016 (dans github.com/webpack/ webpack.js.org/commit/... ), également après avoir écrit ma réponse ... Peut-être que les auteurs de webpack ont ​​été influencés par ma réponse. Notez qu'ils l'ont étendu pour avoir un cache.
splintor
38

Dans mon fichier d'application, j'ai fini par mettre le require

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

avec l'aimable autorisation de cet article: https://github.com/webpack/webpack/issues/118

Il ajoute maintenant tous mes fichiers. J'ai un chargeur pour html et css et il semble fonctionner très bien.

PouletFourrure
la source
27
Qu'y a-t-il exprdans cet exemple?
twiz
2
exprest un chemin vers un seul fichier dans le dossier contextuel. donc si vous devez le faire non seulement pour avoir besoin de tous les fichiers html, c'est utile. webpack.github.io/docs/context.html#context-module-api
mkoryak
18
je ne exprsais toujours pas ce que fait l' argument basé ici même après avoir regardé la documentation Webpack. que signifie «ne pas simplement pour exiger tous les fichiers html»? merci
mikkelrd
3
I got Uncaught ReferenceError: expr n'est pas défini . Un indice à ce sujet?
CSchulz
2
Toujours pas de réponse sur ce que exprsignifie ici
wizulus
5

Que diriez-vous d'une carte de tous les fichiers dans un dossier?

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

Faites ceci:

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
la source
Merci d'avoir laissé tomber cet exemple. J'ai utilisé map renvoyer simplement la valeur que chacun de mes fichiers exporté =).
cacoder
1

Exemple de la façon d'obtenir une carte de toutes les images dans le dossier actuel.

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
la source
1

Tous les mérites à @splintor (merci).

Mais ici, c'est ma propre version dérivée.

Avantages:

  • Les modules exportés sont regroupés sous un {module_name: exports_obj}objet.
    • module_name est construit à partir de son nom de fichier.
    • ... sans extension et en remplaçant les barres obliques par des traits de soulignement (en cas d'analyse de sous-répertoires).
  • Ajout de commentaires pour faciliter la personnalisation.
    • Par exemple, vous voudrez peut-être ne pas inclure de fichiers dans les sous-répertoires si, par exemple, ils sont là pour être requis manuellement pour les modules de niveau racine .

EDIT: Si, comme moi, vous êtes sûr que vos modules ne renverront rien d'autre que (au moins au niveau racine) un objet javascript normal, vous pouvez également les «monter» en répliquant leur structure de répertoire d'origine (voir Code (version profonde ) à la fin).

Code (version 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
));

Exemple:

Exemple de sortie pour éventuel console.log(allModules);:

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

Arborescence des répertoires:

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

Code (version profonde):

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

Exemple:

Résultat de l'exemple précédent utilisant cette version:

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

cela fonctionne pour moi:

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

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

REMARQUE: cela peut nécessiter des fichiers .js dans des sous-répertoires de ./js/ de manière récursive.

jack long
la source