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

Webpack

1.1 Оптимизация конфигурации загрузчика

1.1.1 include & exclude

    module:{
        rules:[
            {
                 test:/\.js$/,
                 use:['babel-loader?cacheDirectory'],
+                include:path.resolve(__dirname,'src'),
+                exclude:/node_modules/
            }
        ]
    }

1.1.2 resolve.modules

resolve: {
        modules: [path.resolve(__dirname, 'node_modules')]
},

1.1.3 resolve.mainFields

mainFieldsИспользуется для настройки сторонних модулей для использования этого файла записи.isomorphic-fetch

  • Если целью является сеть или веб-работник, значение равно ["браузер","модуль","основной"]
  • Когда целью являются другие случаи, значение равно ["module", "main"] ```js resolve: {
  • mainFields:['main'] }, ```

1.1.4 resolve.alias

resolve.aliasЭлементы конфигурации используют псевдонимы для сопоставления исходного пути импорта с новым путем импорта. Этот метод оптимизации повлияет на использованиеTree-Shakingудалить неверный код

alias: {
            'react': path.resolve(__dirname, './node_modules/react/cjs/eact.production.min.js')
        }

1.1.5 resolve.extensions

Если оператор импорта не имеет суффикса файла, Webpack автоматически добавит суффикс, чтобы попытаться узнать, существует ли файл.extensions: ['.js', '.json']

  • Старайтесь, чтобы список суффиксов был как можно меньше.
  • Самая высокая частота идет вперед
  • Максимально используйте суффиксы в операторах экспорта
resolve: {
+        extensions: ['js']
},

1.1.5 module.noParse

Элемент конфигурации module.noParse позволяет Webpack игнорировать рекурсивный анализ некоторых файлов, которые не являются модульными.

    module: {
+        noParse: [/react\.min\.js/]
    }

Игнорируемые файлы не должны содержать import , require , define и другие модульные операторы.

2.DLL

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

  • Разделите базовые модули на отдельные динамически подключаемые библиотеки.
  • Когда импортируемый модуль находится в динамической библиотеке, модуль не может быть снова упакован, но получен из динамической библиотеки.dll-plugin

2.1 Определение DLL

  • Плагин DllPlugin: используется для упаковки библиотеки динамической компоновки.
  • DllReferencePlugin: добавьте библиотеку динамической компоновки, упакованную подключаемым модулем DllPlugin, в файл конфигурации.
module.exports = {
    entry: {
        react: ['react'] //react模块打包到一个动态连接库
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].dll.js', //输出动态连接库的文件名称
        library: '_dll_[name]' //全局变量名称
    },
    plugins: [
        new webpack.DllPlugin({
            name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值
            path: path.join(__dirname, 'dist', '[name].manifest.json')
        })
    ]
}
webpack --config webpack.dll.config.js --mode production

2.2 Использование файлов библиотеки динамической компоновки

plugins: [
+        new webpack.DllReferencePlugin({
+            manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')),
+        })
    ],
webpack --config webpack.config.js --mode development

3. HappyPack

HappyPack позволяет Webpack разбивать задачи на несколько подпроцессов для одновременного выполнения, а затем отправлять результаты в основной процесс после обработки подпроцессов.happypack

npm i happypack@next -D
module: {
        rules: [{
            test: /\.js$/,
            //把对.js文件的处理转交给id为babel的HappyPack实例
 +          use: 'happypack/loader?id=babel',
            include: path.resolve(__dirname, 'src'),
            exclude: /node_modules/
        }, {
            //把对.css文件的处理转交给id为css的HappyPack实例
            test: /\.css$/,
+           use: 'happypack/loader?id=css',
            include: path.resolve(__dirname, 'src')
        }],
        noParse: [/react\.min\.js/]
    },
   plugins: [
        //用唯一的标识符id来代表当前的HappyPack是用来处理一类特定文件
        new HappyPack({
            id: 'babel',
            //如何处理.js文件,和rules里的配置相同
            loaders: [{
                loader: 'babel-loader',
                query: {
                    presets: [
                        "env", "react"
                    ]
                }
            }]
        }),
        new HappyPack({
            id: 'css',
            loaders: ['style-loader', 'css-loader'],
            threads: 4, //代表开启几个子进程去处理这一类型的文件
            verbose: true //是否允许输出日子
        })
    ],

