Привет всем, яодна чаша в неделю, передняя часть, которая не хочет быть пьяной (завернутой). Если написанной статье посчастливилось получить вашу благосклонность, мне очень повезло~
написать впереди
Webpack — это современный пакетный и модульный инструмент JavaScript. В webpack все файлы являются модулями. Внутри файлы конвертируются через загрузчик, хуки внедряются через плагин, и, наконец, выводится файл, состоящий из нескольких модулей.
На приведенном выше рисунке показан скриншот официального сайта веб-пакета. Видно, что для веб-пакета все файлы, такие как JavaScript, CSS, SCSS и изображения, используются в качестве модулей. После того, как эти модули будут обработаны веб-пакетом, они в конечном итоге будут вывод для браузеров.ресурс.
Преимущества WebPack следующие:
- Сообщество огромно и активно, и последние плагины можно найти очень быстро в быстро развивающемся интерфейсе;
- Сценарии использования не ограничиваются веб-разработкой;
- Иметь хороший опыт разработки;
Первый опыт вебпака
Начать быстро
webpack принадлежит инструментальному модулю npm, поэтому перед установкой вам необходимо инициализировать npm, а затем установитьwebpack
а такжеwebpack-cli
Команда выглядит следующим образом:
npm init -y
npm i webpack webpack-cli -D
Начиная с версии webpack 4.0, конфигурация 0 также может использоваться непосредственно с помощью webpack.Здесь наша структура каталогов проекта выглядит следующим образом:
.
├── src
│ ├── module.js
│ └── index.js
├── index.html
└── package.json
Код в каталоге следующий:
src/module.js
export default () => {
// 创建一个DOM元素
const element = document.createElement('h2')
element.textContent = 'Hello 一碗周'
element.addEventListener('click', () => {
alert('Hello webpack')
})
return element
}
src/index.js
import createTitle from './module.js'
const title = createTitle()
document.body.append(title)
index.html
<!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>webpack快速上手</title>
</head>
<body>
<script type="module"
src="./src/index.js"></script>
</body>
</html>
Затем выполните следующую команду:
npx webpack
Наконец, вы можете увидеть, что появился корневой каталог.dist
каталог, есть каталогmain.js
файл, содержимое файла следующее:
(()=>{"use strict";const e=(()=>{const e=document.createElement("h2");return e.textContent="Hello 一碗周",e.addEventListener("click",(()=>{alert("Hello webpack")})),e})();document.body.append(e)})();
Теперь мы можем изменить его первым.index.html
середина<script>
Справочный адрес этикетки, код выглядит следующим образом:
<script type="module"
src="./dist/main.js"></script>
Затем вы можете увидеть, остался ли эффект таким же, как и раньше.
конфигурационный файл
Начиная с webpack4, webpack поддерживает конфигурацию 0, и его входной файл по умолчаниюsrc/index.js
, файл экспорта по умолчаниюdist/main.js
, если мы хотим настроить этот контент, нам нужно создатьwebpack.config.js
файл для настройки этих конфигураций.
webpack.condfig.js
Это файл js, работающий под узлом, поэтому мы должны написать этот файл в стиле CommonJS.Файл экспортирует объект, и все элементы конфигурации отображаются как свойства объекта.
Пример кода выглядит следующим образом:
const path = require('path')
module.exports = {
// 入口文件
entry: './src/main.js',
// 出口配置
output: {
// 配置出口文件名
filename: 'index.js',
// 文件输出目录,必须是绝对目录
path: path.join(__dirname, 'output'),
},
}
Теперь запустите webpack, и вы можете упаковать его в соответствии с нашей конфигурацией.
Режим работы
В вебпаке есть три режима работы, есть два способа установить режим работы, первый предоставляется конфигурационным файлом.mode
вариант, другой передается в командной строке—mode
параметры, конкретные значения'none' | 'development' | 'production'
, различия между тремя режимами заключаются в следующем:
- none: нет операций по оптимизации кода, максимальная читабельность, самая высокая скорость упаковки.
- production: значение по умолчанию, этот режим будет сжимать код
- разработка: автоматическая оптимизация скорости упаковки и добавление помощи в отладке
ресурсный модуль
В дополнение к файлам js, мы также можем загрузить любой тип модуля ресурсов через загрузчик.Здесь мы берем ресурсы CSS в качестве примера.Сначала установите эти два загрузчика.Команды следующие:
npm i style-loader css-loader -D
Тогда мыsrc
Создайте два файла CSS в каталоге и измените исходное содержимое. Код выглядит следующим образом:
src/module.js
import './module.css'
export default () => {
// 创建一个DOM元素
const element = document.createElement('h2')
element.textContent = 'Hello 一碗周'
element.classList.add('title')
element.addEventListener('click', () => {
alert('Hello webpack')
})
return element
}
src/main.js
import createTitle from './module.js'
import './main.css'
const title = createTitle()
document.body.append(title)
src/module.css
.title {
background-color: silver;
color: #444;
}
src/main.css
body {
margin: 0 auto;
width: 1200px;
background-color: antiquewhite;
}
тогда нашwebpack.config.js
Информация файла конфигурации выглядит следующим образом:
const path = require('path')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'index.js',
path: path.join(__dirname, 'dist'),
// publicPath 用于表示资源的打包后的资源前缀,默认为空
},
module: {
rules: [
{
// 模块的匹配规则
test: /.css$/,
// 从后往前执行,每一项都是一个loader
use: ['style-loader', 'css-loader'],
},
],
},
}
Теперь запустите веб-пакет дляsrc
Четыре приведенных ниже ресурса упакованы в виде файла js.
Загрузчик является ядром реализации веб-пакетом всей модульности внешнего интерфейса.Загружая различные загрузчики, можно загрузить любой тип ресурса.
url-loader
url-loader
Вы можете заставить указанный файл возвращать DataURL, когда размер меньше указанного размера, в противном случае передатьfile-loader
Обработать файлы.
DataURL имеет префиксdata:
URL-адрес протокола, который позволяет создателям контента встраивать небольшие файлы в документы. Как показано ниже:
Во-первых, давайте установим необходимые пакеты npm с помощью следующих команд:
npm i url-loader file-loader -D
url-loader
общая посадкаfile-loader
использовать вместе.
Теперь вводим изображение через js, а потом добавляем его на страницу, код такой:
src/main.js
import createTitle from './module.js'
import './main.css'
import logo from './logo.png'
const title = createTitle()
document.body.append(title)
// 在body中插入图片
const img = new Image()
img.src = logo
document.body.append(img)
Затем мы настраиваемwebpack.config.js
, код показан ниже:
const path = require('path')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'index.js',
path: path.join(__dirname, 'dist'),
},
module: {
rules: [
{
// 模块的匹配规则
test: /.css$/,
// 从后往前执行,每一项都是一个loader
use: ['style-loader', 'css-loader'],
},
{
test: /.png$/,
use: {
loader: 'url-loader',
options: {
// 小于这个值的通过url-loader,转换为DataURL,否则使用file-loader
limit: 10 * 1024,
},
},
},
],
},
}
Затем выполните следующую команду в командной строке:
npx webpack
чтобы вывести все, затем запустите нашindex.html
, вы можете получить следующее:
Вышеупомянутоеurl-loader
способ использования.
Когда использовать DataURL, а когда существовать отдельно?
- Для небольших файлов мы можем использовать DataURL, тем самым уменьшая количество запросов.
- Для больших файлов мы можем существовать отдельно, чтобы улучшить скорость загрузки.
Работа с ES6+
Webpack только завершает функцию упаковки и не конвертирует новые функции ES6+, нам нужно конвертировать его через некоторые загрузчики, наиболее распространенными из которых являютсяbabel-loader
. При использованииbabel-loader
Если это так, вам также необходимо полагаться на соответствующиеbabel
Основной модуль, команда установки выглядит следующим образом:
npm i babel-loader @babel/core @babel/preset-env -D
потомwebpack.config.js
Информация о конфигурации выглядит следующим образом:
module: {
rules: [
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{/* more code */},
],
},
Теперь наш упакованный код написан на ES5.
Как webpack загружает ресурсы
webpack в дополнение к поддержке спецификации модуля ES вводит ресурсы, он также поддерживает использование норм и стандартов AMD CommonJS, хотя он поддерживает различные спецификации, но, если это необходимо, старайтесь не смешивать, как смешивание может привести к значительному снижению ремонтопригодность проекта.
В дополнение к трем методам, предоставляемым JavaScript, есть несколько независимых загрузчиков, которые также запускают загрузку ресурсов, напримерcss-loader
, мы используем@import
инструкция иurl()
функция, вызовет загрузку ресурсов; естьhtml-loader
середина<img>
помеченsrc
свойство также запускает загрузку ресурсов, за исключением<img>
помеченsrc
Свойства Существует множество других свойств, которые поддерживаются по умолчанию.
Разработать загрузчик
Загрузчик является основным механизмом веб-пакета, и принцип его реализации относительно прост, теперь мы разработаем собственный загрузчик.
Разработанный нами загрузчик используется для преобразования синтаксиса Markdown в код HTML.Этапы разработки следующие:
- Экспортировать рабочую функцию, которая принимает один параметр, параметр является входом текущего модуля;
- Установите модуль Parsing Markdown, который используется здесь
marked
, имя установкиnpm i marked -D
; - Наконец, обработанный контент
return
, возвращаемый результат в конечном итоге должен быть фрагментом кода JavaScript. Если возвращаемый контент не является фрагментом кода JavaScript, у нас есть два способа его обработки: один — написать загрузчик, который преобразует наш результат в код JavaScript, а второй — использовать существующий загрузчик для его обработки.
Основной код выглядит следующим образом:
markdown-loader.js
const marked = require('marked')
// source 输入的内容,这里为 Markdown 语法
module.exports = source => {
// 通过 marked 插件进行处理,然后将 HTML 字符串交给下一个 loader 处理
return marked.parse(source)
}
Файл конфигурации веб-пакета выглядит следующим образом:
module: {
rules: [
{
test: /.md$/,
// 除了使用文件名,也可以使用路径的方式引入 loader
use: ['html-loader', './markdown-loader'],
},
],
},
После завершения настройки выполняемnpx webpack
команда для завершения упаковки.
Приведенный выше поток выполнения, блок-схема выглядит следующим образом:
Загрузчик похож на конвейер, обрабатывающий входящий контент и выводящий его.
плагин веб-пакета
Механизм плагинов — еще одна ключевая функция webpack помимо Loader, цель которой — расширить возможности webpack по автоматизации проектов. Ранее мы узнали, что загрузчик предназначен для реализации загрузки различных ресурсов для достижения модульной упаковки; плагин предназначен для решения некоторых других автоматизированных задач, отличных от загрузки ресурсов; например, плагин может помочь нам очистить перед упаковкой.dist
содержание.
Loader+Plugin может помочь нам выполнить большую часть работы по фронтенд-инжинирингу, что дает нам иллюзию, что веб-пакет — это фронтенд-инжиниринг, но это не так.
Часто используемые плагины в webpack
Во-первых, мы вводим некоторые часто используемые плагины в webpack и используем эти плагины в проекте.
-
clean-webpack-plugin
: может помочь нам автоматизировать ситуациюdist
плагин каталога; -
html-webpack-plugin
: автоматически генерировать HTML, используя упакованные результаты; -
copy-webpack-plungin
: Копирует один файл или весь каталог, который уже существует, в каталог сборки.
Давайте посмотрим наwebpack.config.js
Как использовать эти три плагина, код выглядит следующим образом:
const path = require('path')
// 引入对应插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'index.js',
path: path.join(__dirname, 'dist'),
},
module: {
rules: [/* more code */],
},
plugins: [
// 用于清空 dist 目录
new CleanWebpackPlugin(),
// 用于生成 index.html
new HtmlWebpackPlugin({
// 添加 title 属性,在 HTML 文件中通过 htmlWebpackPlugin.options.title 获取,采用 Lodash 模板语法书写
title: 'Webpack Plugin Sample',
// 添加一个 meta 元素,name 为 viewport content 为 width=device-width
meta: {
viewport: 'width=device-width',
},
// 使用哪个 HTML 文件作为模板
template: 'index.html',
}),
// 生成多个页面 创建多个 HtmlWebpackPlugin 实例,用于生成 about.html
new HtmlWebpackPlugin({
// filename 默认为 index.html
filename: 'about.html',
}),
// 拷贝不需要打包的内容
new CopyWebpackPlugin([
// 'public/**'
// 直接拷贝 public 下所有内容至输出目录
'public',
]),
],
}
Здесь используется следующий шаблон:
index.html
<!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>Webpack</title>
</head>
<body>
<div class="container">
<h1>
<!-- 使用 Lodash 模板语法可以直接使用 webpack 中的数据 -->
<!-- htmlWebpackPlugin.options.title 是 htmlWebpackPlugin 插件提供的 -->
<%= htmlWebpackPlugin.options.title
%>
</h1>
</div>
</body>
</html>
Синтаксис шаблона здесьLodashкоторый предоставил.
После выполнения упаковки webpackindex.html
Содержимое файла следующее:
<!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>Webpack</title>
<meta name="viewport" content="width=device-width"></head>
<body>
<div class="container">
<h1>
<!-- 使用 Lodash 模板语法可以直接使用 webpack 中的数据 -->
<!-- htmlWebpackPlugin.options.title 是 htmlWebpackPlugin 插件提供的 -->
Webpack Plugin Sample
</h1>
</div>
<script type="text/javascript" src="index.js"></script></body>
</html>
В дополнение к плагинам, описанным выше, webpack также предоставляет сотни плагинов, нам не нужно понимать их все, если нам нужно перейти на Github для прямого поиска.
разработать плагин
По сравнению с Loader, Plugin обладает более широким набором возможностей, а его механизм плагинов фактически реализуется через механизм хуков. Webpack будет иметь много ссылок в своей работе, в каждой ссылке webpack зарыл какие-то хуки, чтобы мы могли использовать эти хуки для выполнения определенных задач и разработки плагина, как показано на следующем рисунке:
Какие предопределенные хуки мы можем просмотреть в официальной документации веб-пакета, перейдите по ссылкенажми на меня.
webpack требует, чтобы плагин был функцией или включеннымapply
Объект методов. В обычных обстоятельствах мы определим класс, который содержитapply
метод, а затем создайте экземпляр этого класса для использования.
Теперь напишем код для опорожнения упакованного.js
в файле/**/
Для этих плагинов без необходимых аннотаций код реализации выглядит следующим образом:
myWebpackPlugin.js
module.exports = class myWebpackPlugin {
apply(compiler) {
console.log('我的webpack插件开始执行')
compiler.hooks.emit.tap('myWebpackPlugin', compilation => {
// compilation => 可以理解为此次打包的上下文
// 可以通过 compilation.assets 获取所有文件的对象
for (const name in compilation.assets) {
// 通过 for...in 语句遍历到所有的文件名
// name // 当前文件名
// compilation.assets[name].source() 获取该文件下所有的内容
if (name.endsWith('.js')) {
// 如果以 .js 文件结尾,获取内容并删除对应的注释
const contents = compilation.assets[name].source()
const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
// 重新将内容包装一个对象
compilation.assets[name] = {
source: () => withoutComments,
// 约定包含一个 size 属性
size: () => withoutComments.length,
}
}
}
})
}
}
Ссылаясь на веб-пакет, код выглядит следующим образом:
webpack.config.js
const path = require('path')
// 引入对应插件
/* more code */
const myWebpackPlugin = require('./myWebpackPlugin')
module.exports = { /* more code */ },
module: { /* more code */ },
plugins: [
/* more code */
new myWebpackPlugin(),
],
}
После выполнения пакета webpack вы обнаружите, что пакет упакован.js
Бесполезные комментарии в коде удаляются.
Из приведенной выше демонстрации мы узнали, что плагины реализуются путем присоединения функций к хукам в жизненном цикле веб-пакета.
Оптимизация опыта разработки
После вышеуказанного исследования у нас есть предварительное представление о веб-пакете, но если текущей ситуации недостаточно для соответствия нашей среде разработки. Комфортная среда разработки должна удовлетворять следующим требованиям:
- Запускаем наш код с помощью HTTP-сервиса (ближе к продакшену)
- Автоматическая компиляция + автоматическое обновление
- Обеспечивает поддержку SourceMap (быстро находит сообщения об ошибках)
автоматическая компиляция
Для автоматической компиляции webpack нужно только запустить режим Watch.После запуска этого режима webpack будет отслеживать изменения файлов.При их изменении webpack переупаковывает и компилирует.
Есть два способа запустить режим просмотра:
-
Добавить один при запуске веб-пакета
--watch
параметры, примеры следующие:npx webapck --watch
-
существует
webpack.config.js
добавлено вwatch: true
конфигурации, конфигурация следующая:module.exports = { //... watch: true, }; Ti
Автообновление браузера
Автообновление браузера можно сделать черезbrowser-syncЧтобы завершить, инструмент относительно прост в использовании, просто нужно отслеживать изменения файлов. Шаги использования следующие:
-
Сначала установите модуль
npm install -g browser-sync
-
Запустите команду и прослушайте соответствующий файл
browser-sync dist --files "**/*"
Недостатки использования этого метода заключаются в следующем:
- Это более громоздко в работе, потому что нам нужно запускать две команды одновременно;
- Эффективность выполнения снижается, потому что веб-пакету необходимо записать на диск после упаковки, а синхронизация браузера должна прочитать диск после отслеживания соответствующих изменений файла после записи.
Из-за различных проблем webpack предоставляетwebpack-dev-serverинструмент, давайте узнаем об этом инструменте далее.
webpack-dev-server
Инструмент будетавтоматическая компиляцияа такжеАвтообновление браузераи т. д. функцияинтегрированный, он также относительно прост в использовании.После завершения установки будет предоставлена команда cli.Во-первых, нам нужно установить этот инструмент.Команда выглядит следующим образом:
npm i webpack-dev-server -D
После завершения установки используйте следующую команду непосредственно для создания службы HTTP и отслеживания изменений файлов для автоматической упаковки и обновления браузера.Выполните команду следующим образом:
npx webpack-dev-server # 或者 npx webpack server
После запуска порт прослушивания по умолчанию — 8080, доступhttp://127.0.0.1:8080
для доступа к нашим упакованным программам.
Стоит отметить, что использование webpack-dev-server не помещает наши результаты упаковки на диск, а только временно помещает результаты упаковки в нашу память, тем самым ускоряя эффективность сборки и улучшая наш опыт разработки.
Что касается элементов конфигурации webpack-dev-server, вот два:
Элементы конфигурации доступа к статическим ресурсам
Во-первых, давайте представим конфигурацию доступа к статическим ресурсам, которая есть в webpack4.и веб-пакет5различаются следующим образом:
- Элементы конфигурации в webpack4*:
contentBase
, его параметр может быть строкой или массивом, указывающим каталог статического файла; - Элементы конфигурации в webpack5*:
static
, его каталог по умолчанию является общедоступным, вы можете передать емуfalse
, его можно отключить.
Следующий код показывает, как статические ресурсы обрабатываются в webpack4*:
webpack.config.js
const path = require('path')
// 引入对应插件
module.exports = {
/* more code */
devServer: {
contentBase: path.join(__dirname, 'public'),
},
/* more code */
plugins: [
/* more code */
// 开发环境不需要每次都拷贝静态资源,只有在打包编译上线前才会编译打包
// new CopyWebpackPlugin([
// // 'public/**'
// // 直接拷贝 public 下所有内容至输出目录
// 'public',
// ]),
],
}
Элементы конфигурации прокси-API
В настоящее время в большинстве случаев фронтенд-приложение и бэкэнд-интерфейс в процессе разработки берутся из разных источников (Что такое политика одинакового происхождения), что приводит к сбою междоменных запросов.Одно из решений этой проблемы заключается в том, что интерфейс сервера поддерживает CORS (междоменное совместное использование ресурсов), но не все API поддерживают CORS; если мы развернем фронт и бэкэнд с тот же источник, внутренний интерфейс также не нужен для запуска CORS.
Помимо описанного выше, лучший способ решить эту проблему — настроить прокси-сервер, сделать запрос API в качестве прокси-сервера (сервера разработки), а затем прокси-сервер будет запрашивать реальный сервер API, т.к. показано на следующем рисунке:
webpack-dev-server поддерживает реализацию прокси-сервера напрямую через конфигурацию, в основном черезdevServer.proxy
Реализация элемента конфигурации.
демо: здесь мы будемGitHubAPIПрокси на локальный прокси-сервер, информация о конфигурации следующая:
const path = require('path')
module.exports = {
/* more code */
devServer: {
contentBase: path.join(__dirname, 'public'),
proxy: {
// 凡是以 /api 开头的接口,都会被代理
'/api': {
// 例如我们请求 http://localhost:8080/api/users 会被代理到 https://api.github.com/api/users
target: 'https://api.github.com',
// 实际上我们的真正请求地址为 https://api.github.com/users 所有我们需要通过 pathRewrite 配置项进行重写路径
pathRewrite: { '^/api': '' },
// 默认情况下,代理时会保留主机头的来源,可以将 changeOrigin 设置为 true 以覆盖此行为。
changeOrigin: true,
},
},
},
/* more code */
}
Теперь мы выполняем следующую команду, чтобы запустить проект
npx webpack server
доступhttp://localhost:8080/api/users
получить доступhttps://api.github.com/users
.
Source Map
Обзор
В настоящее время код в рабочей среде представляет собой упакованный и скомпилированный код, который сильно отличается от исходного кода, однако на этом пути будет проблема, то есть ошибка не может быть быстро локализована, что влияет на эффективность разработки. .
Карта исходного кода может помочь нам решить эту проблему.Короче говоря, исходная карта представляет собой информационный файл, в котором хранится соответствующая информация об исходном коде и скомпилированном коде.Исходная карта может быстро помочь нам найти.
Использовать Source Map относительно просто, достаточно добавить строку в конце преобразованного кода.
//@ sourceMappingURL=map文件路径
Откройте исходный файл карты, он должен выглядеть так:
{
version : 3,
file: "test.js",
sourceRoot : "",
sources: ["testB.js", "testB.js"],
names: ["print", "maps", "list", "func"],
mappings: "AAgBC,SAAQ,CAAEA"
}
Весь файл представляет собой объект JavaScript, который может быть прочитан интерпретатором. В основном он обладает следующими свойствами:
-
version
: версия исходной карты. -
file
: преобразованное имя файла. -
sourceRoot
: Каталог, в котором находятся файлы до преобразования. Если он находится в том же каталоге, что и файл перед преобразованием, этот элемент пуст. -
sources
: файл до преобразования. Этот элемент представляет собой массив, указывающий, что может быть несколько слияний файлов. -
names
: Все имена переменных и свойств перед преобразованием. -
mappings
: Строка, которая записывает информацию о местоположении, которая представляет собой строку в кодировке Base64-VLQ.
исходная карта конфигурации веб-пакета
Настройка исходных карт в веб-пакете проще и может быть выполнена черезdevtool
Элемент конфигурации включен, пример кода выглядит следующим образом:
module.exports = {
// ...
devtool: none // 不生成 source map
}
В веб-пакете есть много режимов карты исходников.Подробности смотрите в документации.нажмите на меня, чтобы войти.
Хотя webpack предоставляет нам так много режимов Source Map, следующие в основном используются в реальном процессе разработки:
-
cheap-module-eval-source-map
: подходит для среды разработки; -
none
: подходит для производственной среды; -
hidden-source-map
: Обычно больше используется модуль разработки; -
nosources-source-map
: применимый к производственной среде, этот режим может размещать сообщение об ошибке в определенной строке, но не предоставляет информацию об исходном коде.
HMR
Обзор
Хотя автообновление браузера помогло нам решить некоторые проблемы, с этим тоже есть проблема, этоСостояние текущей страницы не сохраняется, HMR, предоставляемый webpack, может решить эту проблему.Полное имя HMR:Hot Module ReplacementПеревод модуля горячей замены, Так называемая горячая замена модуля заключается в замене модуля в режиме реального времени во время работы программы, и это не влияет на рабочее состояние приложения.
Запустить HMR
HMR был интегрирован в модуль WebPack-Dev-Server, что означает, что нам не нужно устанавливать его отдельно при использовании HMR. Существует два способа включения HMR.
-
Запуск через командную строку:
npx webpack-dev-server --hot
-
Включить через конфигурационный файл
// 2. 引用 webpack 提供的 HMR插件 const { HotModuleReplacementPlugin } = require('webpack') module.exports = { /* more code */ devServer: { // 1. 将 devServer.hot 设置为 true hot: true, proxy: { /* more code */ }, }, module: { /* more code */ }, plugins: [ /* more code */ // 3. 使用 HMR 插件 new HotModuleReplacementPlugin(), ], }
Теперь мы можем испытать HMR в проекте, но webpack требует от нас ручного написания логики горячей замены модуля через HMR API.Что касается горячей замены файлов стилей, то нам уже помог написать style-loader, и мы не нужно его написать.
Стоит отметить, что ручной HMR API в первую очередь предназначен для авторов фреймворков и инструментов. Как конечный пользователь, HMR, возможно, уже обработал это для вас в определенной среде.
Оптимизация производственной среды
Хотя такие функции, как HMR и Source Map, предоставляемые webpack, оптимизируют опыт разработки, если эти коды используются в качестве кода производственной среды, должны возникнуть проблемы, и существует множество избыточных кодов.
Понятие режима было введено в webpack4, который также был введен ранее.Разные режимы будут иметь различный опыт.Теперь давайте узнаем, как создавать разные конфигурации для разных сред.
Создание различных конфигураций
Webpack имеет два основных способа создания разных конфигураций для разных сред:
- Файл конфигурации экспортирует различные конфигурации в зависимости от среды.
- Одна среда соответствует одному файлу конфигурации
Далее мы рассмотрим, как использовать эти два метода.
Файл конфигурации экспортирует различные конфигурации в зависимости от среды.
Во-первых, давайте посмотрим, как экспортировать различные конфигурации в зависимости от среды Webpack позволяет нам экспортировать функцию, эта функцияreturn
Объект конфигурации, эта функция принимает два параметра:
- Первый представляет текущий режим
- Второй представляет аргумент в командной строке
Теперь давайте реализуем файл конфигурации на основе введенной информации Код выглядит следующим образом:
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = (env, argv) => {
// env 表示当前模式,可以通过命令行中的--env参数指定
// argv 命令行中的其他参数
const config = {
// 开发环境下的配置
/* mroe code... */
}
if (env === 'production') {
// 生产环境下的配置,对一些配置进行重写,或者增加些配置
config.mode = 'production'
config.devtool = false
config.plugins = [
...config.plugins,
new CleanWebpackPlugin(),
new CopyWebpackPlugin(['public']),
]
}
return config
}
В этот момент мы можем пройти--env
Чтобы передать определенные параметры, такие как производственный режим, упакованные следующим образом:
npx webpack --env production
Этот метод больше подходит для небольших и средних проектов.
Одна среда соответствует одному файлу конфигурации
Использование этого метода обычно предназначено для создания нескольких файлов конфигурации веб-пакета и передачи--config
Параметр указывает конкретный файл конфигурации.
Вообще говоря, мы создаем 3 файла конфигурации веб-пакета, а именно:
webpack.common.js # 公共配置
webpack.dev.js # 开发配置
webpack.prod.js # 生产配置
Настройте его в соответствии с классификацией, а затем используйтеwebpck-merge
предоставляется модулемmerge
Чтобы объединить конфигурацию, команда для установки модуля выглядит следующим образом:
npm i webpack-merge -D
В следующем коде показано, как настроить его в производственной среде:
const merge = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const common = require('./webpack.common')
// 通过 merge 进行配置的合并
module.exports = merge(common, {
mode: 'production',
plugins: [new CleanWebpackPlugin(), new CopyWebpackPlugin(['public'])],
})
Затем команда для использования этого файла конфигурации выглядит следующим образом:
npx webpack --config webpack.prod.js
DefinePlugin
DefinePlugin
позволяет создатькомпилироватьНастраиваемые глобальные константы. Этот плагин предоставляется самим webpack. Он может помочь нам отличить среду разработки от производственной среды. Его использование выглядит следующим образом:
const webpack = require('webpack')
module.exports = {
mode: 'none',
entry: './src/main.js',
output: {
filename: 'bundle.js',
},
plugins: [
new webpack.DefinePlugin({
/**
* 如果这个值是一个字符串,它会被当作一个代码片段来使用。
* 如果这个值不是字符串,它会被转化为字符串(包括函数)。
* 如果这个值是一个对象,它所有的 key 会被同样的方式定义。
* 如果在一个 key 前面加了 typeof,它会被定义为 typeof 调用。
*/
API_BASE_URL: JSON.stringify('https://api.example.com'),
}),
],
}
Используйте следующий код, как показано:
console.log(API_BASE_URL)
Tree-shaking
Tree-shaking — это термин, обычно используемый для описания удаления мертвого кода в контексте JavaScript. Он основан на модульности ES6. Следует отметить, что Tree-shaking — это не параметр конфигурации в веб-пакете, а комбинация набора параметров конфигурации в веб-пакете, эта группа функций будет автоматически включена в режиме производства.
Далее давайте посмотрим, как вручную включить Tree-shaking.Код выглядит следующим образом:
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
filename: 'bundle.js',
},
optimization: {
// 模块只导出被使用的成员
usedExports: true,
// 尽可能合并每一个模块到一个函数中,这个功能称为 Scope Hoisting 这个概念是在 webpack3 中提出的
concatenateModules: true,
// 压缩输出结果,删除没有被使用的成员
minimize: true,
},
}
sideEffects
sideEffects добавлен в webpack4, что позволяет нам определить, есть ли у наших файлов побочные эффекты через конфигурацию.Так называемые побочные эффекты относятся к тому, что модуль делает в дополнение к экспорту членов.
Эта функция также автоматически включается в производственном режиме или черезoptimization.sideEffects
Элемент конфигурации запускается, и для элемента конфигурации устанавливается значениеtrue
Вот и все.
После открытия в webpack вам также необходимоpackage.json
Никаких побочных эффектов при разметке нашего кода в файле нет, код такой:
{
"sideEffects": false
}
Если ваш код имеет некоторые побочные эффекты, вы можете вместо этого предоставить массив наших путей кода с побочными эффектами (поддерживаются как относительные, так и абсолютные пути):
{
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}
код субподряда
Так называемый подпакет кода предназначен для упаковки различной логики кода в разные файлы. Например, у нас есть многостраничное приложение Vue, кроме некоторых общих компонентов на каждой странице, ничего общего с ним нет, здесь мы можем упаковать каждую страницу в файл, чтобы уменьшить размер одного файла и избежать файла быть слишком большим. .
В настоящее время у нас в основном есть два способа реализации кода субподряда, а именно:
- Многократная упаковка
- динамический импорт
Далее давайте рассмотрим его подробно.
Многократная упаковка
Также относительно просто настроить несколько записей упаковки, здесь вам нужно толькоentry
Элемент конфигурации настроен как объект, каждый атрибут в объекте представляет собой запись, а имя атрибута — это имя файла. Пример кода выглядит следующим образом:
/* more code ... */
module.exports = {
/* more code ... */
entry: {
// 对象中的每一个属性表示一个入口,属性名表示文件名称
index: './src/index.js',
album: './src/album.js',
},
output: {
// [name] 表示 entry 中的属性名称,这里的输出结果最终为两个文件
filename: '[name].bundle.js',
},
/* more code ... */
}
Здесь следует отметить, что все файлы js будут внедрены в упакованный HTML по умолчанию, если вам нужно сформулировать конкретные файлы, вы можете передать следующий код:
new HtmlWebpackPlugin({
title: 'Multi Entry',
template: './src/index.html',
filename: 'index.html',
// 值为 entry 中的属性名称
chunks: ['index'],
}),
Также существует тот факт, что мы хотим абстрагировать общий модуль, чего можно добиться с помощью следующей конфигурации:
optimization: {
splitChunks: {
// 自动提取所有公共模块到单独 bundle
chunks: 'all',
},
},
Поскольку у клиента есть механизм кэширования, если мы переиздаем версию, но поскольку у клиента есть кеш, наш код не будет обновляться вовремя; чтобы решить эту проблему, мы можем добавить Hash к имени нашего файла, webpack предоставляет три хэши, а именно:
-
hash
: Хэш уровня предмета -
chunkhash
: Хэш на уровне блоков -
contenthash
: Хэш на уровне файла, рекомендуется
Пример кода выглядит следующим образом:
/* more code... */
module.exports = {
/* more code... */
output: {
filename: '[name]-[contenthash:8].bundle.js'
},
/* more code... */
}
динамический импорт
Реализация динамического импорта также относительно проста, нужно толькоimport()
метод. Динамически импортированные модули будут автоматически подпакованы.Преимущество этого метода в том, что когда модуль используется, модуль загружается, что значительно экономит нашу пропускную способность и трафик.
Мы также можем использовать указанные имена для подпакетных модулей с помощью «магических аннотаций», например.
import(/* webpackChunkName: 'components1' */ './posts/posts').then(
({ default: posts }) => {
mainElement.appendChild(posts())
},
import(/* webpackChunkName: 'components2' */ './album/album').then(
({ default: album }) => {
mainElement.appendChild(album())
},
)
Здесь будет две записи упаковки. Если имена в «волшебном комментарии» совпадают, они будут упакованы на одну и ту же страницу.
Извлечь CSS в один файл
Наконец, давайте представим, как предоставить CSS для одного файла, здесь мы рекомендуем использовать webpack.mini-css-extract-plugin
Плагин, который может извлекать CSS непосредственно в один файл.
Если окончательный CSS не будет больше 150 КБ, CSS все равно будет храниться в HTML.<style>
Этикетки более дружелюбны.
напиши в конце
С ростом сложности интерфейса веб-пакет стал обязательным навыком для всех разработчиков интерфейса, и он действительно не работает без изучения.