Extracto del paquete web

1. El concepto de paquete web

       Esencialmente, webpack es un paquete de módulos estáticos para aplicaciones JavaScript modernas . Cuando webpack procesa una aplicación, crea internamente un gráfico de dependencia a partir de uno o más puntos de entrada y luego combina cada módulo que necesita en su proyecto en uno o más paquetes, que son recursos estáticos para mostrar su contenido.
       A partir de la versión 4.0.0, webpack puede empaquetar proyectos sin introducir un archivo de configuración . Sin embargo, sigue siendo altamente configurable y puede satisfacer sus necesidades.
Es necesario comprender algunos conceptos básicos antes de comenzar:

  • entrada
  • producción
  • cargador
  • enchufar
  • modo
  • compatibilidad del navegador
  • ambiente

1.1 Entrada

       El punto de entrada indica qué módulo webpack debe usar como punto de partida para construir su gráfico de dependencia interno . Después de ingresar el punto de entrada, webpack descubrirá qué módulos y bibliotecas son las dependencias del punto de entrada (directa e indirecta).
       El valor predeterminado es ./src/index.js, pero puede especificar uno (o más) puntos de entrada diferentes configurando la propiedad de entrada en la configuración del paquete web. Por ejemplo:

webpack.config.js

module.exports = {
    
    
  entry: './path/to/my/entry/file.js',
};

1.2, salida (salida)

       El atributo de salida le dice al paquete web dónde generar el paquete que crea. y cómo nombrar estos archivos. El valor predeterminado para el archivo de salida principal es "./dist/main.js", y otros archivos generados se colocan en la carpeta "./dist.js" de forma predeterminada.
       Puede configurar estos procesos especificando un campo de salida en la configuración:

webpack.config.js

const path = require('path')

module.exports = {
    
    
  entry: './path/to/my/entry/file.js',
  output: {
    
    
    path: path.resolve(__dirname, 'dist'), // bundle生成(emit)到哪里
    filename: 'my-first-webpack.bundle.js', // 告诉webpack bundle的名称
    ……
  }
}

1.3, cargador

       webpack solo puede comprender archivos JavaScript y JSON, que es una capacidad integrada de webpack disponible de forma inmediata. El cargador permite que webpack procese otros tipos de archivos y los convierta en válidos.plantilla, para ser utilizado por la aplicación y agregado al gráfico de dependencia.

Una de las potentes funciones de Warnig
webpack es la capacidad de importar cualquier tipo de plantilla (como archivos .css), que pueden no ser compatibles con otros empaquetadores o ejecutores. Creemos que esta extensión del lenguaje es necesaria porque permite a los desarrolladores crear gráficos de dependencia más precisos.

En un nivel alto, en la configuración del paquete web, el cargador tiene dos propiedades:

  1. pruebaatributo, que identifica qué archivos se convertirán.
  2. usarAtributo que define qué cargador se debe usar al hacer la conversión.

webpack.config.js

moudle.exports = {
    
    
  output: {
    
    
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    
    
    rules: [{
    
    test:/\.txt$/, use: 'raw-loader'}]
  }
}

En la configuración anterior, se define un solo objeto de módulonormasAtributo, que contiene dos atributos obligatorios: prueba y uso. Dígale al compilador del paquete web (compilador) la siguiente información:

Cuando se analiza como una ruta .txt en una instrucción require()/import, conviértalo con use (use) raw-loader antes de empaquetarlo.

Advertencia
Importante: Al definir reglas en la configuración del paquete web, defínalas en module.rules en lugar de reglas. Para que te resulte más fácil de entender, webpack te avisará si no lo haces de la forma correcta.

Advertencia
Cuando haga coincidir un archivo con una expresión regular, no lo encierre entre comillas.. Es decir, /.txt/ y '/t ˙ xt/ y '/\.txt/ con /t˙ xt/' o "/.txt$/" no son lo mismo. El primero le indica a webpack que coincida con cualquier archivo que termine en .txt, el segundo le indica a webpack que coincida con un solo archivo con una ruta absoluta '.txt'; esto puede no ser lo que pretendía.

1.4, complemento (complemento)

       Los cargadores se usan para transformar ciertos tipos de módulos, mientras que los complementos se pueden usar para realizar una gama más amplia de tareas. Incluyendo: optimización de packaging, gestión de recursos, inyección de variables de entorno, etc.
       Para usar un complemento, solo necesita () y agregarlo a la matriz de complementos. La mayoría de los complementos se pueden personalizar a través de opciones. También puede usar el mismo complemento varias veces para diferentes propósitos en un archivo de configuración. En este caso, necesita crear una instancia de complemento usando el operador new.

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack') // 用于访问内直插件

module.exports = {
    
    
  module: [{
    
    test: /\.txt$/, use: 'raw-loader'}],
  plugins: [new HtmlWebpackPlugin({
    
    template: './src/index.html'})]
}