4. ParallelUglifyPlugin

ParallelUglifyPluginВы можете превратить последовательное сжатие файлов JS в открытие нескольких подпроцессов для параллельного выполнения.

npm i -D webpack-parallel-uglify-plugin
new ParallelUglifyPlugin({
            workerCount: 3, //开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去1
            uglifyJS: {
                output: {
                    beautify: false, //不需要格式化
                    comments: false, //不保留注释
                },
                compress: {
                    warnings: false, // 在UglifyJs删除没有用到的代码时不输出警告
                    drop_console: true, // 删除所有的 `console` 语句,可以兼容ie浏览器
                    collapse_vars: true, // 内嵌定义了但是只用到一次的变量
                    reduce_vars: true, // 提取出出现多次但是没有定义成变量去引用的静态值
                }
            },
        })

5. Сервер автоматически обновляется

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

5.1 Мониторинг файлов

+ watch: true, //只有在开启监听模式时,watchOptions才有意义
+ watchOptions: {
+    ignored: /node_modules/,
+    aggregateTimeout: 300, //监听到变化发生后等300ms再去执行动作,防止文件更新太快导致编译频率太高
+    poll: 1000 //通过不停的询问文件是否改变来判断文件是否发生变化,默认每秒询问1000次
+ }

5.2 Процесс мониторинга файлов

  • Webpack регулярно получает время обновления файла и сравнивает его с последним сохраненным временем.Несоответствие означает, что изменение произошло.Опрос используется для настройки количества раз в секунду.
  • Когда обнаруженный файл больше не изменяется, он сначала будет кэширован, а прослушиватель будет уведомлен после ожидания в течение определенного периода времени.aggregateTimeoutнастроить
  • webpack будет прослушивать только те файлы, от которых зависит запись
  • Нам нужно максимально сократить количество файлов, которые необходимо отслеживать, и частоту проверок, естественно, уменьшение частоты приведет к снижению чувствительности.

5.3 Автоматически обновлять браузер

    devServer: {
        contentBase: './dist',
+        inline: true
    },

webpack отвечает за мониторинг изменений в файлах, а webpack-dev-server отвечает за обновление браузера.Эти файлы будут упакованы в куски, и они будут проксировать клиента, чтобы инициировать соединение WebSocket с сервером.

+  [19] (webpack)-dev-server/client/overlay.js 3.58 KiB {0} [built]
+  [21] (webpack)-dev-server/client/socket.js 1.05 KiB {0} [built]
+  [22] ./node_modules/loglevel/lib/loglevel.js 7.68 KiB {0} [built]
+  [24] ./node_modules/strip-ansi/index.js 161 bytes {0} [built]
+  [31] ./node_modules/url/url.js 22.8 KiB {0} [built]
+  [32] (webpack)-dev-server/client?http://localhost:8080 7.75 KiB {0} [built]
+  [33] multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js 40 bytes {0} [built]

5.4 Горячая замена модуля

Технология «Горячая замена модуля» позволяет обновить только указанный модуль без обновления всей веб-страницы.Принцип заключается в том, что при изменении исходного кода перекомпилируется только измененный модуль, а затем новый выходной модуль используется для замены браузера. старый модуль в

  • Более быстрый отклик и меньшее время
  • Рабочее состояние веб-страницы можно сохранить без обновления веб-страницы.
    devServer: {
+        hot:true
    }
