Говоря об оптимизации производительности webpack4.0

JavaScript CSS Webpack Babel

Предисловие: В реальных проектах нам редко может понадобиться настраивать проект веб-пакета с нуля, особенно после выпуска веб-пакета 4.0 запуск проекта с нулевой конфигурацией стал стандартом. Именно потому, что веб-пакет с нулевой конфигурацией оптимизировал функции «упаковки» и «сжатия», предоставляемые самим проектом, поэтому в практических приложениях мы можем больше сосредоточиться на бизнес-уровне, не отвлекаясь на оптимизацию построения проекта. Однако, с точки зрения учащегося, нам необходимо понять, какие оптимизации сделал веб-пакет в процессе создания, упаковки и сжатия проекта, и какие улучшения производительности можно сделать в исходной конфигурации по умолчанию.
Недавно мне пришла в голову идея после завершения одностраничного приложения vue, отказа от конфигурации сборки vue-cli, оптимизации веб-пакета с нуля и обмена идеями и опытом в процессе в этой статье. Первоначальная настройка веб-пакета — это еще одна статья, которую я написал ранее.Научить вас знать webpack4.0 с нуляВ статье следующий контент не слишком подробно описывает базовую конфигурацию веб-пакета.

Первое, направление оптимизации

1.1 Разработка проекта

Что касается разработчиков, мы надеемся, что веб-пакет может принести нам беспрепятственный опыт разработки. Например, когда код постоянно модифицируется, мы надеемся, что изменение кода может уведомить браузер о своевременном обновлении страницы вместо ручного обновления страницы. Далее, мы надеемся, что модификация кода лишь частично заменит определенный модуль, а не обновит всю страницу. Таким образом, нам не нужно тратить много времени на ожидание обновления, что значительно повышает эффективность разработки страницы.

1.2 Развертывание проекта

Когда проект развертывается и запускается, оптимизация производительности находится в центре нашего внимания.Есть два направления, которые можно считать основными.Первое – уменьшить количество HTTP-запросов.Мы знаем, что при той же скорости сети загрузка образа размером 100 КБ быстрее, чем загрузка двух образов по 50 КБ, поэтому мы требуем, чтобы веб-пакет упаковывал несколько файлов в один или небольшое количество файлов, еще один фокус оптимизации — сокращение времени одного запроса, то есть уменьшение размера запрашиваемого файла. как можно больше. Усилия по оптимизации производительности в веб-пакете также обычно осуществляются вокруг этих двух основных направлений. Кроме того, в строительном проекте мы также надеемся на постоянное повышение эффективности строительства.

Во-вторых, повысить эффективность разработки

2.1 Уменьшить громкость

В среде разработки у нас все еще есть определенные требования к объему кода, меньший размер позволяет быстрее загружаться, более высокая эффективность разработки, конечно, конфигурация относительно проста.

// webpack.dev.js 开发环境webpack配置
module.exports = {
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        port: 9000,
        compress: true, // 代码压缩
      },
}

2.2 Горячее обновление модуля (HMR)

В процессе разработки мы надеемся, что в процессе модификации кода страницу можно будет обновлять в режиме реального времени без ручного обновления. Таким образом, используя HRM, HMR не только позволяет избежать частого ручного обновления страницы, но и сокращает время ожидания при обновлении страницы, что значительно повышает эффективность разработки.

// webpack.dev.js
module.exports = {
  devServer: {
    compress: true,
    hot: true // 开启配置
  },
  plugins: [
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
  ],
}

3. Оптимизация объема сборки

3.1 режим исходной карты в производстве

Webpack предоставляет не менее 7 режимов исходной карты при построении.Хотя режим eval может повысить эффективность построения, скрипт после построения имеет большой размер, поэтому он не подходит для производства. Режим исходной карты может отслеживать конкретное местоположение файла сценария через сгенерированный файл .map, тем самым уменьшая размер файла сценария, который является первым выбором для производственного режима, а в производственном режиме нам нужно скрыть конкретные информация сценария, так что вы можете использовать дешевый и модульный режим для достижения цели. Подводя итог, в параметрах производственного веб-пакета devtool мы используемcheap-module-source-mapКонфигурация

// webpack.pro.js 生产webpack配置脚本
module.exports = {
  mode: 'production',
  devtool: 'cheap-module-source-map',  
}

3.2 Независимый файл CSS