En el ejemplo anterior, html-webpack-plugin genera un archivo HTML para la aplicación e inyecta automáticamente todos los paquetes generados en este archivo.

1.5, modo (modo)

       Al establecer el parámetro de modo en uno de desarrollo, producción o ninguno, puede habilitar las optimizaciones integradas en el paquete web para ese entorno. Su valor por defecto es la producción.

module.exports = {
    
    
  mode: 'production',
}

1.6 Compatibilidad del navegador

       Webpack es compatible con todos los navegadores compatibles con ES5 (IE8 y anteriores no son compatibles).
       import() y require.ensure() de webpack requieren una Promesa. Si desea admitir navegadores más antiguos, precargue el polyfill antes de usar estas expresiones.

1.7, medio ambiente (entorno)

Webpack5 se ejecuta en Node.js v10.13.0+

2. Puntos de entrada

2.1 Sintaxis de entrada única (taquigrafía)

Uso: entrada: cadena | [cadena]
webpack.config.js

module.exports = {
    
    
  entry: './path/to/my/entry/file.js'
}

La sintaxis de entrada única para el atributo de entrada es una forma abreviada de:

module.exports = {
    
    
  entry: {
    
    
    main: './path/to/my/entry/file.js'
  }
}

También es posible pasar una matriz de rutas de archivo al atributo de entrada, lo que creará una llamada 'entrada principal múltiple'. Esto es útil cuando desea inyectar varios archivos dependientes a la vez y mapear sus dependencias en un 'fragmento'.

module.exports = {
    
    
  entry: ['./src/file_1.js', './src/file_2.js'],
  output: {
    
    
    filename: 'bundle.js',
  },
};

2.2, sintaxis de objetos

uso:

entry: {
    
     <entryChunkName> string | [string] } | {
    
    }
module.exports = {
    
    
  entry: {
    
    
    app: './src/app.js',
    adminApp: './src/adminApp.js'
  }
}

La sintaxis de objetos puede ser engorrosa. Sin embargo, esta es la forma más escalable de definir entradas en una aplicación.

Sugerencia
" Extensibilidad de las configuraciones del paquete web " significa que estas configuraciones se pueden reutilizar y combinar con otras configuraciones. Esta es una técnica popular para separar las preocupaciones del entorno, el objetivo de compilación y el tiempo de ejecución. Estos luego se fusionan utilizando herramientas especializadas como webpack-merge.

"Consejo"
Cuando genera una entrada a través de un complemento, puede pasar un objeto vacío {} a la entrada.

2.2.1 Objetos que describen la entrada

Objeto utilizado para describir la entrada. Puede utilizar las siguientes propiedades:

  • dependOn: la entrada de la que depende la entrada actual. Deben cargarse antes de cargar la entrada.
  • import: módulos que deben cargarse al inicio.
  • biblioteca: especifique la opción de biblioteca para crear una biblioteca para la entrada actual.
  • tiempo de ejecución: el nombre del fragmento en tiempo de ejecución. Si se establece, se crea un nuevo fragmento de tiempo de ejecución. Esto se puede establecer en falso después del paquete web 5.43.0 para evitar un nuevo fragmento de tiempo de ejecución.
  • publicPath: cuando se hace referencia a los archivos de salida de esta entrada en el navegador, especifique una dirección URL pública para ellos. Ver salida.publicPath.
    module.exports = {
          
          
      entry: {
          
          
        a2: 'dependingfile.js',
        b2: {
          
          
          dependOn: 'a2',
          import: './src/app.js'
        }
      }
    }
    
    runtime y dependOn no deben usarse en la misma entrada, por lo que la siguiente configuración no es válida y se generará un error:
    module.exports = {
          
          
      entry: {
          
          
        a2: './a',
        b2: {
          
          
          runtime: 'x2',
          dependOn: 'a2',
          import: './b',
       },
     },
    };
    
    Asegúrese de que el tiempo de ejecución no pueda apuntar a un nombre de entrada existente, por ejemplo, la siguiente configuración generará un error:
    module.exports = {
          
          
      entry: {
          
          
        a1: './a',
        b1: {
          
          
          runtime: 'a1',
          import: './b'
        }
      }
    }
    
    Además, no se puede hacer referencia circular a dependOn y también se producirán errores en el siguiente ejemplo:
    module.exports = {
          
          
      entry: {
          
          
        a3: {
          
          
          import: './a',
          dependOn: 'b3',
        },
        b3: {
          
          
          import: './b',
          dependOn: 'a3'
        }
      }
    }
    

2.3 Escenarios comunes

Algunas configuraciones de entrada y sus casos prácticos de uso se enumeran a continuación:

2.3.1 Entradas separadas de aplicaciones y proveedores (biblioteca de terceros)