[./node_modules/webpack/hot sync ^\.\/log$] (webpack)/hot sync nonrecursive ^\.\/log$ 170 bytes {main} [built]
   [0] multi (webpack)-dev-server/client?http://localhost:8080 webpack/hot/dev-server ./src/index.js 52 bytes {main} [built]
[./node_modules/webpack/hot/dev-server.js] (webpack)/hot/dev-server.js 1.66 KiB {main} [built]
[./node_modules/webpack/hot/emitter.js] (webpack)/hot/emitter.js 77 bytes {main} [built]
if (module.hot) {
    module.hot.accept('./index.js', function () {
        console.log('accept index.js');
    });
}

Оптимизирован модуль горячей замены логов браузера

plugins: [
+        new webpack.NamedModulesPlugin(),
+        new webpack.HotModuleReplacementPlugin(),
]
  • Монитор меньше файлов
  • Игнорировать файлы в каталоге node_modules

6. Дифференцируйте окружающую среду

При разработке веб-страниц обычно используется несколько операционных сред, например:

  • Среда, облегчающая разработку и отладку в процессе разработки.
  • Среда выполнения, опубликованная в Интернете для использования пользователями.

6.1 Различия в окружающей среде

  • Код в строке сжат
  • Среда разработки может печатать журналы, которые могут видеть только разработчики.
  • Внутренний интерфейс данных среды разработки и онлайн-среды может отличаться

6.2 Как использовать

if(process.env.NODE_ENV == 'production'){
     console.log('生产环境');
}else{
    console.log('开发环境');
}

Когда вы используете модуль процесса, webpack упаковывает модуль процесса в

+ new webpack.DefinePlugin({
+             'process.env': {
+                 NODE_ENV:JSON.stringify('production')
+             }
+         }),

Причина переноса строки с помощью JSON.stringify при определении значения переменной среды заключается в том, что значение переменной среды должно быть строкой, заключенной в двойные кавычки, а значение JSON.stringify('production') точно равно равно «производству»

new webpack.DefinePlugin({
  'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
})

6.3 Три типа экологического копирайтинга

  • Различать по команде npm
  • Различать слияние веб-пакетов по переменным среды
  • различать в коде

7. CDN

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

  • HTML-файлы не кешируются, они размещаются на вашем собственном сервере, кеш вашего собственного сервера отключается, а URL-адрес статического ресурса становится адресом, указывающим на CDN-сервер
  • Статические файлы JavaScript, CSS, изображения и другие файлы включают CDN и кеш, а также имена файлов со значениями HASH.
  • Чтобы загружать параллельно без блокировки, выделяйте разные статические ресурсы на разные CDN-серверы.
    output: {
        path: path.resolve(__dirname, 'dist'),
+        filename: '[name]_[hash:8].js',
+        publicPath: 'http://img.zhufengpeixun.cn'
    },

8.Tree Shaking

Tree Shakingможно использовать для удаленияJavaScriptМертвый код, который не работает. он зависит от статикиES6модульный синтаксис, например черезimportа такжеexportИмпорт и экспорт.

Использовать дерево

  1. Не компилируйте модули ES6
    {
                     loader: 'babel-loader',
                     query: {
                         presets: [
                             [
    +                               "env", {
    +                                   modules: false //含义是关闭 Babel 的模块转换功能,保留原本的 ES6 模块化语法
    +                               }
                             ],
                             "react"
                         ]
                     }
                 }
    
    webpack --display-used-exports
    
+ const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

 plugins: [
+   new UglifyJSPlugin()
 ]
webpack --display-used-exports --optimize-minimize
webpack --mode  production

9. Извлечь публичный код

9.1 Зачем нужно извлекать общий код

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

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

9.2 Как извлечь

  • Базовая библиотека классов для долгосрочного кэширования
  • Общий код между страницами
  • Отдельные файлы для каждой страницы

как использоватьcommon-chunk-and-vendor-chunk

entry: {
        pageA: './src/pageA',
        pageB: './src/pageB'
},

optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    chunks: "initial",
                    minChunks: 2,
                    maxInitialRequests: 5, // The default limit is too small to showcase the effect
                    minSize: 0 // This is example is too small to create commons chunks
                },
                vendor: {
                    test: /node_modules/,
                    chunks: "initial",
                    name: "vendor",
                    priority: 10,
                    enforce: true
                }
            }
        }
    },

10. Включить подъем области

Scope Hoisting может уменьшить размер файлов кода, упакованных Webpack, и ускорить их работу.Это также переводится как «подъем объема» и представляет собой новую функцию, представленную в Webpack3.

  • Меньший размер кода, потому что объявления функций генерируют много кода
  • Когда код выполняется, поскольку созданная область действия меньше, накладные расходы памяти также уменьшаются hello.js
export default 'Hello';
import str from './hello.js';
console.log(str);
var util = ('Hello');
console.log(util);

Становится функцией two, содержимое, определенное в hello.js, напрямую вводится в main.js.

const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');

module.exports = {
  resolve: {
    // 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
    mainFields: ['jsnext:main', 'browser', 'main']
  },
  plugins: [
    // 开启 Scope Hoisting
    new ModuleConcatenationPlugin(),
  ],
};
--display-optimization-bailout

11. Разделение кода

Разделение кода — одна из самых ярких особенностей webpack. Эта функция разделяет код на разные пакеты, которые затем можно загружать по запросу или параллельно. Существует три распространенных метода разделения кода:

  • Начальная точка входа: используйте конфигурацию входа для ручного разделения кода.
  • Предотвращение дублирования: используйте splitChunks для дедупликации и разделения фрагментов.
  • Динамический импорт: разделение кода с помощью встроенных вызовов функций модулей.

11.1 Несколько записей