Что касается одного файла записи, мы обычно упаковываем все статические ресурсы страницы в файл JS, который реализовал оптимизационную часть в версии 1.2, объединил код в статический ресурс и сократил HTTP-запросы.

Перед разлукой

在这里插入图片描述
Но далее нам нужно отделить код css, зачем? Суть в том, что мы надеемся лучше использовать кеш браузера.Когда стиль изменяется отдельно, нет необходимости применять независимый файл css для загрузки всего файла скрипта, что повышает эффективность. Более того, при столкновении с многостраничными приложениями стили некоторых общих частей могут быть извлечены отдельно.После загрузки страницы следующие страницы также могут использовать кеш для уменьшения запросов.

Webpack4.0 предоставляет плагины для извлечения файлов css,mini-css-extract-plugin, просто нужна простая конфигурация для разделения файла css

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    ···
    plugins: [
        new MiniCssExtractPlugin({
            filename: "[name].[contenthash].css",
            chunkFilename: "[name].[contenthash].css"
        })
    ],
    module: {
        rules: {
            test: /\.(css|scss)$/,
            use: [process.env.NODE_ENV == 'production' ? MiniCssExtractPlugin.loader : 'style-loader', {
              loader: 'css-loader',
              options: {
                sourceMap: true
              },
            }, "sass-loader"]
        }
    }
    ···
}
после разлуки

在这里插入图片描述

3.3 Сжатие файлов js, html, css

Чтобы оптимизировать размер сборки и продолжать уменьшать размер файлов статических ресурсов, мы надеемся, что веб-пакет поможет нам максимально уменьшить размер файлов. Для файлов сценариев js webpack4.0 запускает сжатие кода по умолчанию, когда режим «производственный». Кроме того, нам нужно сжать html и css вручную.
Для сжатия html нужно толькоhtml-webpack-pluginСделайте соответствующую конфигурацию.

// webpack.base.js 

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
          title: 'minHTML',
          filename: 'index.html',
          template: path.resolve(__dirname, '../index.html'),
          minify: { // 压缩 HTML 的配置
            collapseWhitespace: true,
            removeComments: true,
            useShortDoctype: true
          }
        }),
    ]
}

Для сжатия CSS webpack4.0 используетoptimize-css-assets-webpack-pluginдля сжатия отдельных файлов css.

const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

module.exports = {
    plugins: [
        new OptimizeCSSAssetsPlugin()
    ],
}

在这里插入图片描述
在这里插入图片描述
Напротив, мы видим очевидные эффекты.Для получения дополнительной информации о настройке сжатия CSS см.optimize-css-assets-webpack-plugin

3.4. Объединение сжатых изображений

После обработки трех основных блоков js, html и css во внешнем интерфейсе следующая оптимизация, о которой вы можете подумать, — это обработка изображений. Как упоминалось ранее, важным условием повышения производительности является уменьшение количества http-запросов, а в приложениях часто приходится обрабатывать большие и маленькие изображения. значки Большое изображение может значительно уменьшить количество сетевых запросов. Для картинок, которые нужно открывать самостоятельно и размер которых находится в разумных пределах, мы можем преобразовать картинки в base64-битную кодировку и встроить их в css, что тоже может уменьшить запросы.

3.4.1 преобразование base64

При обработке графических ресурсов веб-пакет предоставляет на выбор два загрузчика, file-loader и url-loader.Функции file-loader и url-loader можно использовать для решения проблемы введения URL файлов изображений в проекте. Разница между ними заключается в том, что url-loader может преобразовывать файлы меньше указанного байта в DataURL, а файлы больше указанного байта по-прежнему будут анализироваться файловым загрузчиком.

