acabado del paquete web

Directorio de artículos

Problemas y desarrollo modular tradicional.

Hay muchos módulos en el proyecto y cada módulo es un archivo js. Cuando estos js se cargan en el proyecto, se envían muchas solicitudes http, lo que afecta el rendimiento.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>我的网页</title>
    <!-- <style>
        body {
            background-color: grey;
        }
    </style> -->
    <!--  rel="stylesheet"必须写 -->
    <link href="./test.css" rel="stylesheet">
</head>
<body>
    <h1>我的网页</h1>
    <div id="app">
        <!-- <div>header</div>
        <div>content</div>
        <div>footer</div> -->
    </div>

    <!-- <script src="./test.js"></script> -->

    <script src="./header.js"></script>
    <script src="./content.js"></script>
    <script src="./footer.js"></script>
    <script src="./test.js"></script>
    <!-- 传统模块化开发 -->
    <!-- 多加载了js文件,发送了多次http请求 -->
    <!-- 变量的来源不是很确定  -->
    <!-- 加载顺序问题 -->

    <!-- 现在的模块化开发使用ES6的import export 使用模块 -->
    <!-- 但浏览器不能识别import export -->
    <!-- => webpack 解决以上问题 -->
</body>
</html>
body {
    
    
    background-color: rgb(212, 207, 207);
}
// alert('hello')
const app = document.getElementById('app')

const header = document.createElement('div')
header.innerText='header';
app.appendChild(header)

const content = document.createElement('div')
content.innerText='content';
app.appendChild(content)

const footer = document.createElement('div')
footer.innerText='footer';
app.appendChild(footer)

/***
 * 以上就是面向过程编程,所有的代码都写在一个js文件里面,
 * 对以后项目的维护,功能的扩展都不是很友好
 * 
 * => 面向对象编程
 * 
 */

new Header();
new Content();
new Footer();

//  header.js
function Header(){
    
    
    const header = document.createElement('div')
    header.innerText='header';
    app.appendChild(header)
}
// content.js
function Content(){
    
    
    const content = document.createElement('div')
    content.innerText='content';
    app.appendChild(content)
}
// footer.js
function Footer(){
    
    
    const footer = document.createElement('div')
    footer.innerText='footer';
    app.appendChild(footer) 
}

entrada y salida del paquete web

https://webpack.docschina.org/

  • Básicamente, webpack es una herramienta de agrupación de módulos estáticos para aplicaciones JavaScript modernas.
  • Webpack solo admite la introducción de archivos js de forma predeterminada al principio.
  • Ahora, para CSS, también se puede introducir el formato vue, pero se requiere cierta configuración del cargador.

Entrada->paquete web npx

  1. npx webpack index.js
    Dígale al módulo webpack que el archivo de entrada para empaquetar es index.js y luego comience a empaquetar

  2. Archivo de entrada de configuración webpack.config.js(nombre de configuración predeterminado)

module.exports = {
    
    
  entry: './index.js',
};

Se puede ejecutar directamente en la consola.npx webpack

  1. Los archivos de configuración personalizados webpack.dev.config.js
    se pueden ejecutar directamente en la consola.npx webpack --config ./webpack.dev.config.js

producción

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 de forma predeterminada.

Puede configurar estos procesos especificando un campo de salida en la configuración:

const path = require('path');
module.exports = {
    
    
  entry: './index.js',
  output: {
    
    
    path: path.resolve(__dirname, 'dist'),
    //在任何模块文件内部,可以使用__dirname变量获取当前模块文件所在目录的完整绝对路径。
    filename: 'my-first-webpack.bundle.js',
    publicPath: 'http://localhost:8080/' //打入引入js文件的域名
  },
};
  • ¿Por qué main.js es el predeterminado?
const path = require('path');
module.exports = {
    
    
  entry: {
    
    
      main:'./index.js',
    // entry中key值为打包后的名字
    // 可以有多个入口
  },
};

Configuración de múltiples entradas.

const path = require('path');
module.exports = {
    
    
    entry: {
    
    
        main: './index.js',
        // entry中key值为打包后的名字
        // 可以有多个入口
        sub:'./index.js'
    },
    output: {
    
    
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
        // 输入两个文件main sub
    },
},
;

caché de navegador

  • Rendimiento
    https://webpack.docschina.org/configuration/performance/#root

  • Consejos para desactivar la optimización del rendimiento

module.exports = {
    
    
 //...
 performance:false,
 //关闭性能优化的相关内容,
//   发现npx weback 打包的一些报警信息没有了
};
  • Caché del navegador:
    el mismo archivo Bundle.js se empaqueta y produce cada vez. Si el caché se activa durante la navegación, se leerá desde el caché y el archivo más reciente no se actualizará.

  • El nombre del archivo de salida utiliza el hash generado por el contenido generado:
    webpack.config.js

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

modo

Usar el modo directamente

Al configurar el parámetro de modo seleccionando uno de desarrollo, producción o ninguno, puede habilitar las optimizaciones integradas del paquete web para el entorno correspondiente. Su valor predeterminado es producción.

module.exports = {
    
    
  mode: 'development',
};
  • Bundle.js generado por el empaquetado en modo de desarrollo no se comprimirá

Utilice el archivo de configuración correspondiente al modo.

