Estoy haciendo la transición de una aplicación heredada a Webpack. Estoy usando Webpack 5.56 (último en el momento de escribir este artículo).
Mi aplicación está localizada y tengo una carpeta con varios archivos de configuración regional,
locales - locale.en.ts - locale.de.ts - etc Cada uno de estos archivos de configuración regional es un módulo ES y todos exportan (diferentes implementaciones de) las mismas funciones: getText , printNumber , etc. Tengo un módulo contenedor que import dinámicamente la configuración regional correcta para el usuario actual:
// localization.ts interface LocaleModule { getText(text: string): string; // etc } let module: LocaleModule; import(`locales/locale.${currentUser.language}`).then(m => { module = m; }); export function getText(text: string): string { return module.getText(text); } Conozco el idioma del usuario actual cuando se muestra la página. Quiero incluir el script locale.*.js correcto como fragmento inicial, de modo que:
localization.ts pueden ser síncronas. Parecía que encajaría bien conwebpackMode: "weak" , ya que me gustaría obtener un error en la consola si falta el archivo de locale por cualquier motivo (en lugar de degradar silenciosamente el rendimiento). Los documentos parecen llamar explícitamente mi caso de uso:
Esto es útil para la representación universal cuando los fragmentos requeridos siempre se entregan manualmente en las solicitudes iniciales (incrustados en la página).
Aquí está mi código:
let module: LocaleModule; import( /* webpackMode: "weak" */ /* webpackChunkName: "locales/[request]" */ `./locales/locale.${currentUser.language}` ).then(m => { module = m; }); Sin embargo, parece que webpackMode: "weak" hace que Webpack no emita fragmentos para los módulos a los que se hace referencia . No hay ningún archivo de locale en la carpeta de salida de Webpack. ¡No puedo incluir un fragmento en el HTML si nunca se emitió!
¿Cuál es la razón de este comportamiento? ¿Hay una manera limpia de hacer que Webpack emita fragmentos para import módulos de edición dinámicamente pero no descargarlos de forma asíncrona? (Sé que podría usar webpackMode: "lazy" y simplemente incluir el fragmento por adelantado en una etiqueta de secuencia de comandos, pero me gustaría obtener un error si falta el archivo de configuración regional). ¿O tengo un problema XY y hay ¿Alguna forma mejor de hacer esto que desconozco?
Para usar weak , ya debe servir manualmente los fragmentos como se indica en los documentos. Esto significa que agregarlo en una importación dinámica como comentario no crea ningún fragmento (en contradicción con lazy y lazy-once ).
¿Existe una forma limpia de hacer que Webpack emita fragmentos para módulos importados dinámicamente pero no los descargue de forma asíncrona?
Para carga síncrona:
Tu también puedes:
webpackMode: "lazy" e incluya el fragmento por adelantado en una etiqueta de secuencia de comandos como indicó (la Promise devuelta se rechaza en caso de que falte un fragmento).Para su ejemplo, crear un punto de entrada para cada configuración regional podría ser algo como:
const glob = require('glob') module.exports = { devtool: false, entry: { ...glob.sync('./src/locales/*').reduce((acc, module) => { const name = module.replace('./src/locales/', '').replace('.js', '') acc[name] = module return acc }, {}) } }; Esto emitiría locale.de.js y locale.en.js y luego debería cargar manualmente un <script defer src="locale.<locale>.js"></script> , pero eso depende de cómo sirva tu aplicación
Para carga asíncrona:
Puede usar webpackMode: "lazy" junto con webpackPreload: true para desacoplar las solicitudes de fragmentos main y locale . Como se indica en los documentos
Un fragmento precargado comienza a cargarse en paralelo al fragmento principal.
No puedo publicar un comentario tan largo, así que tiene que ser una respuesta...
Entonces parece que no hay un vínculo real entre los módulos y el paquete no puede resolverlos en tiempo de compilación para que no se emitan. Lo único que cambié en su código es cómo se importan los módulos y funcionó de inmediato:
const langCode = getLangCode(); let mod; import("./locales/locale.en") switch (langCode) { case "en": import(`./locales/locale.en.js`).then(m => { mod = m; console.log("loaded locale"); }) break; case "de": import(`./locales/locale.de.js`).then(m => { mod = m; console.log("loaded locale"); }) break; default: } export function getText(text) { return mod.getText(text); } function getLangCode() { return "de"; } Sé que el cambio de caso no es ideal, pero el paquete no puede adivinar automáticamente ese patrón: ./locales/locale.${langCode}.js y agregar todos los archivos en el directorio que coincidan con .js .
El documento dice lo siguiente:
'débil': intenta cargar el módulo si la función del módulo ya se ha cargado de alguna otra manera (por ejemplo, otro fragmento lo importó o se cargó un script que contiene el módulo). Todavía se devuelve una Promesa, pero solo se resuelve correctamente si los fragmentos ya están en el cliente. Si el módulo no está disponible, se rechaza la Promesa. Nunca se realizará una solicitud de red. Esto es útil para la representación universal cuando los fragmentos requeridos siempre se entregan manualmente en las solicitudes iniciales (incrustados en la página), pero no en los casos en que la navegación de la aplicación activará una importación que no se realizó inicialmente.
Por lo que entiendo, esto significa que se espera que los fragmentos ya estén en la página y se generen a través de otros medios.
Espero que eso te ayude a resolver tu problema.