// webpack.base.js
module.exports = {
    module: {
        rules: [{
            test: /\.(png|jpe?g|gif|svg|ttf|woff2|woff)(\?.*)?$/,
            use: [{
              loader: 'url-loader',
              options: {
                limit: 10000, // 限制大小
              }
            }, 
        ]
  },
}
3.4.2 Сжатие изображений

После преобразования base64 изображений спрайтов и небольших изображений веб-пакет также может сжимать изображения для больших изображений, что рекомендуется.image-webpack-loader, плагин обеспечивает различные формы сжатия, подробнее см.Официальная документация сайта

// webpack.base.js
module.exports = {
    module: {
        rules: [
            {
              loader: 'image-webpack-loader',
              options: {
                optipng: { // 使用 imagemin-optipng 压缩 png,enable: false 为关闭
                  enabled: true,
                },
                pngquant: { // 使用 imagemin-pngquant 压缩 png
                  quality: '65-90',
                  speed: 4
                },
              }
            }
        ]
    }
}

Сравнение эффектов выглядит следующим образом:

在这里插入图片描述
在这里插入图片描述

3.5 Разделение зависимых библиотек

В средних и крупных приложениях сторонние зависимости ужасно велики, занимая более половины упакованных файлов. Однако эти зависимые модули редко являются изменяемыми ресурсами.Подобно логике разделения кода CSS, разделение сторонних зависимых библиотек может лучше использовать кэширование браузера и повысить производительность приложений. Поэтому отделение зависимых модулей от бизнес-кода является важной частью оптимизации производительности. В webpack4.0 разделение зависимых библиотек нужно настроить только через optimization.splitChunks.

// webpack.pro.js
module.exports = {
    optimization: {
       splitChunks: {
          cacheGroups: {
            vendor: {
              chunks: "initial",
              test: path.resolve(__dirname, "../node_modules"),
              name: "vendor", // 使用 vendor 入口作为公共部分
              enforce: true,
            },
          },
        },
      },
}

Результат после отделения публичной библиотеки

在这里插入图片描述

3.6 Анализ зависимостей

Как упоминалось ранее, при анализе оптимизации сторонняя библиотека node_modules на самом деле больше всего влияет на объем, оптимизация этой части может сильно уменьшить упакованный объем. Здесь мы используем последниеwebpack-bundle-analyzerПлагин анализирует упакованные модули, умеет отображать упакованные комплекты контента в интуитивно понятной древовидной диаграмме, удобной для взаимодействия, через нее можно узнать, из каких модулей примерно состоит проект, какой модуль занимает больший объем и возможно ли это или нет Замена.

Мы можем грубо рассмотреть его в нескольких направлениях

  • 1. Определите, является ли зависимость незаменимой и не слишком ли низкая частота использования зависимости в проекте. В проекте мы можем использовать огромную библиотеку для определенной операции или функции, на эту библиотеку приходится большая доля объема, но функция используется меньше. В настоящее время мы можем найти замену библиотеки, которая меньше по размеру и имеет удовлетворительные функции, или вручную реализовать некоторые зависимые функции для ее замены.
  • 2. Можно ли уменьшить размер больших библиотек за счет настройки функций. Яркий пример — echart, полная версия echart имеет после сжатия целых несколько сотен k, что недопустимо. В реальных проектах нам может понадобиться только небольшое количество или часть функции echart.В настоящее время мы можем оптимизировать объем, загрузив функции, используемые диаграммой, в виде диаграммы.
  • 3. Могут ли некоторые неоптимизируемые большие библиотеки уменьшить размер файла по внешней ссылке. Например, сторонние библиотеки, такие как bootstrap и vue, которые нельзя оптимизировать, через бесплатную службу cdn с открытым исходным кодом могут не только уменьшить размер файла, но и повысить скорость загрузки веб-сайта, что также является способом оптимизации. представление

3.7 Загрузка по требованию

В упомянутом выше направлении анализа зависимостей, если без большой библиотеки не обойтись, а скорость использования не является низкой, мы можем использовать форму загрузки по требованию. Этот метод фактически разделяет ваш код в некоторых логических точках останова, а затем ссылается или собирается ссылаться на другие новые блоки кода после выполнения определенных операций в некоторых блоках кода. Это ускоряет первоначальную загрузку приложения и уменьшает его общий размер, поскольку некоторые блоки кода могут никогда не загрузиться.

webpack использует require.ensure () для загрузки по запросу, без использования загрузки по запросу, когда первый экран загружает все сценарии при его загрузке, что имеет тенденцию перетаскивать время на первом экране, что приносит плохой пользовательский опыт. Например. Когда в проекте требуется использование крупномасштабной библиотеки диаграмм, а дома это не нужно, требуется загрузка чаще, чем Shanghao, при этом загрузка пользовательского опыта намного лучше.

Когда нагрузка по требованию не требуется, наш код может выглядеть так:

import test from './components/test.vue'
import test2 from './components/test2.vue'

Когда загрузка по требованию включена, наш код изменяется на:

const test = r => require.ensure([], () => r(require('./components/test.vue')), 'chunk1')
const test2 = r => require.ensure([], () => r(require('./components/test2.vue')), 'chunk2')

Конфигурация веб-пакета изменена на

output: {
    ···
    chunkFilename: '[name].[hash].js'
}

В это время скомпилированный файл изменится с исходного на несколько небольших файлов. При загрузке каждого маршрута загружаются разные ресурсы. Особенно при загрузке ресурсов первого экрана работа приложения дополнительно оптимизирована.

Тем не менее, на практике нам необходимо измерять доступность загрузки по требованию в соответствии с потребностями проекта.Хотя в оптимизации первого экрана было сделано большое улучшение, загрузка по требованию будет разбивать большие файлы на несколько небольших файлов в конце концов.Количество http-запросов. Это снова нарушает основы оптимизации производительности. Поэтому на практике есть компромиссы и еще раз компромиссы.

3.8 Удалить избыточный код

Размер кода был оптимизирован для этого шага, и были оптимизированы места, которые в принципе можно оптимизировать. Затем вы можете получить некоторые детали, чтобы выполнить более точную оптимизацию. Например, вы можете удалить в проекте код, на который не ссылается контекст. Это называется оптимизацией встряхивания дерева. В webpack 4.0 режим производства включает эту оптимизацию по умолчанию. Однако, если в проекте используется babel, то функцию разбора грамматики babel необходимо отключить. нужно только

// .babelrc

{
  "presets": [["env", { "modules": false }]]
}

В-четвертых, оптимизация скорости сборки

После разговора о том, как уменьшить размер проекта после строительства, кратко поговорим о том, как улучшить скорость строительства. На самом деле, скорость создания веб-пакета можно значительно повысить, просто изменив конфигурацию. Общие настройки следующие.

Сборка babel-loader 4.1 занимает слишком много времени

4.1.1 Ограничение области действия загрузчика

Так как babel-loader должен преобразовывать грамматику, это занимает много времени, поэтому на первом шаге необходимо ограничить объем функций babel-loader, чтобы поиск и преобразование babel-loader могли точно определить местонахождение указанного модуля. Значительно улучшена скорость сборки. Например:

// webpack.base.js
module.exports = {
    module:{
        rules: [
            {
                test: /\.js$/,
                include: [resolve('src')],// 限定范围
                use: {
                  loader: 'babel-loader',
                },
            },]
    }
}
4.1.2 Результат выполнения загрузчика кеша

Поскольку для анализа и преобразования babel-loader требуется слишком много времени, мы хотим кэшировать результаты каждого выполнения. В загрузчике вебпака есть опция cacheDirectory, по умолчанию стоит false, после ее включения будет использоваться кешированный результат выполнения, а скорость упаковки будет значительно повышена.

// webpack.base.js
module.exports = {
    module: {
        rules: [
            {
            test: /\.js$/,
            include: [resolve('src')],
            use: {
              loader: 'babel-loader?cacheDirectory',
            },
        },]
    }
}

4.2 разрешить оптимизацию синтаксического анализа

После того, как разрешение веб-пакета настроено, это также может ускорить создание проекта. Подробнее см. следующую конфигурацию:

  • Когда import 'react' не является ни абсолютным, ни относительным путем в проекте, укажите путь поиска без слишком большого количества запросов.
  • Используйте resolve.alias как можно реже для установки псевдонимов путей, потому что это повлияет на оптимизацию встряхивания дерева.
  • Автодополнение суффиксов сведено к минимуму. Сокращение работы поиска пути
  • Когда используемая сторонняя библиотека слишком велика и не содержит вызова для импорта, требуется определить. Вы можете использовать noParse, чтобы библиотека не анализировалась загрузчиками.
// webpack.base.js
module.exports = {
    resolve: {
      modules: [
        path.resolve(__dirname, 'node_modules'),
      ],

      extensions: [".js"], 
    
      // 避免新增默认文件,编码时使用详细的文件路径,代码会更容易解读,也有益于提高构建速度
      mainFiles: ['index'],
    },
    module: {
        noParse: function(content){
            return /jquery/.test(content)
        }
    }
}

V. Заключение

Узким местом оптимизации производительности веб-пакета по-прежнему является время и объем сборки.Как повелитель индустрии инструментов для сборки, веб-пакет постоянно оптимизирует процесс сборки и упаковки. Оптимизируя старые проекты, вы также можете получить более глубокое представление о веб-пакете как об инструменте и знаниях по оптимизации производительности.

Пожалуйста, укажите источник