Cómo cargar todos los archivos en un directorio usando webpack sin requerir declaraciones

95

Tengo una gran cantidad de archivos javascript divididos en 4 subdirectorios en mi aplicación. Con un gruñido, los agarro todos y los compilo en un archivo. Estos archivos no tienen una función module.exports.

Quiero usar el paquete web y dividirlo en 4 partes. No quiero entrar manualmente y solicitar todos mis archivos.

Me gustaría crear un complemento que en la compilación recorra los árboles de directorios, luego tome todos los nombres y rutas de archivo .js, luego requiera todos los archivos en los subdirectorios y los agregue a la salida.

Quiero que todos los archivos de cada directorio se compilen en un módulo que luego podría requerir de mi archivo de punto de entrada, o incluirlo en los activos que menciona http://webpack.github.io/docs/plugins.html .

Al agregar un nuevo archivo, solo quiero colocarlo en el directorio correcto y saber que se incluirá.

¿Hay alguna forma de hacer esto con un paquete web o un complemento que alguien haya escrito para hacer esto?

Pollo
fuente

Respuestas:

119

Esto es lo que hice para lograrlo:

function requireAll(r) { r.keys().forEach(r); }
requireAll(require.context('./modules/', true, /\.js$/));
férula
fuente
¿Hay alguna forma de especificar qué cargador usar? Mi caso de uso es que quiero usar el image-size-loaderpara todas las imágenes para crear marcadores de posición con relaciones de aspecto correctas.
bobbaluba
13
¿Podría proporcionarle una muestra de trabajo webpack.config.js
Rizwan Patel
2
@bobbaluba, puede especificar el cargador en el fichero de configuración: loaders: [ { test: /\.json$/, loader: 'json' } ]. { test: /\.json$/, loader: 'json' }agrega el cargador json para archivos .json, siempre que haya instalado el cargador.
Jake
1
Tenga en cuenta que si intenta estar SECO aquí escribiendo una función que lo llame require.context(...)(por ejemplo, si está tratando de requerir todo en varias carpetas), webpack lanzará una advertencia. Los argumentos require.contextdeben ser constantes en tiempo de compilación.
Isaac Lyman
3
@ Joel npmjs.com/package/require-context fue creado en 2017 y mi respuesta es a partir de 2015, por lo que es difícil decir que se toma directamente desde allí. También tenga en cuenta que require-contextes un envoltorio webpack, y su muestra se toma de webpackla documentación de webpack.js.org/guides/dependency-management/#context-module-api , que se agregó en 2016 (en github.com/webpack/ webpack.js.org/commit/… ), también después de que escribí mi respuesta ... Tal vez los escritores de webpack fueron influenciados por mi respuesta. Tenga en cuenta que lo expandieron para tener caché.
splintor
38

En el archivo de mi aplicación terminé poniendo el require

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

cortesía de esta publicación: https://github.com/webpack/webpack/issues/118

Ahora está agregando todos mis archivos. Tengo un cargador para html y css y parece funcionar muy bien.

Pollo
fuente
27
¿Qué hay expren este ejemplo?
twiz
2
expres una ruta a un solo archivo dentro de la carpeta de contexto. así que si necesita hacer esto no solo para requerir todos los archivos html, esto es útil. webpack.github.io/docs/context.html#context-module-api
mkoryak
18
Todavía no me exprqueda claro qué está haciendo el argumento basado aquí, incluso después de mirar los documentos del paquete web. ¿Qué significa "hacer esto no solo para requerir todos los archivos html"? gracias
mikkelrd
3
Tengo no detectada ReferenceError: expr no está definido . ¿Alguna pista sobre eso?
CSchulz
2
Todavía no hay respuesta sobre lo que exprsignifica aquí
wizulus
5

¿Qué tal un mapa de todos los archivos en una carpeta?

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

Hacer esto:

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
fuente
Gracias por dejar caer este ejemplo. Usé map simplemente devolví el valor que cada uno de mis archivos exportó =).
cacoder
1

Ejemplo de cómo obtener un mapa de todas las imágenes de la carpeta actual.

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
fuente
1

Todos los méritos para @splintor (gracias).

Pero aquí está mi propia versión derivada.

Beneficios:

  • Los módulos que se exportan se agrupan en un {module_name: exports_obj}objeto.
    • module_name se crea a partir de su nombre de archivo.
    • ... sin extensión y reemplazando barras inclinadas por guiones bajos (en caso de escaneo de subdirectorios).
  • Se agregaron comentarios para facilitar la personalización.
    • Es decir, es posible que desee no incluir archivos en subdirectorios si, por ejemplo, están allí para ser requeridos manualmente para módulos de nivel raíz .

EDITAR: Si, como yo, está seguro de que sus módulos no devolverán nada más que (al menos en el nivel raíz) un objeto javascript normal, también puede "montarlos" replicando su estructura de directorio original (consulte Código (Versión profunda) ) sección al final).

Código (versión original):

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

Ejemplo:

Salida de muestra para eventual console.log(allModules);:

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

Árbol de directorio:

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

Código (versión profunda):

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

Ejemplo:

Resultado del ejemplo anterior usando esta versión:

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

esto funciona para mi:

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

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

NOTA: esto puede requerir archivos .js en subdirecciones de ./js/ de forma recursiva.

jack largo
fuente