Diferentes configuraciones de archivos

  • paquete web.deb.js
  • paquete web.prod.js
  • packahe.json
    {
          
          
        "scripts":{
          
          
            "build":"webpack --config ./build/webpack.prod.js",
            "dev":"webpack-dev-server --config ./build/webpack.dev.js",
            "dev:build":"webpack --config ./build/webpack.dev.js",
        }
    }
    

fusión de paquete web

  • Instalar la combinación de paquetes web
  • La parte de configuración pública de webpack.base.js se coloca aquí
const path = require('path');
module.exports = {
    
    
    entry: {
    
    
        main: './index.js'
    },
    output: {
    
    
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js',
    },
},
;
  • Fusionar configuración en archivos de modo de desarrollo y producción respectivamente
const {
    
    merge}   = require('webpack-merge')

// 公共配置
const baseConfig = require('./webpack.base')
// 开发配置
const devConfig = module.exports = {
    
    
    "mode":"development",
    "devtool":"",
    "devServer":{
    
    },
    "plugins":[]
}

module.exports = merge(baseConfig,devConfig)

Uso básico del cargador.

  • webpack solo puede comprender archivos JavaScript y JSON, que es la capacidad integrada de webpack disponible de fábrica.
  • El cargador permite que webpack procese otros tipos de archivos y los convierta en módulos válidos.

Atributos

En la configuración del paquete web, el cargador tiene dos atributos:

  • El atributo de prueba identifica qué archivos se convertirán.
  • El atributo de uso define qué cargador se debe utilizar al realizar la conversión.
const path = require('path');
module.exports = {
    
    
  output: {
    
    
    filename: 'my-first-webpack.bundle.js',
  },
  module: {
    
    
    rules: [{
    
     test: /\.txt$/, use: 'raw-loader' }],
  },
};

En la configuración anterior, el atributo de reglas se define para un objeto de módulo separado, que contiene dos atributos requeridos: prueba y uso. Esto le dice al compilador del paquete web lo siguiente:

"Hola, compilador de paquetes web, cuando encuentre una ruta que se resuelva en '.txt' en una declaración require()/import, use raw-loader para convertirla antes de empaquetarla". "

https://webpack.docschina.org/loaders/Instale el cargador aquí

Cargador para procesar imágenes: cargador de archivos, cargador de URL

  1. cargador de archivos
    https://v4.webpack.docschina.org/loaders/file-loader/
  • Manejar la configuración del formato de imagen
module.exports = {
    
    
    module: {
    
    
        rules: [
            {
    
    
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
    
    
                        loader: 'file-loader',
                        options: {
    
    
                            name: '[hash].[ext]',
                            // 生成的dist中图片名是原图片名(默认文件名是一个md5生成的)
                            // name配置项是配置打包生成的文件的名字,使用的是placeholder语法
                            // [name]表示的是原文件的名字;
                            // [hash]  表示的是这次打包的hash值   
                            // [ext]表示的是原文件的后缀;
                            outputPath: 'images',
                            // 生成的图片在dist/images/路径下
                        },
                    }
                ],
            },
        ],
    },
};
  • usar
import testJpg from './resource/test.jpg';
console.log('name',testJpg)
const img = new Image();
img.src = testJpg;
const app = document.getElementsByTagName('div')[0]
app.appendChild(img);

Después de ejecutar el comando de empaquetado npx, abra la página de inicio en dist y podrá ver la imagen.

  1. El cargador de URL devuelve base64.

https://v4.webpack.docschina.org/loaders/url-loader/

Un cargador para webpack que transforma archivos en URI base64.

  • url-loader funciona como un cargador de archivos, pero puede devolver un DataURL si el archivo es más pequeño que un límite de bytes.
module.exports = {
    
    
    module: {
    
    
        rules: [
            {
    
    
                test: /\.(png|jpg|gif)$/i,
                use: [
                    {
    
    
                        loader: 'url-loader',
                        options: {
    
    
                            limit: 8192
                            // 防止图片过大,限制大小
                        }
                    }
                ]
            }
        ]
    }
}
  1. Uso integral del límite del cargador de URL
    • La imagen es muy grande->cargador de URL->la cadena base64 es muy grande->bundle.js será muy grande->index.html tardará mucho en cargar bundle.js

    • La imagen es muy pequeña -> cargador de URL -> la base64 de la imagen se configura directamente en el atributo src de img -> no es necesario enviar imágenes de solicitud http adicionales

    • La imagen es muy pequeña -> cargador de archivos -> generar el archivo de imagen por separado -> introducción del índice -> paquete.js es muy pequeño -> bloque de carga de página -> enviar una solicitud http más

    • La imagen es muy grande -> cargador de archivos -> bundle.js es muy pequeño -> la imagen se solicita por separado

    module.exports = {
          
          
        module: {
          
          
            rules: [
                {
          
          
                    test: /\.(png|jpg|gif)$/i,
                    use: [
                        {
          
          
                            loader: 'url-loader',
                            options: {
          
          
                                name: 'dirname/[hash].[ext]',
                                // 生成的dist中图片名是原图片名(默认文件名是一个md生成的)
                                outputPath: 'images',
                                // 生成的图片在dist/images/路径下
                                limit: 8192
                                // 防止图片过大,限制大小
                            }
                        }
                    ]
                }
            ]
        }
    }
    

