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
Импорт и экспорт.
Использовать дерево
- Не компилируйте модули 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();