`entry: {
  index: './src/index.js',
  another: './src/another-module.js'
}

11.2 Предотвращение дублирования

Splitchunks может извлечь модуль общественного зависимости на вновь сгенерированный кусок.common-chunk-and-vendor-chunk

optimization: {
        splitChunks: {
            cacheGroups: {
                commons: {
                    chunks: "initial",
                    minChunks: 2
                },
                vendor: {
                    test: /node_modules/,
                    chunks: "initial",
                    name: "vendor",
                }
            }

11.3 Динамический импорт и отложенная загрузка (динамический импорт)

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

  • Разделите функции сайта, по одному фрагменту для каждой категории
  • Непосредственно загружайте функции, необходимые для открытия страницы в первый раз, и показывайте ее пользователю как можно скорее.
  • Некоторые функции, которые зависят от большого количества кода, могут быть загружены по запросу.
  • Код разделения требует времени для загрузки по запросу
document
    .getElementById('clickMe')
    .addEventListener('click', () => {
        import (/*webpackChunkName:"alert"*/
        './alert').then(alert => {
            console.log(alert);

            alert.default('hello');
        });
    });
loaders: [
                {
                    loader: 'babel-loader',
                    query: {
                        presets: ["env", "stage-0", "react"]
                    }
                }
            ]

12. Плагин WebPack-dev-middleWare

Плагин webpack-dev-middleware отслеживает и компилирует измененные файлы и обычно используется вместе с webpack-hot-middleware для обеспечения горячей загрузки.webpack-dev-middleware webpack-hot-middleware

const path = require("path")
const express = require("express")
const webpack = require("webpack")
const webpackDevMiddleware = require("webpack-dev-middleware")
const webpackConfig = require('./webpack.config.js')
const app = express(),
            DIST_DIR = path.join(__dirname, "dist"),// 设置静态访问文件路径
            PORT = 9090, // 设置启动端口
            complier = webpack(webpackConfig)

app.use(webpackDevMiddleware(complier, {
//绑定中间件的公共路径,与webpack配置的路径相同
    publicPath: webpackConfig.output.publicPath,
    quiet: true  //向控制台显示内容
}))

// 这个方法和下边注释的方法作用一样,就是设置访问静态文件的路径
app.use(express.static(DIST_DIR))
app.listen(PORT,function(){
    console.log("成功启动:localhost:"+ PORT)
})

13. Анализ выходных данных

  • профиль: запись трудоемкой информации в процессе строительства;
  • json: вывод результатов сборки в формате JSON и, наконец, вывод только файла .json, который включает всю информацию, связанную со сборкой.
webpack --profile --json > stats.json

Webpack официально предоставляет инструмент визуального анализаWebpack Analyse

  • Модули: показать все модули, каждый модуль соответствует файлу. И он также включает в себя график зависимости между всеми модулями, путь модуля, идентификатор модуля, кусочком, к которому принадлежит модуль, а размер модуля;
  • Блоки: отображение всех блоков кода, блока кода, состоящего из множества модулей. Кроме того, содержит ID, имя, размер кодовых блоков, каждый кодовый блок содержит количество модулей и отношения зависимости между кодовыми блоками;
  • Активы: отображение всех ресурсов выходных файлов, включая .js, .css, изображения и т. д. А также имя файла, размер, из какого блока кода взялся файл;
  • Предупреждения: отображает все предупреждения в процессе сборки;
  • Ошибки: отображает все сообщения об ошибках, возникших в процессе сборки;
  • Подсказки: покажите время, затраченное на обработку каждого модуля.

Примечание

libraryTarget и библиотека

Они необходимы при использовании Webpack для создания библиотеки, которую можно импортировать и использовать другими модулями.

  • output.libraryTarget настраивает способ экспорта библиотеки.
  • output.library настраивает имя библиотеки экспорта. Обычно они используются вместе.

output.libraryTarget — это тип перечисления строк, который поддерживает следующие конфигурации.

переменная (по умолчанию)

Написанная библиотека будет назначена через var переменной с именем via library.

Если output.library='LibraryName' настроен, выходные и используемые коды следующие:

// Webpack 输出的代码
var LibraryName = lib_code;

// 使用库的方法
LibraryName.doSomething();
假如 output.library 为空,则将直接输出:

lib_code Среди них lib_code относится к содержимому кода библиотеки и представляет собой самовыполняющуюся функцию с возвращаемым значением.

commonjs

Написанные библиотеки будут экспортированы через спецификацию CommonJS.

Если output.library='LibraryName' настроен, выходные и используемые коды следующие:

// Webpack 输出的代码
exports['LibraryName'] = lib_code;

// 使用库的方法
require('library-name-in-npm')['LibraryName'].doSomething();
其中 library-name-in-npm 是指模块发布到 Npm 代码仓库时的名称。

commonjs2

Написанная библиотека будет экспортирована через спецификацию CommonJS2, а код вывода и использования будет следующим:

// Webpack 输出的代码
module.exports = lib_code;

// 使用库的方法
require('library-name-in-npm').doSomething();
CommonJS2 和 CommonJS 规范很相似,差别在于 CommonJS 只能用 exports 导出,而 CommonJS2 在 CommonJS 的基础上增加了 module.exports 的导出方式。

在 output.libraryTarget 为 commonjs2 时,配置 output.library 将没有意义。

this

Написанной библиотеке будет присвоено имя, указанное библиотекой через this , а код вывода и использования будет следующим:

// Webpack 输出的代码
this['LibraryName'] = lib_code;

// 使用库的方法
this.LibraryName.doSomething();

window

Написанной библиотеке будет присвоено имя, указанное библиотекой через окно, то есть библиотека будет смонтирована в окне, а вывод и используемые коды будут следующими:

// Webpack 输出的代码
window['LibraryName'] = lib_code;

// 使用库的方法
window.LibraryName.doSomething();

global

编写的库将通过 global 被赋值给通过 library 指定的名称,即把库挂载到 global 上,输出和使用的代码如下:

// Webpack 输出的代码
global['LibraryName'] = lib_code;

// 使用库的方法
global.LibraryName.doSomething();