Cargador de estilos: cargador de estilos, cargador css

  • Los estilos simples se pueden procesar operando el cargador en js
  • Si importa un archivo css, necesita instalar el cargador correspondiente
    1. cargador de estilos
    2. cargador-css
    • style-loader se usa junto con css-loader y el orden no se puede cambiar.
    • La función de css-loader es transcodificar el archivo css, y la función de style-loader es insertar el archivo css transcodificado en el archivo correspondiente.
    • El estilo generado por el paquete se insertará en la etiqueta de estilo en index.html
      webpack.config.js
{
    
    
  module: {
    
    
    rules: [
      {
    
    
        test: /\.css$/,
        // use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], 
        uer: ['style-loader','css-loader']
      },
    ];
  }
}

Orden de ejecución del cargador

De derecha a izquierda, de abajo hacia arriba

cargador descarado

// webpack.config.js
module.exports = {
    
    
    ...
    module: {
    
    
        rules: [{
    
    
            test: /\.scss$/,
            use: [
                "style-loader", // 将 JS 字符串生成为 style 节点
                "css-loader", // 将 CSS 转化成 CommonJS 模块
                "sass-loader" // 将 Sass 编译成 CSS,默认使用 Node Sass
            ]
        }]
    }
};
  • La
    opción importLoaders le permite configurar cuántos cargadores se aplican a los recursos @imported antes de css-loader.
// webpack.config.js
{
    
    
  test: /\.scss/,
  use: [
    {
    
     loader: 'style-loader'},
    {
    
     loader: 'css-loader',
      options: {
    
    
            importLoaders: 2 //如果css中import scss文件 应用2个层级的loader
        },
    },
    {
    
     loader: 'postcss-loader' },
    {
    
     loader: 'sass-loader'}
  ]
}

postcss-loader+autoprefix configurar prefijo de estilo

https://v4.webpack.docschina.org/loaders/postcss-loader/#sourcemap

  • webpack.config.js establece el cargador
{
    
    
  test: /\.css/,
  use: [
    {
    
     loader: 'style-loader', options: {
    
     sourceMap: true } },
    {
    
     loader: 'css-loader', options: {
    
     sourceMap: true } },
    {
    
     loader: 'postcss-loader', options: {
    
     sourceMap: true } },
    {
    
     loader: 'sass-loader', options: {
    
     sourceMap: true } }
  ]
}
  1. webpack.config.js carga el prefijo automático
    {
          
          
    test: /\.css$/,
    use: [
            {
          
          
            loader: 'postcss-loader',
            options: {
          
          
                    plugins: () => [require('autoprefixer')({
          
          
                        'browsers': ['> 1%', 'last 2 versions']
                    })],
                }
            },
        ]
    }
    

o

  1. postcss.config.js carga el prefijo automático
    module.exports = ({
           
            file, options, env }) => ({
          
          
    //   parser: file.extname === '.sss' ? 'sugarss' : false,
    plugins: {
          
          
        // require('autoprefixer')({...options}),
        // require('autoprefixer')({
          
          
        //     // 也可以在这设置目标浏览器
        //     browsers : ['last 100 versions'] 
        // })
        require('autoprefixer')({
          
          
            'browsers': ['> 1%', 'last 2 versions']
        })
    }
    })
    
  2. Establecer el rango de navegadores de destino
    https://github.com/browserslist/browserslist
    Todas las herramientas encontrarán los navegadores de destino automáticamente cuando agregue lo siguiente a
    • paquete.json:
      "browserslist":[
          "> %1",
          "last 2 versions"
      ]
      
    • O en la configuración .browserslistrc:

modularidad CSS

Antes de hablar sobre cómo implementar la modularidad CSS, hablemos de qué problemas deberían resolverse utilizando la modularidad:

  1. Privatización de estilo
  2. Evite la contaminación por otros archivos de estilo
  3. Reutilizable

https://github.com/css-modules/css-modules

https://webpack.docschina.org/loaders/css-loader/#modules

{
    
    
    test: /\.css$/i,
    loader: "css-loader",
    options: {
    
    
        modules: true,
    },
}
  • Principio de modularidad: agregue un sufijo al selector CSS actual
/* components/Button.css */
.normal {
    
     /* normal 相关的所有样式 */ }
.disabled {
    
     /* disabled 相关的所有样式 */ }
/* components/Button.js */
import styles from './Button.css';
console.log(styles);
buttonElem.outerHTML = `<button class=${
      
      styles.normal}>Submit</button>`

El HTML generado es

<button class="button--normal-abc53"> Processing... </button>

Imprimir resultados

Object {
    
    
  normal: 'button--normal-abc546',
  disabled: 'button--disabled-def884',
}

Los módulos CSS manejan todos los nombres de clases en CSS y utilizan objetos para guardar la correspondencia entre la clase original y la clase ofuscada.

complementoscomplementos

https://v4.webpack.docschina.org/plugins/
https://webpack.js.org/awesome-webpack/

complemento-html-webpack

https://v4.webpack.docschina.org/plugins/html-webpack-plugin/

var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
    
    
  entry: 'index.js',
  output: {
    
    
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js'
  },
//   插件都是实例化使用
  plugins: [new HtmlWebpackPlugin()]
};

Esto producirá un archivo dist/index.html que contiene el siguiente contenido:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>
  • Antes, creábamos manualmente dist/index.html nosotros mismos y luego introducíamos el paquete dist/bundle.js.
  • Con el complemento html-webpack-plugin, se crea index.html después de empaquetar el paquete web y se introduce automáticamente bundle.js.
  • Pero el archivo htm creado por webpack solo presenta bundle.js y no tiene otro contenido.
  • Entonces necesitamos configurar otro contenido para el complemento.
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');