// webpack.config.js
module.exports = {
    
    
  module.exports = {
    
    
    entry: {
    
    
      main: './src/app.js',
      vendor: './src/vendor.js',
    }
  }
}

// webpack.prod.js
module.exports = {
    
    
  output: {
    
    
    filename: '[name].[contenthash].bundle.js,
  }
}

// webpack.dev.js
module.exports = {
    
    
  module.exports = {
    
    
    filename: '[name].bundle.js'
  }
}

Esto le dice a webpack que queremos configurar 2 puntos de entrada separados (como el ejemplo anterior).
De esta manera, las bibliotecas o archivos necesarios (como Bootstrap, JQuery, imágenes, etc.) que no se han modificado se pueden almacenar en vendor.js y luego se empaquetan juntos en un fragmento separado. Los hashes de contenido siguen siendo los mismos, lo que permite que los navegadores los almacenen en caché de forma independiente, lo que reduce los tiempos de carga.

Sugerencia
Esto no se recomienda en webpack < 4, por lo general, el proveedor se agrega como un punto de entrada separado a la opción de entrada para compilarlo en un solo archivo (junto con CommonsChunkPlugin).
Esto no se recomienda en el paquete web 4. En su lugar, use la opciónoptimization.splitChunks para separar los módulos del proveedor y de la aplicación y cree un archivo separado para ellos. No cree una entrada para el proveedor u otro que no sea el punto de partida de la ejecución.

2.3.2 Solicitud multipágina