module.exports = {
    
    
  entry: 'index.js',
  output: {
    
    
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js'
  },
  plugins: [new HtmlWebpackPlugin({
    
    
      template:'./src/index.html'
      //配置dist/html模板
  })]
};

Complementos de uso común de Webpack

  • CleanWebpackPlugin
    se utiliza para limpiar los archivos del paquete generados por el proyecto anterior antes del empaquetado. De forma predeterminada, este complemento eliminará todos los archivos en el directorio Output.Path del paquete web.

devtool->sourceMap

https://v4.webpack.docschina.org/configuration/devtool/#devtool

  • devtool -> parámetro: cadena falsa
  • Elija un formato de mapa de origen para mejorar el proceso de depuración. Los diferentes valores afectarán significativamente la velocidad de construcción y reconstrucción.
    paquete web.config.js
const path = require('path');
module.exports = {
    
    
    mode:'development',
    devtool:'none',
    entry: {
    
    
        main: './index.js',
    },
    output: {
    
    
        path: path.resolve(__dirname, 'dist'),
    },
}

index.js

console.logg('hello')
// 这行代码webpack打包的时候不会报错,打开网页后浏览器报错,问题定位到dist/main.js
  1. devtool: 'none', cuando la página web informa un error, el navegador localizará el error en el archivo dist/main.js, que tiene la velocidad de empaquetado más rápida
  2. devtool: 'eval-source-map', el navegador localizará el error en el archivo de código fuente original
  3. devtool: 'source-map', código fuente original, genera un archivo de mapa de la relación entre el código fuente y el código empaquetado
  • Mejores prácticas
    1. Entorno de desarrollocheap -module-eval-source-map eval-cheap-module-source-map
    2. Entorno de producción mapa-fuente-módulo barato
  • barato: indica en qué fila está la pregunta pero no indica la columna
  • module:cheap ignora los módulos y cargadores de terceros. Si agrega un módulo, se le solicitará.
  • eval: el archivo de mapeo del código fuente y el código empaquetado no se generará, sino que se colocará en main.js

servidor-dev-webpack

  • Cada vez que modifica el código fuente, debe volver a ejecutarlo npx webpacko npm run buildcompilarlo y empaquetarlo, y actualizar la página para ver la página modificada.
  • webpack-dev-server puede optimizar este proceso
  • El servidor webpack-dev-server está escrito usando node+express

https://v4.webpack.js.org/configuration/dev-server/

  1. instalarnpm install webpack-dev-server --save-dev
  2. configuración webpack.config.js
    var path = require('path');
    
    module.exports = {
          
          
        //...
        devServer: {
          
          
            // contentBase: path.join(__dirname, 'dist'),
            // webpack5中contentBase已经失效了
            static: {
          
          
                directory: path.join(__dirname, 'dist'),
            },
            compress: true,//压缩
            port: 9000,
            open: true //告诉 dev-server 在 server 启动后打开浏览器。默认禁用。
            // proxy 可以处理跨域问题
        },
    };
    
  3. paquete de configuración.json
    "scripts": {
          
          
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack",
        "dev" : "webpack-dev-server"
    },
    
  4. npm run dev

devServer.proxy

  • Proxy ciertas URL puede ser útil si tiene una API de servidor de desarrollo backend independiente y desea enviar solicitudes de API con el mismo nombre de dominio.
  • Los problemas entre dominios generalmente se resuelven mediante el reenvío de solicitudes.
  • Se aplica solo al entorno de desarrollo.
    Si tiene un servicio backend en localhost:3000, puede habilitar el proxy de esta manera:

paquete web.config.js

module.exports = {
    
    
    //...
    devServer: {
    
    
        // 1.
        // proxy: {
    
    
        //     '/api': 'http://localhost:3000'
        // },
        // 2.
        // proxy: {
    
    
        //     '/api': {
    
    
        //         target: 'http://localhost:3000'
        //     }
        // }
        proxy: {
    
    
            '/api': {
    
    
                // 一旦devServer(5000)服务器接收到 /api/xxx 的请求,就会把请求转发到另一个服务器(3000)
                // 浏览器和服务器之间有跨域,但是服务器和服务器之间没有跨域
                target: 'http://thirdserver.com:3000',
                changeOrigin: true,
                pathRewrite: {
    
     
                    '^/api': '' 
                    // 所有以/api开头的请求,把/api转换为空字符串
                    // 发送请求时,请求路径重写:将 /api/xxx --> /xxx (去掉/api
                },
                secure: false,
                //默认情况下,不接受运行在 HTTPS 上,且使用了无效证书的后端服务器。
                // 如果你想要接受,修改配置如下:
            }
        }
    }
};

Las solicitudes a /api/users ahora se enviarán mediante proxy a las solicitudes a http://localhost:3000/api/users.

diferencias de compilación de webpack VS webpack-dev-server

"scripts":{
    
    
    "build":"webpack", // 打包后文件在dist/main.js可以找到
    "dev":"webpack-dev-server" //打包后文件在内存中
}

Complemento de actualización en caliente HotModuleReplacementPlugin

  1. Conozca las actualizaciones de HMR
    • Ingrese texto en el cuadro de entrada. Después de modificar el código fuente, la página web se actualiza automáticamente y luego solicita nuevamente, y el estado se pierde.
    • Modificar el código fuente y actualizar automáticamente la página web es una implementación en caliente y no una actualización en caliente.
  2. Solución: complemento HotModuleReplacementPlugin
    https://webpack.docschina.org/plugins/hot-module-replacement-plugin/
    https://webpack.js.org/guides/hot-module-replacement/#enabling-hmr
    :: :advertencia
    HMR nunca debe usarse en un entorno de producción.
    :::
const webpack = require('webpack');
// ........
module.exports = {
    
    
    plugins:[new webpack.HotModuleReplacementPlugin()]
    // webpack内置插件
}

https://stackoverflow.com/questions/69102254/webpack-options-has-an-unknown-property-hotonly-invalid-options-object-dev-s

Las últimas versiones aplican automáticamente el complemento HotModuleReplacementPlugin cuando configura hot: true, así que verifique que no tenga HotModuleReplacementPlugin en sus complementos si tiene hot: true/hot: “solo”. Recibirá una advertencia como "[webpack-dev-server] “hot: true” aplica automáticamente el complemento HMR, no es necesario que lo agregue manualmente a la configuración de su paquete web". si tiene la configuración anterior.

  • style-loader configura automáticamente las actualizaciones en caliente. Si se cambia el CSS, el estilo cambiará solo. Los propios frameworks reaccionar y vue también están configurados. Si necesita personalizar
if(module.hot){
    
        //在你要监听的文件里面写
    console.log('hot')
    // './print.js'
    // Ignored an update to unaccepted module ./src/print.js -> ./src/index.js
    // accept第一个参数必须是当前依赖的模块路径
    module.hot.accept('./print.js',()=>{
    
        // ./src值得是更新文件路径
        console.log('代码热更新,写自己的代码控制')   
        const oldSpan = document.getElementsByTagName('span')[0];
        oldSpan.innerText=`HRP-sp${
      
      print.a}`;  
    })
}

babel->ES6

https://www.babeljs.cn/docs/index.html

  • Babel es un compilador de JavaScript

Babel es una cadena de herramientas que se utiliza principalmente para convertir código escrito en sintaxis ECMAScript 2015+ en sintaxis JavaScript compatible con versiones anteriores para que pueda ejecutarse en versiones actuales y anteriores de navegadores u otros entornos. A continuación se detalla lo que Babel puede hacer por usted:

  1. Conversión gramatical
  2. Agregue funciones faltantes en el entorno de destino a través de Polyfill (mediante la introducción de módulos Polyfill de terceros, como core-js)
  3. Conversión de código fuente (codemods)
  • preset-env utiliza
    https://www.babeljs.cn/setup#installation
    https://webpack.js.org/loaders/babel-loader/
    https://babel.docschina.org/docs/en/next/configuration /
  1. npm install -D babel-loader @babel/core @babel/preset-env

  2. configuración

    module: {
          
          
    rules: [
        {
          
          
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,//排除第三方代码
        use: {
          
          
            loader: 'babel-loader',
            options: {
          
          
                presets: ['@babel/preset-env']
            }
         }
        }
      ]
    }
    
  3. babel.config.json
    https://babel.docschina.org/docs/en/next/usage/

Sacudiendo el árbol

  • Tree Shaking solo es compatible con ES Moudle y no es compatible con CommonJs
  • ES Moudle->Introducción estática, importación y exportación al compilar
  • CommonJS->Introducción dinámica, requiere que module.exports se introduzca durante la ejecución
const flag = true;
if(flag){
    
    
    const {
    
    add} = require('./math')
}

if(flag){
    
    
    import {
    
    add} from ('./math')
    // 这种动态引入会报错
    // import and export may only appear at the top level 
}

Tree Shaking significa que cuando introduzco un módulo, no introduzco todo el código de este módulo, solo presento el código que necesito, lo que requiere la ayuda de la función Tree Shaking que viene con el paquete web para ayudarnos a lograrlo. Tree Shaking solo admite el módulo ES (importar...) y no admite requisitos...

  • https://developer.mozilla.org/zh-CN/docs/Glossary/Tree_shaking

  • https://webpack.js.org/guides/tree-shaking/

  • Al configurar la vibración del árbol en modo de desarrollo:

    mode:'development',
    optimization: {
          
          
        usedExports: true,
    },
    
    • En el modo de desarrollo, el código no utilizado para facilitar la depuración no se elimina, solo se anotan los métodos sin referencia.
  • En modo de producción, no es necesario configurarlo en webpack.config.js. usedExports se habilita automáticamente de forma predeterminada.

  • Si Tree Shaking no surte efecto, consulte el mapa fuente

libre de efectos secundarios (sin efectos secundarios)

  • Además del valor de retorno, cualquier efecto que afecte cualquier cosa fuera de la función (pantalla, red, archivos, variables globales, etc.) se denomina efecto secundario.

Este método se implementa mediante el atributo "sideEffects" de package.json.

{
    
    
  "name": "your-project",
  "sideEffects": false
}

Si todo el código no contiene efectos secundarios, simplemente podemos marcar este atributo como falso para indicarle al paquete web que puede eliminar de forma segura las exportaciones no utilizadas.

Debido a que Tree Shaking eliminará nuestras funciones de exportación no utilizadas, debido a que el polyfill está definido en la ventana y no tiene exportación, se eliminará. Configure el
efecto secundario para excluir las comprobaciones de efectos secundarios
::: tip
"efecto secundario (efecto secundario)" La definición es un código que realiza un comportamiento especial cuando se importa, en lugar de simplemente exponer una exportación o varias exportaciones. Por ejemplo, tomemos el polyfill, que afecta el alcance global y generalmente no permite la exportación.
:::