module.exports = {
    
    
  entry: {
    
    
    pageOne: './src/pageone/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
}

Le dice a webpack que espere tres gráficos de dependencia separados (como el ejemplo anterior).
Motivo : en una aplicación de varias páginas, el servidor extraerá un nuevo documento HTML para su cliente. La página se vuelve a cargar con este nuevo documento y los recursos se vuelven a descargar. Sin embargo, esto nos brinda oportunidades especiales para hacer cosas como usar la optimización.splitChunks para crear paquetes para el código de la aplicación que se comparte entre las páginas. Debido a la mayor cantidad de puntos de entrada, las aplicaciones de varias páginas pueden beneficiarse enormemente de estas técnicas al poder reutilizar grandes cantidades de código/módulos en múltiples puntos de entrada.

Como regla general: use solo un punto de entrada por documento HTML.

3. salida

Puede configurar la opción de salida para decirle al paquete web cómo escribir archivos compilados en el disco duro. Tenga en cuenta que solo se puede especificar una configuración de salida, aunque puede haber varios orígenes de entrada.

3.1 Uso

En la configuración del paquete web, el requisito mínimo para la propiedad de salida es establecer su valor en un objeto y luego configurar el nombre del archivo de salida como output.filename:

module.exports = {
    
    
  output: {
    
    
    filename: 'bundle.js'
  }
}

Esta configuración genera un único archivo bundle.js en el directorio dist.

3.2 Múltiples puntos de entrada

Si se crea más de un "fragmento" en la configuración (por ejemplo, al usar varios puntos de entrada o al usar un complemento como CommonsChunkPlugin), se deben usar sustituciones para garantizar que cada archivo tenga un nombre único.

module.exports = {
    
    
  entry: {
    
    
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    
    
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}
// 写入到硬盘:./dist/app.js, ./dist/search.js

3.3 Avanzado Avanzado

Aquí hay un ejemplo complejo usando CDN y hash para recursos:
config.js

module.exports = {
    
    
  output: {
    
    
    path: '/home/proj/cdn/assets/[fullhash]',
    publicPath: 'https://cdn.example.com/assets/[fullhash]'
  }
}

Si no sabe cuál es la dirección publicPath del archivo de salida final en el momento de la compilación, puede dejarlo en blanco y configurarlo dinámicamente en tiempo de ejecución a través de __webpack_public_path__ en el archivo de punto de entrada.

__webpack_public_path__ = myRuntimePublicPath

4, cargador

El cargador se utiliza para convertir el código fuente del módulo. Los cargadores le permiten preprocesar archivos al importar o "cargar" módulos. Por lo tanto, los cargadores son similares a las "tareas" en otras herramientas de compilación y brindan una forma poderosa de manejar los pasos de compilación de front-end. Los cargadores pueden convertir archivos de diferentes idiomas (como TypeScript) a JavaScript o convertir imágenes en línea a URL de datos. ¡El cargador incluso le permite importar archivos CSS directamente en plantillas de JavaScript!

4.1 Ejemplos

Por ejemplo, puede usar cargadores para decirle a webpack que cargue archivos css o que convierta TypeScript a JavaScript. Para hacer esto, primero instale el cargador correspondiente:

npm install --save-dev css-loader ts-loader

Luego indique a webpack que use css-loader para cada archivo .css y ts-loader para todos los archivos .ts:
webpack.config.js

module.exports = {
    
    
  module: {
    
    
    rules: [
      {
    
     test: /\.css$/, use: 'css-loader'},
      {
    
     test: /\.ts$/, use: 'ts-loader'}
    ]
  }
}

4.2 Usar cargadores

En su aplicación, hay dos formas de usar los cargadores:

  • método de configuración(Recomendado): especifique el cargador en el archivo webpack.config.js.
  • método en línea: muestra el cargador especificado en cada declaración de importación.
    Tenga en cuenta que los cargadores estaban disponibles a través de la CLI en webpack v4, pero están obsoletos en webpack v5.

4.3、Configuración

module.rules le permite especificar múltiples cargadores en la configuración de su paquete web. Este enfoque es una forma concisa de presentar cargadores y ayuda a mantener el código limpio y mantenible. Al mismo tiempo, le permite tener una descripción general de cada cargador:
los cargadores se ejecutan de derecha a izquierda , comenzando con sass-loader, luego continúan con la ejecución de css-loader y finalmente terminan con style-loader.

module.exports = {
    
    
  module: {
    
    
    rules: [{
    
    
      test: /\.css$/,
      use: [
        {
    
     loader: 'style-loader'},
        {
    
     
          loader: 'css-loader',
          options: {
    
    
            modules: true,
          }
        },
        {
    
     loader: 'sass-loader' }
      ]
    }]
  }
}

4.4 Modo en línea

El cargador se puede especificar en la declaración de importación o cualquier referencia equivalente al método de importación. ¡usar! Separe los cargadores de los recursos. Cada parte será equivalente a la resolución del directorio actual.

import Styles from 'style-loader!css-loader?modules!./styles.css';

Todos los cargadores, precargadores y postcargadores en la configuración se pueden anular anteponiendo las declaraciones de importación en línea:

  • ¡usar! prefijo, deshabilitará todos los cargadores normales configurados (cargadores normales)
import Styles from '!style-loader!css-loader?modules!./styles.css'
  • ¡usar! ! prefijo, deshabilitará todos los cargadores configurados (precargador, cargador, postcargador)
import Styles from '!!style-loader!css-loader?modules!./styles.css'
  • El uso del prefijo -! deshabilitará todos los precargadores y cargadores configurados, pero no los postcargadores
import Styles from '-!style-loader!css-loader?modules!./styles.css'

Las opciones pueden pasar parámetros de consulta como ? key=value&foo=bar, o un objeto JSON como ? {'clave': 'valor', 'foo': 'barra'}

Sugerencia
Use module.rules tanto como sea posible, ya que esto puede reducir la cantidad de código repetitivo en el código fuente y puede depurar y localizar problemas en el cargador más rápido cuando ocurren errores.

4.5, características del cargador

  • El cargador admite llamadas en cadena. Cada cargador de la cadena aplicará la transformación al recurso procesado. Un conjunto de cargadores encadenados se ejecutará en orden inverso. El primer cargador de la cadena pasa su resultado (es decir, el recurso con la transformación aplicada) al siguiente cargador, y así sucesivamente. Finalmente, el último cargador de la cadena, devuelve el Javascript que espera el paquete web.
  • Los cargadores pueden ser síncronos o asíncronos.
  • El cargador se ejecuta en Node.js y puede realizar cualquier operación.
  • El cargador se puede configurar a través del objeto de opciones (el parámetro de consulta todavía se admite para establecer opciones, pero este método ha quedado obsoleto).
  • Además del principal común de package.json para exportar módulos npm como cargadores, también puede usar el campo de cargador en module.rules para hacer referencia directa a un módulo.
  • Los complementos (complementos) pueden traer más funciones al cargador.
  • El cargador puede generar archivos arbitrarios adicionales.

La función de preprocesamiento del cargador puede proporcionar más capacidades para el ecosistema de JavaScript. Los usuarios ahora tienen más flexibilidad para introducir lógica detallada, como compresión, empaquetado, traducción de idiomas (o compilación) y muchas más características.

4.6 Analizar el cargador

El cargador sigue las reglas de resolución de módulos estándar. En la mayoría de los casos, el cargador se cargará desde la ruta del módulo (generalmente desde npm install, node_modules).
Esperamos que el módulo del cargador se exporte como una función y se escriba como Javascript compatible con Node.js. Por lo general, npm se usa para administrar cargadores, pero también es posible usar archivos en la aplicación como cargadores personalizados. Según las normas, los cargadores suelen denominarse xxx-loader (p. ej., json-loader).

5, complemento

Los complementos son la columna vertebral de webpack. Webpack en sí está construido sobre el mismo sistema de complementos que usa en la configuración de su paquete web .

El propósito del complemento es resolver otras cosas que el cargador no puede lograr. webpack proporciona muchos complementos listos para usar.

Sugerencia
Si usa el paquete webpack-sources en el complemento, use require('webpack').source en lugar de require('webpack-source') para evitar conflictos de versión de caché persistentes.

5.1 Análisis

Un complemento de paquete web es un objeto Javascript con un método de aplicación. El método de aplicación será llamado por el compilador del paquete web y se podrá acceder al objeto del compilador durante todo el ciclo de vida de la compilación.

ConsoleLogOnBuildWebpackPlugin.js

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
    
     
  apply(compiler) {
    
    
    compiler.hooks.run.tap(pluginName, (compilation) => {
    
    
      console.log('webpack 构建正在启动');
    })
  }
}

module.exports = ConsoleLogOnBuildwebpackPlugin;

El primer parámetro del método tap del gancho del compilador debe ser el nombre del complemento en caso de camello. Se recomienda usar una constante para esto, de modo que pueda reutilizarse en todos los ganchos.

5.2 Uso

Dado que los complementos pueden llevar parámetros/opciones, debe pasar una nueva instancia a la propiedad de complementos en la configuración de su paquete web.

Dependiendo del uso de su paquete web, hay varias formas de usar los complementos.

5.3 Método de configuración

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');

module.exports = {
    
    
  entry: './path/to/my/entry/file.js',
  output: {
    
    
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    
    
    rule: [
      {
    
    
        test: /\.(js|jsx)$/,
        use: 'bable-loader',
      }
    ]
  },
  plugins: [
    new webpack.ProgressPlugin(),
    new HtmlWebpackPlugin({
    
     tempalte: './src/index.html'})
  ]
}

ProgressPlugin se usa para personalizar el informe de progreso durante el proceso de compilación. HtmlWebpackPlugin generará un archivo HTML y usará un script para introducir un archivo JS llamado my-first-webpack.bundle.js en él.

5.4 Método API de nodo

Al usar la API de nodo, también puede pasar complementos a través del atributo de complementos en la configuración.
algún-nodo-script.js

const webpack = require('webpack'); // 访问webpack运行时(runtime)
const configuration = require('./webpack.config.js')

let compiler = webpack('configuration');

new webpack.ProgressPlugin().apply(compiler)

compiler.run(function(err, stats) {
    
    
  // ...
})

6. Configuración

Ejemplo de configuración en línea: https://createapp.dev/webpack/no-library–html-webpack-plugin

Es posible que haya notado que muy pocas configuraciones de paquetes web se ven exactamente iguales. Esto se debe a que el archivo de configuración del paquete web es un archivo Javascript y se exporta un objeto de configuración del paquete web en el archivo. webpack se procesará de acuerdo con las propiedades definidas por esta configuración.

Dado que webpack sigue la especificación de la plantilla Commonjs, puede usar en la configuración:

  • Introducir otros archivos a través de require(...)
  • Use las funciones de utilidad descargadas por npm a través de require(…)
  • Utilice expresiones de flujo de control de Javascript como ? : operador
  • Utilice la asignación constante o variable para el valor
  • Escribir y ejecutar funciones para generar una configuración parcial

Utilice estas funciones en los escenarios apropiados.

Si bien es técnicamente posible, se debe evitar lo siguiente :

  • Cuando use la herramienta CLI del paquete web, acceda a los argumentos de la CLI (debe escribir su propia herramienta CLI en su lugar o usar --dev)
  • exportar resultados indeterminados (dos llamadas a webpack deberían producir el mismo archivo de salida)
  • Escriba una configuración larga (el archivo de configuración debe dividirse en varios)

Sugerencia
La conclusión más importante de esta documentación es que la configuración del paquete web puede tener muchos estilos y sabores diferentes. El punto es que para que estas configuraciones sean fáciles de mantener y comprender, deben ser consistentes dentro del equipo.

En el siguiente ejemplo, se muestra cómo la configuración del paquete web se puede expresar y configurar de manera flexible, lo que se debe principalmente al hecho de que la configuración es un código:

6.1 Configuración básica

webpack.config.js

const path = require('path');
module.exports = {
    
    
  mode: 'development',
  entry: './foo.js',
  output: {
    
    
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js',
  }
}

6.2, objetivos múltiples

Además de exportar una única configuración como objeto, función o Promesa, también es posible exportarla como múltiples configuraciones.

6.3 Usar otros lenguajes de configuración

Webpack admite archivos de configuración escritos en una variedad de lenguajes de datos y programación.

7. Módulos

En la programación modular, los desarrolladores descomponen un programa en fragmentos funcionalmente discretos, a los que llaman módulos .

Cada módulo tiene un tamaño más pequeño que un programa completo, lo que hace que la verificación, la depuración y las pruebas sean muy sencillas. Los módulos bien escritos proporcionan sólidos límites de encapsulación y abstracción, de modo que cada módulo de la aplicación tenga un diseño coherente y un propósito claro.

Node.js ha soportado la programación modular desde el principio. Sin embargo, la modularización de la web se está apoyando lentamente. Hay varias herramientas que admiten la modularización de Javascript en el mundo web, y cada una de estas herramientas tiene ventajas y limitaciones. Webpack toma lecciones aprendidas de estos sistemas y aplica el concepto de módulos a cualquier archivo en un proyecto.

7.1 ¿Qué es un módulo webpack?

En comparación con los módulos de Node.js, los módulos de paquete web pueden expresar sus dependencias de varias maneras. Aquí hay unos ejemplos:

  • Declaración de importación ES2015
  • Declaración de CommonJS require ()
  • AMD define y requiere declaraciones
  • declaraciones @import en archivos css/sass/less
  • hoja de estilo url(…) o HTML img src=… enlace a una imagen en el archivo.

7.2 Tipos de módulos compatibles

Webpack admite de forma nativa los siguientes tipos de módulos:

  • Módulo ECMAScript
  • Módulos CommonJS
  • Módulo AMD
  • Activos
  • Módulo de ensamblaje web

A través del cargador, el paquete web puede admitir módulos escritos en varios idiomas y sintaxis de preprocesador. El cargador describe al paquete web cómo manejar módulos no nativos e introduce las dependencias relevantes en sus paquetes. La comunidad de paquetes web ha creado cargadores para una variedad de lenguajes y preprocesadores populares, que incluyen:

  • CaféScript
  • Mecanografiado
  • ESNext(Bable)
  • Hablar con descaro a
  • Menos
  • Aguja
  • Olmo

En general, webpack proporciona una API personalizable, potente y rica que permite su uso en cualquier pila de tecnología, al tiempo que admite flujos de trabajo no intrusivos en entornos de desarrollo, prueba y producción.

8. Resolución del módulo

resolver es una biblioteca que ayuda a encontrar la ruta absoluta de un módulo. Un módulo se puede utilizar como módulo dependiente de otro módulo, y luego ser referenciado por este último, de la siguiente manera:

import foo from 'path/to/module';
// 或者
require('path/to/module'

Un módulo dependiente puede ser código de una aplicación o una biblioteca de terceros. El resolutor ayuda a webpack a encontrar el código del módulo que debe introducirse en el paquete de cada instrucción require/import. Al agrupar módulos, el paquete web usa resolución mejorada para resolver rutas de archivos.

8.1 Reglas de análisis en webpack

Usando resolución mejorada, webpack puede resolver tres rutas de archivo:
ruta absoluta

import '/home/me/file';
import 'c:\\Users\\me\\file';

Dado que se ha obtenido la ruta absoluta del archivo, no se requiere más análisis.
camino relativo

import '../src/file1';
import './file2';

En este caso, el directorio donde se encuentra el archivo de origen usando import o require se considera como el directorio de contexto, y la ruta relativa proporcionada en import/require se empalmará con esta ruta de contexto para generar la ruta absoluta del módulo.
ruta del módulo

import 'module';
import 'module/lib/file';

Recupere módulos en todos los directorios especificados en resolve.modules. Puede reemplazar la ruta del módulo inicial configurando un alias, consulte la opción de configuración resolve.alias para obtener más detalles.

  • Si el paquete contiene un archivo package.json, los campos especificados en la opción de configuración resolve.exportsFields se buscarán a su vez, y el primer campo en package.json confirmará la exportación disponible en el paquete de acuerdo con la especificación de exportación del paquete.

Una vez que la ruta se resuelve de acuerdo con las reglas anteriores, la resolución verificará si la ruta apunta a un archivo o una carpeta. Si la ruta apunta a un archivo:

  • Si el archivo tiene una extensión, el archivo se empaqueta directamente.
  • De lo contrario, las extensiones de archivo se resolverán mediante la opción resolve.extensions, que le dice al analizador qué extensiones son aceptables (p. ej., .js, .jsx).

Si la ruta apunta a una carpeta, proceda de la siguiente manera para encontrar un archivo con la extensión correcta:

  • Si la carpeta contiene un archivo package.json, se buscará según el orden de los campos en la configuración de resolve.mainFields
    y la ruta del archivo se determinará según el primer campo en package.json que cumpla con los requisitos de configuración.
  • Si no hay un archivo package.json o resolve.mainFields no devuelve una ruta válida, buscará de acuerdo con el orden de nombre de archivo especificado en la opción de configuración resolve.mainFiles para ver si un nombre de archivo existente puede coincidir en la importación/ requiere directorio.
  • Luego, las extensiones de archivo se resuelven de manera similar utilizando la opción resolve.extensions.

Webpack proporciona valores predeterminados sensibles para estas opciones, según el objetivo de compilación.

8.2 Análisis del cargador

Las reglas de análisis del cargador también siguen especificaciones específicas. Pero el elemento de configuración resolveLoader puede establecer reglas de análisis independientes para el cargador.

8.3 Almacenamiento en caché

Cada acceso del sistema de archivos a un archivo se almacena en caché, lo que permite una activación más rápida de múltiples solicitudes paralelas o en serie para el mismo archivo. En el modo de observación, solo los archivos modificados se eliminan de la memoria caché. Si el modo de observación está desactivado, la memoria caché se borrará antes de cada compilación.

9, Federación de módulos

9.1 Motivación

Varias compilaciones independientes pueden componer una aplicación, no debe haber dependencias entre estas compilaciones independientes, por lo que se pueden desarrollar e implementar de forma independiente.

9.2, el concepto subyacente

Distinguimos entre módulos locales y módulos remotos. Los módulos locales son módulos normales que forman parte de la compilación actual. Los módulos remotos no forman parte de la compilación actual y se cargan en tiempo de ejecución desde los llamados contenedores.

La carga de un módulo remoto se considera una operación asíncrona. Cuando se utilizan módulos remotos, estas operaciones asíncronas se colocarán en la operación de carga del siguiente fragmento entre el módulo remoto y la entrada. Los módulos remotos no se pueden usar sin una operación de carga de fragmentos.

La carga de fragmentos generalmente se realiza llamando a import(), pero también se admiten sintaxis más antiguas como require.ensure o require([…]) subclases.

Los contenedores se crean con una entrada de contenedor que expone el acceso asíncrono a módulos específicos. El acceso expuesto se divide en dos pasos:

  1. módulo de carga (asincrónicamente)
  2. módulo de ejecución (síncrono)

El paso 1 se realizará durante la carga de fragmentos. El paso 2 se realizará durante la ejecución intercalada con otros módulos (locales y remotos). De esta forma, el orden de ejecución no se ve afectado por la conversión de módulos de local a remoto o de remoto a local.

Los contenedores se pueden anidar y los contenedores pueden usar módulos de otros contenedores. También puede haber dependencias circulares entre contenedores.

9.3 Conceptos avanzados

Cada compilación actúa como un contenedor y también puede tener otras compilaciones como contenedores. De esta forma, cada compilación puede acceder a módulos expuestos por otros contenedores cargando módulos desde el contenedor correspondiente.

Un módulo compartido es un módulo que se puede reescribir y proporciona reescrituras en contenedores anidados. Por lo general, apuntan a los mismos módulos en cada compilación, como las mismas bibliotecas.

La opción packageName permite encontrar la versión requerida configurando el nombre del paquete. De forma predeterminada, infiere automáticamente las solicitudes de módulos, cuando desee deshabilitar la inferencia automática, establezca la versión requerida en falso.

9.4 Bloques de construcción

ContainerPlugin (nivel bajo)
Este complemento utiliza el módulo público especificado para crear una entrada de contenedor adicional.

ContainerReferencePlugin (nivel bajo)
Este complemento agrega referencias específicas a contenedores como elementos externos y permite importar módulos remotos desde estos contenedores. También llama a la API de anulación de estos contenedores para proporcionarles sobrecargas (a través de __webpack__override__ o la API de anulación cuando la compilación también es un contenedor) y la sobrecarga especificada se proporciona a todos los contenedores a los que se hace referencia.

ModuleFederationPlugin (nivel alto)
ModuleFederation组合了ContainerPlugin和ContainerReferencePlugin。

9.5 Objetivos conceptuales

  • Puede exponer y usar cualquier tipo de módulo compatible con webpack.
  • La carga de fragmentos debe cargar todo lo que necesita en paralelo (web: viaje de ida y vuelta único al servidor)
  • Control desde el usuario hasta el contenedor
    • Reescribir módulos es una operación unidireccional
    • Los contenedores hermanos no pueden anular los módulos de los demás
  • El concepto se aplica independientemente del entorno.
    • Disponible para web, Node.js, etc.
  • Solicitudes relativas y absolutas en acciones
    • siempre se proporcionará, incluso si no se utiliza
    • Resolverá la ruta relativa a config.context
    • La versión requerida no se utilizará de forma predeterminada
  • Solicitudes de módulos en Shared
    • solo disponible cuando se usa
    • coincidirá con todas las solicitudes de módulos iguales utilizadas en la compilación
    • proporcionará todos los módulos correspondientes
    • La versión requerida se extraerá de package.json en esta ubicación en el diagrama
    • Se pueden proporcionar y utilizar varias versiones diferentes cuando se han anidado módulos de nodo.
    • Una solicitud de módulo con un final / en un recurso compartido coincidirá con todas las solicitudes de módulo con este prefijo

9.6 Casos de uso

Cada página se construye individualmente.
Cada página de una aplicación de una sola página se expone desde el contenedor en una compilación separada. La aplicación principal (shell de la aplicación) también se crea de forma independiente y hará referencia a todas las páginas como módulos remotos. De esta manera, cada página se puede desplegar individualmente. La aplicación principal se implementa cuando se actualizan las rutas o se agregan nuevas rutas. La aplicación principal define las bibliotecas comunes como módulos compartidos para evitar la duplicación en la creación de páginas.

Bibliotecas de componentes como contenedores
Muchas aplicaciones comparten una biblioteca de componentes común que se puede construir como un contenedor que expone todos los componentes. Cada aplicación utiliza componentes del contenedor de la biblioteca de componentes. Los cambios en las bibliotecas de componentes se pueden implementar individualmente sin volver a implementar todas las aplicaciones. La aplicación utiliza automáticamente la última versión de la biblioteca de componentes.

Contenedores remotos dinámicos
La interfaz del contenedor admite los métodos get e init. init es un método compatible con asíncrono que contiene solo un parámetro cuando se llama: el objeto de ámbito compartido. Este objeto se utiliza como ámbito compartido en el contenedor remoto y se completa con módulos proporcionados por el host. Se puede usar para conectar dinámicamente contenedores remotos a contenedores host en tiempo de ejecución.

(async () => {
    
    
  // 初始化共享作用域(shared scope)用提供的已知此构建和所有远程的模块填充它
  await __webpack_init_sharing__('default');
  const container = window.someContainer; // 或从其他地方获取容器
  // 初始化容器 它可能提供共享模块
  await container.init(__webpack_share_scopes__.default);
  const module = await container.get('./module');
})();

El contenedor intenta proporcionar un módulo compartido, pero advierte si el módulo compartido ya está en uso e ignora el módulo compartido proporcionado. Los contenedores aún pueden usarlo como un módulo de degradación.

Puede implementar pruebas A/B cargando dinámicamente diferentes versiones de un módulo compartido.

Sugerencia
Antes de intentar conectarse dinámicamente a un contenedor remoto, asegúrese de que el contenedor esté cargado.

Ejemplo:
init.js

function loadComponent(scope, module) {
    
    
  return async () => {
    
    
    // 初始化共享作用域(shared scope)用提供的已知此构建和所有远程的模块填充它
    await __webpack_init_sharing__('default');
    const container = window[scope]; // 或从其他地方获取容器
    // 初始化容器 它可能提供共享模块
    await container.init(__webpack_share_scopes__.default);
    const factory = await window[scope].get(module);
    const Module = factory();
    return Module;
  };
}

loadComponent('abtests', 'test123');

9.7, control remoto dinámico basado en Promise

En general, el control remoto se configura usando una URL, los ejemplos son los siguientes:

module.exports = {
    
    
  plugins: [
    new ModuleFederationPlugin({
    
    
      name: 'host',
      remotes: {
    
    
        app1: ''
      }
    })
  ]
}

Pero también puede pasar una promesa al control remoto, que se llamará en tiempo de ejecución. Debe llamar a esta promesa con una plantilla que se ajuste a la interfaz get/init descrita anteriormente. Por ejemplo, si desea pasar qué versión del módulo de federación debe usar, puede hacer algo a través de un parámetro de consulta.

9.8 Ruta pública dinámica

Proporcionar una API de host para configurar publicPath
permite que el host configure publicPath del módulo remoto en tiempo de ejecución al exponer el método del módulo remoto.

Este enfoque es especialmente útil cuando monta aplicaciones secundarias implementadas de forma independiente en rutas secundarias del dominio del host.

Escenario:
tiene una aplicación host en https://my-host.com/app/* y una subaplicación en https://foo-app.com. Las aplicaciones secundarias también se montan en el dominio del host, por lo que se puede acceder a https://foo-app.com a través de https://my-host.com/app/foo-app y https://my-host.com /app/foo-app/* puede redirigir a https://foo-app.com/* a través de un proxy.

Ejemplo:
webpack.config.js (remoto)

module.exports = {
    
    
  entry: {
    
    
    remote: './public-path',
  },
  plugins: [
    new ModuleFederationPlugin({
    
    
      name: 'remote', // 该名称必须与入口名称相匹配
      exposes: ['./public-path'],
      // ...
    }),
  ],
};

public-path.js (remoto)

export function set(value) {
    
    
  __webpack_public_path__ = value;
}

src/index.js (anfitrión)

const publicPath = await import('remote/public-path');
publicPath.set('/your-public-path');

//bootstrap app  e.g. import('./bootstrap.js')

10. Más

https://webpack.docschina.org/

Supongo que te gusta

Origin blog.csdn.net/weixin_44767973/article/details/128230949
Recomendado
Clasificación