{
    
    
  "name": "your-project",
  "sideEffects": ["@babeli/polyfill","*.css"]
}

división de código

https://webpack.docschina.org/guides/code-splitting/

  • El código generalmente se divide en código de lógica empresarial y otro código del kit de herramientas, todo empaquetado en main.js, el archivo es muy grande
  • Si se modifica el código de lógica empresarial y se vuelven a empaquetar otros códigos de herramientas, el navegador volverá a descargar el main.js grande.
    • src/index.js
    import _ form 'lodash'
    console.log('hello world!');//每次修改业务逻辑,webpack打包的时候也会将lodash一块重新打包到bundle.js
    const result = _.join(['test1','test2','test3'],'-');
    console.log('result',result)
    
  • Resolver->Separación de códigos->Configurar múltiples entradas

Solución manual -> Configurar múltiples entradas y salidas

  • Punto de partida de entrada: utilice la configuración de entrada para separar manualmente el código.
  • fuente/índice,js
    console.log('hello world!');
    const result = _.join(['test1','test2','test3'],'-');
    console.log('result',result)
    
  • src/lodash.js
    import _ form 'lodash'
    window._= _
    
  • paquete web.config.js
    module.exports = {
          
          
        entry:{
          
          
            main:'./src/index.js',
            lodash:'./src/lodash.js'
            //打包生成 main.js和lodash.js并引入到index.html中
        },
        output: {
          
          
            path: path.resolve(__dirname, 'dist'),
            filename: '[name].js',
        }
    },
    }
    

Solución de complemento SplitChunksPlugin

  • SplitChunksPlugin elimina duplicados y separa fragmentos.
    https://webpack.docschina.org/plugins/split-chunks-plugin/

  • src/index.js

import _ form 'lodash'
console.log('hello world!');//每次修改业务逻辑,webpack打包的时候也会将lodash一块重新打包到bundle.js
const result = _.join(['test1','test2','test3'],'-');
console.log('result',result)
  • paquete web configurar SplitChunks
module.exports = {
    
    
  //...
  optimization: {
    
    
    splitChunks: {
    
    
        chunks:'all'
  },
};

importar carga diferida->separación de código

https://webpack.docschina.org/guides/lazy-loading/#root

// Note that because a network request is involved, some indication
// of loading would need to be shown in a production-level site/app.
button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
    
    
    const print = module.default;
// 注意当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象。
    print();
});
  • La separación del código de carga diferida de importación también se configura a través de SplitChunksPlugin.

splitChunks.chunks: indica qué fragmentos se seleccionarán para la optimización. Cuando se proporciona una cadena, los valores válidos son todos, asíncronos e iniciales. Proporcionar todo puede ser particularmente poderoso, porque significa que los fragmentos se pueden compartir incluso entre fragmentos asíncronos y no asíncronos.

Comprender el paquete de fragmentos de módulos

[La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente (img-jtOQyPHA-1654528404640)(https://gitee.com/jingyu7/pic/ raw/master/202201061256177.png)]

  • Módulo, fragmento y paquete son en realidad el mismo código lógico con tres nombres en diferentes escenarios de conversión:
  • Lo que escribimos directamente es un módulo, que el paquete web procesa como un fragmento y finalmente genera un paquete que el navegador puede ejecutar directamente.

Configuraciones comunes de SplitChunksPlugin

  • splitChunks.chunks
    Este objeto de configuración representa el comportamiento predeterminado de SplitChunksPlugin.
module.exports = {
    
    
  //...
  optimization: {
    
    
    splitChunks: {
    
    
      chunks: 'async',//默认只有异步代码进行代码分隔 all, async, and initial
      minSize: 20000, //如果引入的包>20000KB就进行代码分隔
      minRemainingSize: 0,//通过确保拆分后剩余的最小 chunk 体积
      minChunks: 1, //拆分前必须共享模块的最小 chunks 数。
    // 这个配置表示split前单个非按需导入的module的并行数的最低下限
    // 注:只对import或require直接引入的module有效。
    // 1. minChunks设置为n
    // 2. 假设有m个入口点,这m个入口点都直接引入了某个模块module(通过import或require直接或间接地引入了模块),也就是共享次数为m
    // 3. 当m至少等于n时,module才会被单独拆分成一个bundle

      maxAsyncRequests: 30,//按需加载时的最大并行请求数。
      maxInitialRequests: 30,//入口点的最大并行请求数
      enforceSizeThreshold: 50000,//强制执行拆分的体积阈值和其他限制
      cacheGroups: {
    
     //缓存组
    //   对于缓存组是一个对象,处了可以有上面的chunks、minSize、minChunks、maxAsyncRequests、maxInitialRequests、name外,还有其他的一些参数:
    // 如果不在缓存组中重新赋值,缓存组默认继承上面的选项,但是还有一些参数是必须在缓存组进行配置的
    // 缓存组的概念理解
    // 源代码中引入了lodash jquery 都分别分隔到了对应的js
    // 假如希望它两合并后分隔
    // 当分析到引入lodash时缓存到defaultVendors,分析到jquery满足规则也缓存起来
    // 当所有模块到分析结束后,再把defaultVendors组一起分隔
        defaultVendors: {
    
    
          test: /[\\/]node_modules[\\/]/, //捕获模块规则
          priority: -10, //优先级
          reuseExistingChunk: true,
          //如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
          //假如源代码中不同文件中都引入lodash模块,
          //在第一次引入分析后被当前缓存组缓存,后面的此模块的引入分析复用之前缓存结果
        },
        default: {
    
    
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
};

División de código CSSMiniCssExtractPlugin

Este complemento extrae CSS en archivos separados, crea un archivo CSS para cada archivo JS que contiene CSS y admite la carga bajo demanda de CSS y SourceMaps .

  • Anteriormente, el archivo de estilo CSS era procesado y empaquetado por styleLoader y colocado en main.js->css en js->finalmente colocado en el estilo del encabezado.
  • Generalmente utilizado en entornos de producción.
  • mini-css-extract-plugin
    https://webpack.docschina.org/plugins/mini-css-extract-plugin/
    webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
    
    
  plugins: [new MiniCssExtractPlugin()],
  module: {
    
    
    rules: [
      {
    
    
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
};

El ajuste preestablecido de shimming depende de ProvidePlugin

Cargue módulos automáticamente en lugar de tener que importarlos o solicitarlos en todas partes.

  • Se puede usar para complementos de configuración global y también se puede usar para compatibilidad con jquery en código antiguo.
  • gramática
new webpack.ProvidePlugin({
    
    
  identifier: 'module1',
  // ...
});
  • Uso: jQuery
    Para cargar jquery automáticamente podemos apuntar ambas variables que expone al módulo de nodo correspondiente:
const path = require('path');
const webpack = require('webpack');
 module.exports = {
    
    
   entry: './src/index.js',
   output: {
    
    
     filename: 'main.js',
     path: path.resolve(__dirname, 'dist'),
   },
  plugins: [
    new webpack.ProvidePlugin({
    
    
        $: 'jquery',
        jQuery: 'jquery',
        // webpack为我们提供了ProvidePlugin的插件,上面配置的意思是,当我们在模块中遇到‘$’就会去自动的引入jquery
    });
  ],
 };

Luego en cualquiera de nuestro código fuente:

// in a module
$('#item'); // <= works
jQuery('#item'); // <= also works
// $ is automatically set to the exports of module "jquery"

La diferencia entre la versión 4 y la versión 5.

Optimización del rendimiento

Hay dos direcciones de optimización.

  1. Velocidad de construcción del paquete
  2. Tamaño del código de salida

babel-loader-exclude,cacheDirectory

  • El objetivo principal es mejorar la velocidad de empaquetado y construcción de js, el primero es el almacenamiento en caché y el segundo es la exclusión.
  • El cargador CSS no genera caché.
  1. excluir incluir

    exclude:path.resolve(__dirname,'node_modules')
    
    • pregunta

      • Al configurar babel-loader en webpack, ¿por qué deberíamos excluir la carpeta node_modules?
      • ¿Qué pasa si el módulo js en esta carpeta también tiene una sintaxis ES6 similar a las funciones de flecha?
    • Porque si no excluye esta carpeta, Babel también leerá y recompilará los códigos de otras bibliotecas de herramientas a las que haga referencia en su propio código. La compilación del código JavaScript es más lenta. En muchos casos, su propio código comercial solo representa 10%, pero el código de otras bibliotecas de herramientas a las que se hace referencia puede representar entre el 80% y el 90% después de la compilación. Si tarda 10 segundos en compilar su propio código comercial, entonces el código de todo el proyecto tardará 100 segundos. Usted encontrará que la velocidad es muy lenta, lo que no favorece la mejora de la eficiencia del desarrollo. Por otro lado, las bibliotecas de herramientas ahora publicadas en npm generalmente incluyen código fuente y código compilado. Al mismo tiempo, se hace referencia al código compilado de forma predeterminada. Esto equivale a compilar el código compilado nuevamente. En realidad, no tiene ningún efecto y es un pérdida de tiempo. Por lo tanto, cuando configuramos, generalmente excluimos el código de la biblioteca de herramientas en node_modules del alcance de compilación de babel.

    • Aunque no existe una especificación clara para los paquetes en npm que deben compilarse en la sintaxis es5/es3, el hecho actual es que la mayoría de los paquetes públicos se compilan según esta especificación, por lo que ya es un estándar de facto.

    • ¿Qué pasa si algunos paquetes en node_modules tienen sintaxis es6?

    Respuesta: Especifique ciertos paquetes en node_modules para que no se excluyan mediante expresiones regulares

  2. Caché de Babel: habilite cacheDirectory: verdadero en las opciones de babel-loader
    para colocar el código de compatibilidad compilado en el caché. Si está en el caché la próxima vez que compile, el código compilado se usará directamente. Solo tiene efecto
    para js .

    module:{
          
          
        rules:[
            test: /\,js$/,
            options:{
          
          
                cacheDirectiry:true
            },
            inclued:srcPath,
            exclude:path.resolve(__dirname,'node_modules')
        ]
    }
    

procesamiento de momentos de webpack.IgnorePlugin

IgnorePlugin en el paquete web ignora el contenido localizado al empaquetar. Por ejemplo, si se introduce un complemento y solo se usa el paquete en idioma chino, los paquetes en idiomas distintos del chino se excluyen al empaquetar.

El tiempo de procesamiento de la biblioteca de momentos se usa a menudo en proyectos. ¿Ha descubierto que después de la introducción del momento, el tamaño del archivo creado del proyecto es obviamente mucho mayor? Analicemos las razones y cómo optimizarlo.

//
import moment from 'moment'
// 引入中文
import 'moment/locale/zh-cn'
// 设置中文
moment.locale('zh-cn');
let momentStr = moment().subtract(10, 'days').calendar();
console.log('现在时间:', momentStr);

Después de buscar mucho en Internet, descubrí que todas las configuraciones regionales se empaquetan durante el empaquetado. La solución inicial es usar webpack.IgnorePlugin para manejarlo.
¿Qué hizo IgnorePlugin?

  • Análisis del principio de IgnorePlugin
    El principio de IgnorePlugin es eliminar todos los archivos locales del momento, porque muchas veces no lo usaremos en absoluto en el desarrollo. La forma de utilizar este complemento es la siguiente:
...
plugins: [
    new webpack.IgnorePlugin(/^./locale$/, /moment$/) // 配置忽略规则
    // 忽略moment库中的locale文件夹啊
]

Entonces es posible que tengas preguntas, ¿qué debo hacer si se han eliminado todos los archivos locales, pero quiero usar uno de ellos? No te preocupes, aún puedes usarlo en tu código de esta manera:

const moment = require('moment');
require('moment/locale/ja');//如果需要请单独引用
moment.locale('ja');

https://github.com/zhanzizhen/how-to-optimize-momentjs-with-webpack/blob/master/README.md

configuración sin analizar

Generalmente, los archivos que terminan en .min.js se han modularizado, por lo que no es necesario realizar un análisis de loder o de paquete web en este momento, y el significado literal de noParer ya no se analiza.

module: {
    
    
    noParse: /jquery/, // 不解析模块中的依赖关系 提高打包效率
    rules: []
}
  • Comparación entre ignorePlugin y noParse

    1. IgnorePlugin importa directamente módulos que cumplen con las condiciones coincidentes y no los incluye en el código.
    2. Aún se introducirá noParse, pero no participará en el análisis y empaquetado del cargador o el paquete web.
  • noParse no cambiará el volumen del paquete, solo acelerará la velocidad de construcción

embalaje multiproceso happPack

Dado que JavaScript es un modelo de subproceso único, si desea aprovechar las capacidades de las CPU de múltiples núcleos, solo puede lograrlo a través de múltiples procesos, pero no a través de múltiples subprocesos.
Dado que Webpack que se ejecuta en Node.js es un modelo de subproceso único, las tareas que Webpack necesita manejar deben realizarse una por una. La función de Happypack es descomponer la tarea de análisis de archivos en múltiples subprocesos para su ejecución simultánea. Una vez que el proceso hijo completa la tarea, el resultado se envía al proceso principal. Por lo tanto, la velocidad de construcción del proyecto de Webpack se puede mejorar enormemente.

ver y verOpciones

Webpack puede monitorear archivos en busca de cambios y recompilarlos cuando se modifican.
Habilite el modo Vigilancia. Esto significa que después de la compilación inicial, webpack continuará escuchando cambios en los archivos analizados.

module.exports = {
    
    
  //...
  watch: true,
};

El modo de vigilancia está habilitado de forma predeterminada en webpack-dev-server y webpack-dev-middleware.

  • watchOptions es un conjunto de opciones que se utilizan para personalizar el modo de reloj:
module.exports = {
    
    
  //...
  watchOptions: {
    
    
    ignored: /node_modules/,
    //监听大量文件会导致大量的 CPU 或内存占用。可以使用正则排除像 node_modules 如此庞大的文件夹:
    aggregateTimeout: 200,//批量更新
    // 当第一个文件更改,会在重新构建前增加延迟。这个选项允许 webpack 将这段时间内进行的任何其他更改都聚合到一次重新构建里。以毫秒为单位:
  },
};

DllPlugin

DllPlugin, DllReferencePlugin es un paquete de código de uso común que requiere mucho tiempo para compilarse con anticipación (como reaccionar, reaccionar-dom) y llamarlo dll. Cuando empaquete más tarde, omita el código original sin empaquetar y use el dll directamente. De esta manera, se acortará el tiempo de construcción y se mejorará la velocidad de empaquetado del paquete web.

  • ¿Es sólo un caché? Cambia espacio por tiempo.

  • autodll-webpack-plugin también es un complemento de clase, que anteriormente usaba vue-cli

  • webpack 4 tiene un mejor rendimiento de empaquetado que dll. Entonces autodll-webpack-plugin ya no se usa

Cuando más tarde encontré autodll-webpack-plugin y descubrí que el dll había sido abandonado, en realidad me sentí un poco decepcionado. Sentí que todos mis esfuerzos anteriores fueron en vano y no pude evitar pensar que no podía aprender. él. Pero cuando pensé detenidamente en el principio de dll, descubrí que era solo cuestión de tiempo, intercambiar espacio por tiempo, pero la configuración era un poco más complicada.
Esto también nos recuerda que cuando aprendamos nuevos conocimientos, no nos centremos en la configuración del proceso y el ajuste de parámetros. Porque el proceso eventualmente se simplificará y los parámetros (API) eventualmente se actualizarán. Deberíamos centrarnos en lo grande y dejar de lado lo pequeño, y centrarnos en el contenido central, porque las ideas centrales tienen menos probabilidades de quedar obsoletas.

Supongo que te gusta

Origin blog.csdn.net/uotail/article/details/125156446
Recomendado
Clasificación