разделение кода
Разделение кода (code splitting
)Даwebpack
Уникальная технология, которая может разделить код по определенной форме, вместо того, чтобы загружать все сразу, а загружать по запросу, может эффективно уменьшить размер загружаемых ресурсов на первом экране.
CommonsChunkPlugin
CommonsChunkPlugin
даwebpack4-
Встроенный плагин может объединять несколькоchunk
извлечено из публичной части. Тем самым уменьшая повторную упаковку модулей в процессе разработки и повышая скорость разработки. Общий размер ресурса также уменьшается, и можно эффективно использовать кеш клиента.
CommonsChunkPlugin
Настраиваемые свойства следующие.
-
name
:будетchunks
атрибут, соответствующийsource chunk
Общие модули в извлечении дляname
в, если не указаноchunks
, который будет извлекаться по умолчаниюentry chunks
публичные модули в -
chunks
: уточнитьsource chunk
, то есть из которогоchunk
Найти общие модули в, опуская этот параметр по умолчаниюentry chunks
-
filename
: имя извлеченного файла ресурсов, которое поддерживает динамическую генерацию в виде языка шаблонов. -
minChunks
: может быть числом, функцией илиInfinity
Упаковка без плагинов
Корневой каталог включаетpackage.json
,webpack.config.js
иsrc
Ждать,src
каталог включаетfoo.js
,bar.js
иutils.js
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^3.10.0"
},
"dependencies": {
"jquery": "^3.2.1"
}
}
// webpack.config.js
module.exports = {
entry: {
foo: './src/foo.js',
bar: './src/bar.js'
},
output: {
filename: './dist/[name].js'
}
}
// src/bar.js
import jquery from 'jquery'
import { log } from './utils.js'
console.log(jquery, log, 'bar')
// src/foo.js
import jquery from 'jquery'
import { log } from './utils.js'
console.log(jquery, log, 'foo')
// src/utils.js
export function log(){
console.log('log')
}
После запуска пакета он окажется в корневом каталогеdist
создание папкиbar.js
иfoo.js
,вjquery
иutils
упакованы в эти два файла.
Наконец, вам нужно добавить на страницуscript
Знакомство с этикеткойfoo.js
иbar.js
.
// src/index.html
<html lang="zh-CN">
...
<body>
<script src="./bar.js"></script>
<script src="./foo.js"></script>
</body>
</html>
Извлечь общедоступный код
Исправлятьwebpack.config.js
, добавлятьCommonsChunkPlugin
Плагины извлекают общие модули.
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
foo: "./src/foo.js",
bar: "./src/bar.js",
},
output: {
filename: "./dist/[name].js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js",
}),
],
}
следующееfoo.js
иbar.js
сторонние модули вjquery
и публичные модули внутри проектаutils
,webpack
Все запущенные файлы упакованы вvendor.js
,foo.js
иbar.js
Объем значительно уменьшается.
страницаvendor.js
быть в другомjs
импортировал раньше.
// dist/index.js
<html lang="zh-CN">
...
<body>
<script src="./vendor.js"></script>
<script src="./bar.js"></script>
<script src="./foo.js"></script>
</body>
</html>
Извлечь время выполнения
При использовании плагина для извлечения общедоступных модулей извлекаемые ресурсы включают не только код модуля, но иwebpack
Время выполнения.webpack
Среда выполнения относится к коду, который инициализирует среду, например, создание объектов кэша модуля, объявление функций загрузки модуля и т. д.
Первый нижеCommonsChunkPlugin
экземпляр будет извлеченfoo.js
иbar.js
сторонние модули вjquery
, локальный модульutils
иwebpack
файл времени выполнения вvendor
середина.
и следующийCommonsChunkPlugin
пример сноваvendor
Извлеките файлы среды выполнения вruntime
средний, финальныйvendor
включает сторонние модулиjquery
и локальные модулиutils
,runtime
содержитwebpack
файл времени выполнения.
Уведомлениеruntime
изCommonsChunkPlugin
должен появиться вplugins
Наконец, иначеwebpack
Модуль не будет извлечен нормально.
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
foo: "./src/foo.js",
bar: "./src/bar.js",
},
output: {
filename: "./dist/[name].js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js",
}),
new webpack.optimize.CommonsChunkPlugin({
name: "runtime",
filename: "./dist/[name].js",
chunks: ["vendor"],
}),
],
}
Выполнить пакет будет вdist
создается в каталогеruntime.js
иrendor.js
и другие документы.
вышеplugins
Эквивалентно следующему способу.
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "runtime"],
filename: "./dist/[name].js",
}),
]
также можно сделать черезminChunks
Для достижения цели извлечения файлов среды выполнения при настройкеminChunks
заn
, это означает, что модуль может быть толькоn
Кусокchunks
При этом ссылка будет извлечена,CommonsChunkPlugin
По умолчанию две записи обращаются только к одному модулю.chunk
Ссылка будет извлечена, т.е.minChunk
По умолчанию2
.
Установить какInfinity
Указывает, что порог извлечения бесконечно высок, т.е. все модули не будут извлечены.
Установить какInfinity
Как правило, есть две функции, первая — разрешитьwebpack
извлекать только определенные модули, другой — генерировать модуль без каких-либо модулей, а только содержащийwebpack
файл времени выполненияruntime
.
Следующие средства от входаchunk
извлеките файлы среды выполнения изfoo
иbar
Извлечь сторонние модули и локальныеutils
модуль.
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "runtime",
filename: "./dist/[name].js",
minChunks: Infinity,
}),
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js",
chunks: ["foo", "bar"],
}),
]
Извлечение сторонних модулей и локальных модулей
первыйCommonsChunkPlugin
примерminChunks
Установить какInfinity
, что означает, что все модули не будут извлечены, в это времяname
Установить какruntime
можно извлечьwebpack
файл времени выполнения. Однако из-заname
Назначенvendor
,иvendor
на входеentry
Это заявлено вvendor
Модуль, соответствующий массиву (jquery
)иwebpack
файл времени выполнения.
разCommonsChunkPlugin
пример изvendor
извлеченный изwebpack
файл времени выполнения, на этот разvendor
содержит только сторонние модулиjquery
,runtime
содержит файлы времени выполнения.
последнийCommonsChunkPlugin
Пример последний изfoo
иbar
извлеките локальный модуль вutils
середина.
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
foo: "./src/foo.js",
bar: "./src/bar.js",
vendor: ["jquery"],
},
output: {
filename: "./dist/[name].js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js",
minChunks: Infinity,
}),
new webpack.optimize.CommonsChunkPlugin({
name: "runtime",
filename: "./dist/[name].js",
chunks: ["vendor"],
}),
new webpack.optimize.CommonsChunkPlugin({
name: "utils",
filename: "./dist/[name].js",
chunks: ["foo", "bar"],
}),
],
}
Выполнить пакет будет вdist
создается в каталогеvendor.js
,utils.js
иruntime.js
.
вышеplugins
Эквивалентно следующему способу.
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "runtime"],
filename: "./dist/[name].js",
minChunks: Infinity,
}),
new webpack.optimize.CommonsChunkPlugin({
name: "utils",
filename: "./dist/[name].js",
chunks: ["foo", "bar"],
}),
]
Другой способ — использоватьminChunks
функция, где перваяCommonsChunkPlugin
примерminChunks
в функции,module.resource
полный путь, включая имя модуля,count
Количество обращений к модулю путем обхода входного файла и зависимых от него модулей, если модуль находится вnode_modules
, он будет извлечен вvendor
, по существу такой способ позволяетvendor
Сохраняются только сторонние модули.
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
foo: "./src/foo.js",
bar: "./src/bar.js",
},
output: {
filename: "./dist/[name].js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js",
minChunks: function(module, count) {
return module.resource && module.resource.includes("node_modules")
},
}),
new webpack.optimize.CommonsChunkPlugin({
name: "runtime",
filename: "./dist/[name].js",
chunks: ["vendor"],
}),
new webpack.optimize.CommonsChunkPlugin({
name: "utils",
filename: "./dist/[name].js",
chunks: ["foo", "bar"],
}),
],
}
Страница относится к каждомуjs
Способ следующий.
<html lang="zh-CN">
...
<body>
<script src="./runtime.js"></script>
<script src="./utils.js"></script>
<script src="./vendor.js"></script>
<script src="./foo.js"></script>
<script src="./bar.js"></script>
</body>
</html>
Одностраничное приложение, извлекающее сторонние модули
Одностраничное приложение может создать отдельную запись следующим образомvendor
Содержит сторонние модулиvue
иwebpack
файл времени выполнения.
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
main: "./src/main.js",
vendor: ["vue"],
},
output: {
filename: "./dist/[name].js",
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js",
}),
],
}
финал после упаковкиdist
создается в каталогеmain.js
иvendor.js
.
Цитируется на страницеjs
Способ следующий.
<html lang="zh-CN">
...
<body>
<script src="./vendor.js"></script>
<script src="./main.js"></script>
</body>
</html>
Асинхронная загрузка ресурсов
Когда количество модулей слишком велико, а объем ресурсов слишком велик, некоторые временно неиспользуемые модули загружаются с задержкой. Сделайте ресурсы, загружаемые при первом отображении страницы, как можно меньше, а последующие модули будут ждать, пока не наступит нужное время, чтобы инициировать загрузку.Этот метод является загрузкой по запросу.
webpack
Официально рекомендуетсяimport
функция для асинхронной загрузки модуля и возвратаPromise
объект.
Следующий корневой каталог включаетwebpack.config.js
иsrc
папки и т. д., гдеsrc
включить нижеmain.js
,utils.js
,main.js
прошедшийimport
Асинхронная загрузкаutils.js
.
// src/main.js
setTimeout(() => {
import(/* webpackChunkName: "utils-chunk" */ "./utils.js")
}, 2000)
console.log("main")
// src/utils.js
import jquery from "jquery"
console.log(jquery, "utils")
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "./dist/[name].js",
chunkFilename: "./dist/[name].js",
publicPath: "../",
},
}
output.chunkFilename
Используется для указания асинхронногоchunk
Имя файла, способ поддержки языка шаблона, асинхронностьchunk
По умолчанию имя отсутствует, его значение по умолчанию равно[id].js
,как0.js
,1.js
Ждать.
пройти черезwebpack
Все уникальные аннотации позволяютwebpack
получить асинхронныйchunk
имя, как в предыдущем/* webpackChunkName: "utils-chunk" */
, после упаковкиchunk
имяutils-chunk
.
После упаковкиmain.js
В качестве загружаемого ресурса на первом экране страница проходитscript
теги для ссылки, в то время как косвенные ресурсы (utils-chunk.js
) запросить путь для прохожденияoutput.publicPath
указать.
На страницу ссылаются следующим образом.
<html lang="zh-CN">
...
<body>
<script src="./main.js"></script>
</body>
</html>
2s
позже на страницеhead
Динамическая вставка внутри этикеткиscript
этикетка, ссылка на этикеткуutils-chunk.js
.
optimization.splitChunks
CommonsChunkPlugin
Общие модули могут быть извлечены во многих сценариях, но их дефекты также очень очевидны.
- не замужем
CommonsChunkPlugin
Экземпляры могут извлекать только одинvendor
, чтобы извлечь несколькоvendor
Нужно добавить большеCommonsChunkPlugin
например, легко вызвать дублирование кода конфигурации - несколько
CommonsChunkPlugin
Между экземплярами может существовать логическая связь. Только правильная логическая связь может гарантировать, что извлеченный код соответствует ожидаемому, а некоторые конфигурации непросты для понимания и не могут быть использованы «из коробки».
webpack4
удаленCommonsChunkPlugin
, улучшенCommonsChunkPlugin
И переработана и реализована функция фрагментации кода, готовая к прохождениюoptimization.splitChunks
свойства для упрощения настройки разделения кода.
Извлечь общедоступный код
будетwebpack
обновление версии, даCommonsChunkPlugin
Измените сценарий упаковки асинхронных ресурсов наsplitChunks
,регулироватьwebpack.config.js
.
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "[name].js",
},
optimization: { splitChunks: { chunks: "all" } },
mode: "none",
}
// package.json
{
...
"devDependencies": {
"webpack": "4.29.4",
"webpack-cli": "3.2.3"
}
}
Результат запуска пакета следующий, гдеmain.js
иutils.js
упакованы индивидуально,utils.js
сторонние модули, упомянутые вjquery
был упакован вvendors~utils-chunk.js
.
ссылка на страницуmain.js
Задний,2s
позже на страницеhead
Вставьте внутрь этикеткиvendors~utils-chunk.js
иutils-chunk.js
, количество параллельных запросов в это время равно2
.
CommonsChunkPlugin
Сцена не извлеченаutils
серединаjquery
модуль, если только модифицироватьutils
В одной строке кода клиенту достаточно повторно загрузить весьutils-chunk.js
. иsplitChunks
Извлекатьjquery
модуль,jquery
не будет часто меняться, модифицироватьutils
В одной строке кода клиенту нужно только повторно скачатьutils-chunk.js
, а размер этого файла всего1 KiB
нет, иvendor~utils-chunk.js
Он также хорошо использует кэширование браузера.
Условия экстракции
CommonsChunkPlugin
Извлечение конкретных модулей через элементы конфигурации ближе к императиву. иsplitChunks
Разница в том, что задаются только некоторые условия извлечения, такие как объем модуля, расположение модуля и т.д. Когда некоторые модули удовлетворяют этим условиям, они будут автоматически извлечены, что ближе к декларативному.splitChunks
Условия извлечения по умолчанию следующие.
- извлечен
chunk
отnode_modules
каталог, вnode_modules
Модули, как правило, являются общими модулями, которые больше подходят для извлечения. - извлечен
javascript chunk
больше, чем30KB
,CSS chunk
больше, чем50KB
, объем ресурсов после извлечения, как правило, слишком мал, и эффект оптимизации, вызванный этим, также относительно общий. - В процессе загрузки по требованию максимальное значение ресурсов, запрошенных параллельно, меньше или равно
5
- При загрузке в первый раз максимальное количество ресурсов, запрошенных параллельно, меньше или равно
3
Извлечь несколько асинхронных ресурсов
Корневой каталог включаетwebpack.config.js
иsrc
папка,src
включить нижеmain.js
иfoo.js
,bar.js
.
// src/main.js
setTimeout(() => {
import(/* webpackChunkName: "bar-chunk" */ "./bar.js")
import(/* webpackChunkName: "foo-chunk" */ "./foo.js")
}, 2000)
console.log("main")
// src/bar.js
import react from "react"
console.log(react, "bar")
// src/foo.js
import vue from "vue"
import react from "react"
console.log(vue, react, "foo")
После запуска пакетаwebpack
создастvue
кодовый блок (vendor~foo-chunk
),foo-chunk
Зависит от этого блока кода и также создает содержащийreact
кодовый блок (vendors~bar-chunk~foo-chunk
),foo-chunk
иbar-chunk
Зависит от этого блока кода.
существуетimport('./bar.js)
При вызове,vendors~bar-chunk~foo-chunk.js
иbar-chunk.js
Загружать параллельно. существуетimport('./foo.js)
При вызове,vendor~foo-chunk.js
иfoo-chunk.js
Параллельная загрузка, в данный момент загружать не нужноvendors~bar-chunk~foo-chunk.js
, вы можете напрямую читать кеш.
Параметр конфигурации splitChunks
webpack
официально даноsplitChunks
Значения по умолчанию следующие.
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
chunks
chunks
НастраиваемыйsplitChunks
рабочий режим, включая три необязательных значенияasync
(дефолт),initial
,all
,вasync
т.е. извлекать только асинхронноchunk
,initial
Извлечь только входящую синхронизациюchunk
,all
Оба режима включены одновременно.
Корневой каталог включаетwebpack.config.js
иsrc
,src
включить нижеmain.js
,bar.js
иfoo.js
.
// src/main.js
import jquery from "jquery"
setTimeout(() => {
import(/* webpackChunkName: "bar-chunk" */ "./bar.js")
import(/* webpackChunkName: "foo-chunk" */ "./foo.js")
}, 2000)
console.log(jquery, "main")
// src/bar.js
import react from "react"
console.log(react, "bar")
// src/foo.js
import vue from "vue"
import react from "react"
console.log(vue, react, "foo")
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "[name].js",
},
optimization: { splitChunks: { chunks: "all" } },
mode: "none",
}
После запуска пакетаmain.js
сторонние модули вjquery
извлечено вvendor~main.js
, остальные коды зарезервированы доmain.js
середина,foo.js
сторонние модулиvue
извлечено вvendor~foo-chunk.js
, оставшийся код зарезервирован доfoo-chunk.js
середина,foo.js
иbar.js
сторонние модулиreact
извлечено вvendor~foo-chunk~bar-chunk.js
,bar.js
Остальная часть кода зарезервирована доbar-chunk.js
.
Исправлятьchunks
собственностьinitial
снова упаковано, где толькоmain.js
сторонние модули вjquery
извлечено вvendor~main.js
, оставшийся код зарезервирован доmain.js
,foo.js
иbar.js
Сторонние модули вfoo-chunk.js
иbar-chunk.js
.
Исправлятьchunks
собственностьasync
После упаковки снова,main.js
Средний код зарезервирован до тех пор, покаmain.js
, сторонние модули не извлекаются,foo.js
сторонние модули вvue
извлечено вvendor~foo-chunk.js
, оставшийся код зарезервирован доfoo-chunk.js
,foo.js
иbar.js
сторонние модулиreact
извлечено вvendor~bar-chunk~foo-chunk.js
,bar.js
Оставшийся код вbar-chunk.js
.
условие совпадения
-
minSize
: минимальный размер извлеченного блока кода перед сжатием, по умолчанию30000
(30KB
) -
maxSize
: максимальный размер извлеченного блока кода перед сжатием, по умолчанию0
, т.е. неограниченный размер -
minChunks
: количество ссылок на модуль, по умолчанию1
-
maxAsyncRequests
: максимальное количество загрузок по запросу, по умолчанию5
-
maxInitialRequests
: максимальное количество начальных начальных загрузок, по умолчанию3
-
automaticNameDelimiter
: извлеченный блок кода автоматически генерирует разделитель имен, по умолчанию ~ -
name
: имя извлеченного файла блока кода, по умолчаниюtrue
, то есть имя файла генерируется автоматически
группа кеша
Группа кешаcacheGroups
По умолчанию включаетvendors
иdefault
два правила,vendors
для добычиnode_modules
в подходящих модулях,default
Он работает с модулями, на которые ссылаются несколько раз. Чтобы отключить определенное правило, вы можете напрямую установить его вfalse
.
cacheGroups
Каждый из них наследует или переопределяет внешнийsplitChunks
значения параметров в , например.cacheGroups.vendors
ни один из предметовminChunks
свойство, оно унаследует внешнееsplitChunks.minChunks
значение атрибутаcacheGroups.vendors.minChunks
за1
.cacheGroups.default
предмет имеетminChunks
свойство, оно перезапишет внешнийsplitChunks.minChunks
характеристики.
Помимо указанных выше значений параметров,cacheGroups
Предусмотрены три дополнительных свойства конфигурации.
-
test
: может соответствовать пути модуля илиchunk
имя, по умолчанию для всех модулей -
priority
: указывает вес извлечения, чем выше значение, тем выше приоритет. Модуль может удовлетворять несколькимcacheGroups
, который извлекается, контролируется наибольшим весом -
reuseExistingChunk
: использовать ли существующийchunk
,true
значит, если текущийchunk
Включенные модули извлечены, новые создаваться не будут.
Корневой каталог включаетwebpack.config.js
иsrc
папка,src
включить нижеmain.js
иutils.js
.
// src/main.js
import Vue from "vue"
import Vuex from "vuex"
import VueRouter from "vue-router"
import { log } from "./utils.js"
console.log(Vue, Vuex, VueRouter, log, "main")
// src/utils.js
export function log() {
console.log("log")
}
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "[name].js",
},
optimization: {
splitChunks: {
chunks: "all",
},
},
mode: "none",
}
Запуск упакованного стороннего модуляvue
,vuex
иvue-router
извлечено вvendors~main.js
,main.js
оставшийся код иutils.js
код зарезервирован доmain.js
середина.
Если вы хотите извлечь его отдельноutils.js
, вы можете настроить его следующим образомcacheGroups
,вmodule.resource
полный путь, включая имя модуля.
// webpack.config.js
splitChunks: {
chunks: "all",
cacheGroups: {
utils: {
test: (module) => {
return /src\\utils/.test(module.resource)
},
priority: -20,
minSize: 0,
},
default: false,
}
}
Запуск упакованного стороннего модуляvue
,vuex
,vue-router
извлечено вvendors~main.js
середина,utils.js
Код извлекается вutils~main.js
середина,main.js
Остальной код зарезервирован.
Производственная среда
Производственная среда отличается от среды разработки.Производственная среда фокусируется на взаимодействии с пользователем, на том, как позволить пользователям быстрее загружать ресурсы, в том числе на том, как сжимать ресурсы, добавлять переменные среды для оптимизации упаковки и как максимально использовать кэши браузера.
Конфигурация среды
одиночная конфигурация
Единая конфигурация, которая используется независимо от средыwebpack.config.js
, просто передайте параметры переменных среды в начале сборки, а затемwebpack.config.js
Какая конфигурация используется, определяется условием.
Уведомлениеwindows
Не поддерживается для использованияENV=development
способ, команда будет заблокирована и будет сообщено об ошибке, сторонние плагиныcross-env
решает эту проблему.
cnpm i cross-env --save-dev
Корневой каталог включаетwebpack.config.js
иsrc
папки и т. д., гдеsrc
включить нижеindex.html
иmain.js
.
// package.json
{
...
"scripts": {
"dev": "cross-env ENV=development webpack-dev-server",
"build": "cross-env ENV=production webpack"
},
"devDependencies": {
"webpack": "4.29.4",
"webpack-cli": "3.2.3",
"webpack-dev-server": "^3.1.14",
"html-webpack-plugin": "^3.2.0"
}
}
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ENV = process.env.ENV
const isProd = ENV === 'production'
module.exports = {
entry: './src/main.js',
output: {
filename: isProd ? "./[name].[chunkhash:8].js" : "./[name].js",
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
})
]
}
// src/index.html
<html lang="zh-CN">
<head>
<title>hello world</title>
</head>
<body>
<p>hello world</p>
</body>
</html>
// src/main.js
console.log("hello world")
бегатьdev
Script, консоль может просматривать упакованный выходной файл среды разработки.
бегатьbuild
Команда сценария для просмотра выходного файла после упаковки.
Конфигурация с несколькими средами
Для каждой среды можно создать отдельный файл конфигурации, например, среда разработкиwebpack.dev.config.js
, производственная средаwebpack.prod.config.js
, но два конфигурационных файла обычно имеют повторяющиеся части, которые необходимо менять каждый раз при изменении, что не способствует сопровождению.
также можно создать отдельныйwebpack.config.js
, то два другихjs
Обратитесь к этому файлу и добавьте конфигурацию своей среды. Но обычно используйте сторонние плагиныwebpack-merge
, Привык делатьwebpack
Конфигурация объединена для облегчения управления конфигурацией различных сред.
Корневой каталогbuild
,package.json
,src
папка,src
включить нижеindex.html
иmain.js
.
// package.json
{
...
"scripts": {
"dev": "webpack-dev-server --config=./build/webpack.dev.config.js",
"build": "webpack --config=./build/webpack.prod.config.js"
}
}
build
включеныwebpack.config.js
,webpack.dev.config.js
иwebpack.prod.config.js
.
// build/webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./src/main.js",
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
}
// build/webpack.dev.config.js
const webpackConfig = require("./webpack.config.js")
module.exports = {
...webpackConfig,
output: {
filename: "./[name].js",
},
}
// build/webpack.prod.config.js
const webpackConfig = require("./webpack.config.js")
module.exports = {
...webpackConfig,
output: {
filename: "./[name].[chunkhash:8].js",
},
}
работать отдельноdev
иbuild
Сценарий команды, выходные данные согласуются с одной конфигурацией.
производственный режим
Раноwebpack
В версии слишком много элементов конфигурации, используемых в разных средах, которые нельзя использовать из коробки.webpack4
добавлено вmode
Элемент конфигурации, с помощью которого можно переключать режим упаковки.
В настоящее время в производственной среде находится следующее:webpack
Элементы конфигурации, подходящие для производственных сред, добавляются автоматически.
// webpack.config.js
module.exports = {
...
mode: "production"
}
переменная среды
существуетwebpack
можно использовать вDefinePlugin
Добавьте разные переменные среды для производственной среды и среды разработки, т.е.webpack.DefinePlugin
используется для установки глобальных переменных в среде браузера (не будет монтироваться вwindow
начальство).
webpack.DefinePlugin
Применяется ко всем модулям и полностью заменяет переменные среды в модуле установленными значениями.
Корневой каталогwebpack.config.js
,package.json
иsrc
,src
включить нижеmain.js
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "4.29.4",
"webpack-cli": "3.2.3"
}
}
// webpack.config.js
const webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
filename: "./[name].js",
},
plugins: [
new webpack.DefinePlugin({
ENV: JSON.stringify('production'),
})
],
mode: 'development',
devtool: 'none',
}
// src/main.js
console.log(ENV)
Проверьте выходной каталог после упаковкиdist
серединаmain.js
файл, которыйENV
полностью заменяется"production"
.
// dist/main.js
"./src/main.js":(function(module, exports) {
console.log("production")
})
Обратите внимание, что для строк или объектов, содержащих строки, добавьтеJSON.stringify
, если не добавленоJSON.stringify
, после подстановки станет имя переменной, а не строковое значение, то есть указанное вышеENV
будет заменен наproduction
(без строковых кавычек).
В дополнение к значениям строкового типа также могут быть установлены другие типы переменных среды.
new webpack.DefinePlugin({
ENV: JSON.stringify("production"),
ENVIR: '"development"',
IS_PRODUCTION: true,
ENV_ID: 1038,
CONSTANTS: JSON.stringify({
TYPES: ["foo", "bar"],
}),
})
Многие фреймворки и библиотеки используютprocess.env.NODE_ENV
Как переменная, которая отличает среду разработки от производственной среды, ее значение равноproduction
То есть текущая среда является производственной средой, и код среды разработки, такой как информация о предупреждениях и журналы, будет удален при упаковке библиотеки и фреймворка, что поможет уменьшить размер кода и улучшить работу. скорость.
можно настроить следующим образомprocess.env.NODE_ENV
переменная, обратите внимание, что если она включенаmode: 'production'
,ноwebapck
будет установлено автоматическиprocess.env.NODE_ENV
значение, нет необходимости устанавливать его снова.
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("development"),
})
Дифференцировать путь окружающей среды
scripts
webpack4
введение версииmode
свойства, в том числеdevelopment
,production
,none
Три режима.
development
режим поместит модуль внутрьprocess.env.NODE_ENV
Значение установлено наdevelopment
, позволяя среде разработкиwebpack
плагин.production
режим поместит модуль внутрьprocess.env.NODE_ENV
Значение установлено наproduction
, позволяя производитьwebpack
плагин.
Доступны наwebpack.config.js
установить вmode
, также доступный вpackage.json
серединаscripts
установить в команде скрипта--mode
.
// package.json
"scripts": {
"build-dev": "webpack --mode=development",
"build-prod": "webpack --mode=production"
}
Также по умолчанию установлены специальные скриптыmode
,следующее"dev": "webpack-dev-server"
изmode
заdevelopment
,"build": "webpack"
изmode
заproduction
.
// package.json
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack"
}
А внутри модуля можноprocess.env.NODE_ENV
Значение оценки текущей среды, обратите внимание наmode
Способ заключается в том, что его можно передать в любом модуле с помощьюprocess.env.NODE_ENV
Получить текущие переменные среды, но не можетnode
окрестности(webpack
файл конфигурации), чтобы получить текущие переменные среды.
// package.json
"scripts": {
"build": "webpack"
}
// src/mian.js
console.log(process.env.NODE_ENV) // production
// webpack.config.js
console.log(process.env.NODE_ENV) // undefined
module.exports = {
entry: "./src/main.js",
...
}
следующееwebpack.config.js
Вы можете получить переменные среды через функции, но вы не можете получить переменные среды вне функций.main.js
Средняя выходная мощностьproduction
из-за специального скрипта"build": "webpack"
будет установлено по умолчаниюmode
заproduction
модель.
// package.json
"scripts": {
"build-dev": "webpack --env=development",
"build-prod": "webpack --env=production"
}
// webpack.config.js
console.log(process.env.NODE_ENV) // undefined
module.exports = (env) => {
console.log(env) // development | production
return {
entry: "./src/main.js",
...
}
}
// src/main.js
console.log(process.env.NODE_ENV) // production
webpack.DefinePlugin
scripts
путь внутри модуляprocess.env.NODE_ENV
Только несколько фиксированных значений.
webpack.DefinePlugin
Затем вы можете установить модульprocess.env.NODE_ENV
любое значение, но оно не может бытьnode
Получите текущие переменные среды в файле environment.
// package.json
"scripts": {
"build": "webpack"
}
// webpack.config.js
const webpack = require("webpack")
console.log(process.env.NODE_ENV) // undefined
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('dev'),
})
]
}
// src/main.js
console.log(process.env.NODE_ENV) // dev
cross-env
Ни один из двух вышеперечисленных методовnode
окрестности(webpak
файл конфигурации) для получения переменных окружения,scripts
Метод может быть получен только внутри функции через метод функции и не может быть получен в функции.webpack.config.js
чтобы получить текущие переменные среды.
С помощью сторонних плагиновcross-env
допустимыйnode
Среда получает текущую переменную среды и может произвольно устанавливать значение переменной среды.
// package.json
"scripts": {
"build": "cross-env ENVIR=prod webpack"
},
"devDependencies": {
"cross-env": "^7.0.3",
...
}
// webpack.config.js
console.log(process.env.ENVIR) // prod
module.exports = {
entry: "./src/main.js",
...
}
// src/main.js
console.log(process.env.ENVIR) // undefined
source map
source map
Относится к процессу преобразования скомпилированного, сжатого и упакованного кода обратно в исходный код.webpack
Упакованный и сжатый код практически не читается, в это время код выдает ошибку, и очень сложно отследить его стек вызовов.
Конфигурация не включена
Корневой каталог включаетpackage.json
,webpack.config.js
иsrc
папка,src
включить нижеindex.html
,main.js
иstyle.scss
,вMiniCssExtractPlugin
Основная функция плагина заключается в извлеченииcss
файл стиля.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"css-loader": "^0.28.9",
"html-webpack-plugin": "^3.2.0",
"node-sass": "^4.7.2",
"sass-loader": "^6.0.7",
"mini-css-extract-plugin": "^0.5.0",
"style-loader": "^0.19.0",
"webpack": "4.29.4",
"webpack-cli": "^3.2.3"
}
}
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
entry: "./src/main.js",
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css",
}),
],
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader',
'sass-loader'
],
}
]
}
}
// src/index.html
<html lang="zh-CN">
<body>
<p>hello world</p>
</body>
</html>
// src/main.js
import './index.scss'
console.log('source-map')
// src/index.scss
$color: red;
p {
color: $color;
}
воплощать в жизньbuild
После того, как скрипт упакован, вывод в корневую директориюindex.html
,main.css
,main.js
,использоватьVS Code
Плагин редактораLive Server
,index.html
Щелкните правой кнопкой мыши внутриOpen with Live Server
,Проверятьindex.html
Развернут на сервере.
Проверьте вывод в консоли ниже.
Нажмитеmian.js:formatted:76
Перейти к следующему местоположению, но вы можете только просмотреть расположение этого оператора вывода в упакованном коде и не можете вернуться к исходному коду.
Затем просмотрите стили в консоли.
Нажмитеmian.css:1
Если вы перейдете к следующему местоположению, вы сможете только просмотреть упакованный код стиля, но не сможете вернуться назад.
включить конфигурацию
существуетwebpack.config.js
добавлено вdevtool
включиjs
документsource map
, а дляscss
,css
вам нужно добавить доп.source map
элемент конфигурации.
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
}
]
},
devtool: 'source-map'
}
выполнить сноваbuild
упаковка скрипта,dist
В каталоге будет еще несколькоmap
файл, так как включенdevtool
элемент конфигурации,source map
Он будет проходиться шаг за шагом с исходным кодом до окончательногоmap
файл, имя файла которого по умолчанию соответствует выходному файлу плюс.map
суффикс, напримерmain.js.map
,main.js
В конце по умолчанию будет добавлен комментарий для идентификацииmap
Расположение файла.
// main.js
...
//# sourceMappingURL=main.js.map
Еще раз проверьте результат вывода на консоли, и вы уже можете увидеть конкретный номер строки этого оператора в исходном коде.
Нажмитеmain.js:2
Перейти к следующему, вы можете увидеть конкретную ситуацию этого заявления.
Стиль можно полностью проследить доscss
в файле.
Нажмитеindex.scss:3
Перейти к ниже.
Показатели безопасности
Наsource map
После этого в инструментах разработчикаwebpack://
Исходный код проанализированного проекта можно найти в каталоге.
Обратите внимание, что при открытии инструментов разработчика браузераmap
Файлы загружаются одновременно, а затем браузер использует их для анализа соответствующего выходного файла, анализируя структуру каталогов и содержимое исходного кода.
map
Файл, как правило, большой и не будет загружен без открытия инструментов разработчика, а с помощьюsource map
Будут определенные риски безопасности.
webpack
при условииhidden-source-map
иnosources-source-map
Две стратегии улучшенияsource map
безопасность.
hidden-source-map
все равно будет генерировать полныйmap
файл, но пара не добавляется в выходной файлmap
ссылка на файл. Чтобы отследить исходный код, вы можете использовать сторонние сервисы (такие какSentry),будетmap
файл загружен.
nosources-source-map
Структуру каталогов исходного кода можно просмотреть в инструментах разработчика, но конкретное содержимое файла будет скрыто. можно посмотреть в консолиconsole
Точное количество строк в логе, которого в принципе достаточно для возврата ошибок.
элемент конфигурации devtool
devtool
Используется для отладки, включая более десятка следующих конфигураций.
none
eval
eval-source-map
cheap-eval-source-map
cheap-module-eval-source-map
source-map
cheap-source-map
cheap-module-source-map
inline-source-map
inline-cheap-source-map
inline-cheap-module-source-map
hidden-source-map
nosources-source-map
который включаетeval
,cheap
,module
,source-map
и другие ключевые слова, большинство из которых объединены, и их конкретные характеристики заключаются в следующем.
-
eval
:использоватьeval
обертывает код модуля и существуетsourceURL
,sourceURL
указать исходный файл -
cheap
: Бэйлmap
файл, информация о позиции столбца исходного кода не сохраняется, включается только информация о позиции строки. пренебрегатьloader
изsource map
, и показывать только транспилированный код -
module
:включаютloader
изsourcemap
-
source-map
:генерировать.map
документ
none
Корневой каталог включаетpackage.json
,webpack.config.js
иsrc
папка,src
включить нижеindex.html
иmain.js
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"babel-loader": "^8.0.5",
"html-webpack-plugin": "^3.2.0",
"webpack": "4.29.4",
"webpack-cli": "^3.2.3"
}
}
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
entry: "./src/main.js",
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
],
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
cacheDirectory: true,
presets: [["@babel/preset-env", { modules: false }]],
},
},
],
},
devtool: "none",
mode: "development"
}
// src/index.html
<html lang="zh-CN">
<body>
<p>hello world</p>
</body>
</html>
// src/main.js
const fn = ()=>{
console.log('source map')
}
fn()
бегатьbuild
После команды скрипта просмотрите вывод в консоли.
Нажмитеmian.js:97
Прыгайте ниже.
none
Элемент конфигурации нельзя отследить до исходного кода, он основан только на конфигурации.loader
Код модуля транспилируется.
eval
Исправлятьwebpack.config.js
серединаdevtool
собственностьeval
, затем запуститеbuild
Команда сценария для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
eval
В элементе конфигурации упакован код модуляeval
пакет, в том числеsourceURL
, исходный код трассировкиloader
Преобразовано (функция стрелки преобразована в обычную функцию), с информацией о столбце курсора.
source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьsource-map
, беги сноваbuild
команды скрипта,dist
В каталоге создано много.map
документ.
Просмотр кода упакованного вывода.
Консоль Нажмите и прыгайте после просмотра вывода.
source-map
В элементе конфигурации, сгенерированном.map
файл, код вывода пакета добавляется в концеsourceMappingURL
, исходный код трассировки — это исходный код с информацией о столбце курсора.
cheap-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьcheap-source-map
,бегатьbuild
команды сценария, а также вdist
создается в каталоге.map
файлы, упакованный выходной код иsource-map
Последовательный.
Консоль Нажмите и прыгайте после просмотра вывода.
cheap-source-map
В элементе конфигурации он также будет генерировать.map
файл, конец упакованного выходного кода также будет добавленsourceMappingURL
, исходный код трассировкиloader
Преобразованные (стрелочные функции преобразуются в обычные функции), без информации о столбце курсора (курсор находится в начале строки).
eval-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьeval-source-map
,бегатьbuild
Команда сценария для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
eval-source-map
В элементе конфигурации упакован код модуляeval
пакет, в том числеsourceURL
иsourceMappingURL
, не будет генерироваться.map
файл, но будетmap
Преобразование содержимого файла вbase64
кодировка вставлена вsourceMappingURL
Позже исходный код трассировки представляет собой исходный код с информацией о столбце курсора.
cheap-eval-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьcheap-eval-source-map
,бегатьbuild
Команда сценария для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
cheap-eval-source-map
В элементе конфигурации упакован код модуляeval
пакет, в том числеsourceURL
иsourceMappingURL
, не будет генерироваться.map
файл, но будетmap
Преобразование содержимого файла вbase64
кодировка вставлена вsourceMappingURL
Позже исходный код трассировкиloader
Преобразованные (стрелочные функции преобразуются в обычные функции), без информации о столбце курсора (курсор находится в начале строки).
cheap-module-eval-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьcheap-module-eval-source-map
,бегатьbuild
Команда сценария для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
cheap-module-eval-source-map
В элементе конфигурации упакован код модуляeval
пакет, в том числеsourceURL
иsourceMappingURL
, не будет генерироваться.map
файл, но будетmap
Преобразование содержимого файла вbase64
кодировка вставлена вsourceMappingURL
Позже исходный код трассировки представляет собой исходный код без информации о столбце курсора (курсор находится в начале строки).
cheap-module-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьcheap-module-source-map
,бегатьbuild
Команда сценария для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
cheap-module-source-map
В элементе конфигурации он также будет генерировать.map
файл, конец упакованного выходного кода также будет добавленsourceMappingURL
, исходный код трассировки является исходным кодом, без информации о столбце курсора (курсор находится в начале строки).
inline-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьinline-source-map
,бегатьbuild
Команда сценария для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
inline-source-map
В элементе конфигурации он не будет сгенерирован.map
файл, но будетmap
Преобразование содержимого файла вbase64
кодировка вставлена вsourceMappingURL
Позже исходный код трассировки представляет собой исходный код с информацией о столбце курсора.
hidden-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьhidden-source-map
,бегатьbuild
команды сценария, а также вdist
создается в каталоге.map
файл для просмотра упакованного и выводимого кода.
Консоль Нажмите и прыгайте после просмотра вывода.
inline-source-map
В элементе конфигурации он будет генерировать.map
файл, но не сохранитmap
Ссылки на файлы (нетsourceMappingURL
) и не может быть отслежен до исходного кода.
nosources-source-map
Исправлятьwebpack.config.js
серединаdevtool
собственностьnosources-source-map
,бегатьbuild
После команды скрипта просмотрите вывод в консоли.
Нажмитеmain.js:2
Прыгайте ниже.
Просмотр кода упакованного вывода.
nosources-source-map
В элементе конфигурации, сгенерированном.map
файл, код вывода пакета добавляется в концеsourceMappingURL
, исходный код невозможно отследить (структуру каталогов исходного кода можно просмотреть, а конкретное содержимое скрыто), но его можно просмотреть в консолиconsole
Точное количество строк журнала.
Сравнение различий
Ниже приведены отличия каждого элемента конфигурации, среди которых скорость сборкиfastest > fast > ok > slow > slowest
.
devtool | скорость наращивания | метод карты | оценочный пакет | sourceMappingURL | Есть ли информация о столбце курсора | Это имеет обратную силу | код возврата |
---|---|---|---|---|---|---|---|
none |
fastest |
- | - | - | - | нет | - |
eval |
fast |
eval внутри функцииsourceURL Путь к исходному файлу ссылки |
да | - | имеют | да |
loader транспилированный код |
source-map |
slowest |
Добавить в конце модуляsourceMappingURL Цитироватьmap
|
нет | Ссылка на сайтmap имя файла |
имеют | да | исходный код |
cheap-source-map |
ok |
Добавить в конце модуляsourceMappingURL Цитироватьmap
|
нет | Ссылка на сайтmap имя файла |
нет | да |
loader транспилированный код |
eval-source-map |
slowest |
eval внутри функцииsourceURL Обратитесь к пути к исходному файлу и вставьте его в конец функции.sourceMappingURL
|
да |
map содержаниеbase64 кодирование |
да | да | исходный код |
cheap-eval-source-map |
ok |
eval внутри функцииsourceURL Обратитесь к пути к исходному файлу и вставьте его в конец функции.sourceMappingURL
|
да |
map содержаниеbase64 кодирование |
нет | да |
loader транспилированный код |
cheap-module-eval-source-map |
slow |
eval sourceURL в функции ссылается на путь к исходному файлу, а затем вставляется в конец функцииsourceMappingURL
|
да |
map содержаниеbase64 кодирование |
нет | да | исходный код |
cheap-module-source-map |
slow |
Добавить в конце модуляsourceMappingURL Цитироватьmap
|
нет | Ссылка на сайтmap имя файла |
нет | да | исходный код |
inline-source-map |
slowest |
Добавить в конце модуляsourceMappingURL
|
нет |
map содержаниеbase64 кодирование |
да | да | исходный код |
hidden-source-map |
slowest |
- | нет | - | - | - | - |
nosources-source-map |
slowest |
Добавить в конце модуляsourceMappingURL Цитироватьmap
|
нет | Ссылка на сайтmap имя файла |
- | - | - |
сжатие ресурсов
Как правило, ресурсы, опубликованные в онлайн-среде, подвергаются сжатию кода (сокращению), то есть удалению избыточных пробелов, новых строк и невыполненного кода, сокращению имен переменных, удалению комментариев и т. д., при этом гарантируется неизменность результата выполнения. с более короткой формой.
Общий размер кода будет значительно уменьшен после сжатия, и в то же время он будет в основном нечитаемым, что в определенной степени повышает безопасность кода.
Сократить JavaScript
webpack3
и ниже можно пройтиwebpack.optimize.UglifyJsPlugin
Реализовать сжатие кода.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^3.10.0"
}
}
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./dist/[name].js"
},
plugins: [new webpack.optimize.UglifyJsPlugin()]
}
// src/main.js
const fn = function () {
console.log("hello world")
}
fn()
webpack4
Затем используйте по умолчаниюterser-webpack-plugin
Как встроенный плагин сжатия, он поддерживаетES6+
Сжатие кода. существуетwebpack4
пройти вoptimization.minimize
Определяет, включать ли сжатие.По умолчанию оно отключено в среде разработки и включено по умолчанию в производственной среде.
// webpack.config.js
module.exports = {
...
optimization: {
minimize: true
}
}
также можно сделать черезoptimization.minimizer
Пользовательские плагины сжатия и элементы их конфигурации, которые могут быть автоматически удалены при упаковке следующим образом.console.log
.
// webpack.config.js
const TerserPlugin = require("terser-webpack-plugin")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
pure_funcs: ["console.log"],
},
},
}),
],
},
}
Сжать CSS
Сжатиеcss
Первый заключается в использованииextract-text-webpack-plugin
илиmini-css-extract-plugin
Извлеките стиль, затем используйтеoptimize-css-assets-webpack-plugin
сжимать.
Корневой каталогpackage.json
,webpack.config.js
иsrc
папка,src
включить нижеmain.js
иindex.css
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"css-loader": "^0.28.7",
"mini-css-extract-plugin": "^0.5.0",
"optimize-css-assets-webpack-plugin": "^4.0.1",
"webpack": "4.29.4",
"webpack-cli": "^3.2.3"
}
}
// webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
"css-loader"
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
],
optimization: {
minimize: true,
minimizer: [new OptimizeCSSAssetsPlugin()]
},
}
// src/main.js
import "./index.css"
console.log("hello world")
// src/index.css
p {
color: red;
}
воплощать в жизньbuild
После того, как скрипт упакован, просмотрите выводcss
документ.
// dist/main.css
p {
color: red;
}
тайник
Кэш относится к повторному использованию ресурсов, уже полученных браузером.Подробная политика кэширования (например, время кэширования) определяется сервером, и браузер будет использовать локальный кэш для ответа до истечения срока действия ресурса.
Но и этот метод принесет проблемы, если кодbug fix
, и хотите обновить сразу во всех браузерах пользователей, лучше всего изменить ресурсURL
, вынуждая клиента повторно скачать ресурс.
Общим методом является вычисление содержимого ресурса один раз при каждой его упаковке.hash
, и сохраняется в имени файла как номер версии.
номер версии
обычно используется следующим образомchunkhash
в качестве номера версии файла, который будет использоваться отдельно для каждогоchunk
рассчитатьhash
ценность.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "4.29.4",
"webpack-cli": "^3.2.3"
}
}
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name]@[chunkhash:8].js"
}
}
// src/main.js
console.log("hello world")
бегатьbuild
Скрипт упакован следующим образом.
Изменение имени файла ресурсов также означает, чтоHTML
Изменения в эталонном пути могут быть сделаны с помощьюhtml-webpack-plugin
Плагин, который автоматически синхронизирует имена ресурсов, на которые ссылаются, после упаковки.
// package.json
"devDependencies": {
...
"html-webpack-plugin": "3.2.0"
}
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html"
})
]
}
// src/html
<html lang="zh-CN">
<body>
<p>hello world</p>
</body>
</html>
снова бежатьbuild
Пакет скриптов, открытьdist
Внизindex.html
, где пути к ресурсам, на которые есть ссылки, синхронизируются.
CommonsChunkPlugin
пройти черезCommonsChunkPlugin
Некоторые редко изменяемые коды могут извлекаться отдельно, чтобы отличить их от часто повторяющихся бизнес-кодов.Эти ресурсы могут постоянно кэшироваться на стороне клиента.
ноwebpack3
и следующее указано для каждого модуляid
Он увеличивается на число, и когда вставляется новый модуль, это вызывает другие модули.id
изменение, которое влияетchunk
содержание в финальном воздействииchunkhash
значение, что приводит к повторной загрузке ресурсов, которые не нужно загружать.
Корневой каталогpackage.json
,webpack.config.js
иsrc
папка,src
включить нижеmain.js
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^3.10.0"
},
"dependencies": {
"jquery": "^3.2.1"
}
}
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
main: "./src/main.js",
vendor: ["jquery"]
},
output: {
filename: "./dist/[name]@[chunkhash:8].js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name]@[chunkhash:8].js"
})
]
}
// src/main.js
import "jquery"
console.log("main.js")
бегатьbuild
Скрипт упаковки, просмотр выходных ресурсов, которыеvendor
Содержит только сторонние модулиjquery
иwebpack
файл времени выполнения.
затем вsrc
под новымutils.js
,main.js
введено в.
// src/main.js
import "jquery"
import "./utils"
console.log("main.js")
// src/utils.js
console.log("utils.js")
выполнить сноваbuild
Скрипт упаковки, просмотр выходных ресурсов.
Это создает проблему,vendor
Модули не изменились, но изменились их путевые имена.
В сравненииdist
Под содержаниемvendor@5eb95a94.js
иvendor@fe14193b.js
, произошли только следующие два изменения.
HashedModuleIdsPlugin
Решение — сменить модульid
метод генерации,webpack3
ВстроенныйHashedModuleIdsPlugin
Плагин, он может генерировать строковый тип для каждого модуля в соответствии с его путемhash id
.
// src/main.js
import "jquery"
console.log("main.js")
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: {
main: "./src/main.js",
vendor: ["jquery"],
},
output: {
filename: "./dist/[name]@[chunkhash:8].js",
},
plugins: [
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name]@[chunkhash:8].js",
}),
],
}
бегатьbuild
Скрипт упаковки, просмотр выходных ресурсов.
main.js
вводитьutils.js
.
import "jquery"
import "./utils"
console.log("main.js")
снова бежатьbuild
Бэйл.
так какvendor
Включать только сторонние модулиjquery
иwebpack
время выполнения, покаjquery
Путь всегда фиксирован, поэтому егоhash id
всегда фиксируется.
webpack3
Следующая версия, потому что она не поддерживает строковый типid
,можно использоватьwebpack-hashed-module-id-plugin
плагин. иwebpack4+
Модифицировал модульid
метод генерации, больше нет этой проблемы.
Анализ мониторинга
Вы можете использовать сторонние плагины для упаковки выводаbundle
Тома отслеживаются и анализируются, чтобы предотвратить добавление ненужных избыточных модулей.
Import Cost
Vs Code
серединаImport Cost
Размер импортированного модуля можно определить в режиме реального времени, когда в коде есть ссылка на новый модуль (в основномnode_modules
модуль в ), он рассчитает сжатый иgzip
занимаемый объем после.
webpack-bundle-analyzer
Еще одним инструментом визуального анализа являетсяwebpack-bundle-analyzer
, может анализироватьbundle
сочинение.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"vue": "^2.6.12",
"vue-router": "^3.5.1",
"vuex": "^3.6.2",
"webpack": "^3.10.0",
"webpack-bundle-analyzer": "^4.4.1"
}
}
// webpack.config.js
const webpack = require("webpack")
const Analyzer = require("webpack-bundle-analyzer").BundleAnalyzerPlugin
module.exports = {
entry: {
main: "./src/main.js",
vendor: ["vue", "vuex", "vue-router"]
},
output: {
filename: "./dist/[name].js"
},
plugins: [
new Analyzer(),
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "./dist/[name].js"
})
]
}
// src/main.js
import Vue from "vue"
import Vuex from "vuex"
import VueRouter from "vue-router"
import { log } from "./utils.js"
console.log(Vue, Vuex, VueRouter, log, "main.js")
// src/utils.js
export function log() {
console.log("utils.js")
}
бегатьbuild
Результаты анализа сценария следующие.
Оптимизация упаковки
Если вы не видите никаких точек оптимизации на ранней стадии проекта и вносите их в проект, это увеличит сложность, и эффект оптимизации будет неидеальным. Как правило, проект развивается до определенного масштаба, и проблемы с производительностью возникают до конкретной оптимизации.
HappyPack
HappyPack
это многопоточность для улучшенияwebpack
Плагин для скорости упаковки.
Трудоемкая часть процесса упаковкиloader
Переводите различные ресурсы, такие какbabel
перевестиES6+
и так далее, конкретный рабочий процесс выглядит следующим образом.
- Получить запись об упаковке из конфигурации
- совпадение
loader
правила и транспилирует входной модуль - Поиск зависимостей для транспилированных модулей
- Повторите шаги для вновь найденных модулей.
2
и шаги3
, пока не останется новых зависимых модулей
Шаги2
шагать4
это рекурсивный процесс,webpack
Необходимо шаг за шагом приобретать ресурсы более глубокого уровня, а затем переводить их один за другим. Фундаментальная проблема заключается вwebpack
однопоточный, если модуль зависит от нескольких других модулей,webpack
Эти модули должны быть переведены один за другим. Хотя эти задачи перевода не зависят друг от друга, они должны выполняться последовательно. иHappyPack
Основная функция заключается в том, что он может открывать несколько потоков, параллельно переводить разные модули и в полной мере использовать локальные ресурсы для повышения скорости упаковки.
одиночный погрузчик
Использовать при использованииHappyPack
который предоставилloader
заменить оригиналloader
, и конвертировать исходныйloader
перейти кHappyPack
плагин.
Корневой каталогpackage.json
,webpack.config.js
иsrc
,вsrc
включить нижеmain.js
,bar.js
,foo.js
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"babel-loader": "^8.0.5",
"vue": "^2.6.12",
"vuex": "^3.6.2",
"webpack": "4.29.4",
"webpack-cli": "3.2.3",
"happypack": "^5.0.0"
}
}
// src/main.js
import "./foo.js"
import "./bar.js"
console.log("main.js")
// src/foo.js
import vue from "vue"
console.log(vue, "foo.js")
// src/bar.js
import Vuex from "vuex"
console.log(Vuex, "bar.js")
Исходныйwebpack
Конфигурация следующая.
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
cacheDirectory: true,
presets: [["@babel/preset-env", { modules: false }]],
},
},
],
},
}
ВведеноHappyPack
Модификация после плагинаwebpack
конфигурация.
// webpack.config.js
const HappyPack = require("happypack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "happypack/loader",
},
],
},
plugins: [
new HappyPack({
loaders: [
{
loader: "babel-loader",
options: {
cacheDirectory: true,
presets: [["@babel/preset-env", { modules: false }]],
},
},
],
}),
],
}
несколько загрузчиков
HappyPack
оптимизировать несколькоloader
, требуется для каждогоloader
настроитьid
,в противном случаеHappyPack
не могу знатьrules
иplugins
Как переписываться по одному.
Корневой каталогpackage.json
,webpack.config.js
иsrc
,src
включить нижеmain.js
иindex.css
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.3.1",
"babel-loader": "^8.0.5",
"webpack": "4.29.4",
"webpack-cli": "3.2.3",
"happypack": "^5.0.0",
"css-loader": "^0.28.9",
"style-loader": "^0.19.0"
}
}
// src/main.js
import "./index.css"
console.log("main.js")
// src/index.css
p {
color: red;
}
Исходныйwebpack
Конфигурация следующая.
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
cacheDirectory: true,
presets: [["@babel/preset-env", { modules: false }]],
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
}
ВведеноHappyPack
Модификация после плагинаwebpack
конфигурация.
// webpack.config.js
const HappyPack = require("happypack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
module: {
rules: [
{
test: /\.js$/,
loader: "happypack/loader?id=js",
exclude: /node_modules/,
},
{
test: /\.css$/,
loader: "happypack/loader?id=css",
},
],
},
plugins: [
new HappyPack({
id: "js",
loaders: [
{
loader: "babel-loader",
options: {
cacheDirectory: true,
presets: [["@babel/preset-env", { modules: false }]],
},
},
],
}),
new HappyPack({
id: "css",
loaders: ["style-loader", "css-loader"],
}),
],
}
Сузить пакет
Как правило, есть два способа повысить производительность: увеличить ресурсы или уменьшить масштаб. Увеличение ресурсов означает использование большегоCPU
и памяти, используя больше вычислительной мощности, чтобы сократить время выполнения задач. Сужение касается самой задачи, такой как удаление избыточных процессов или отказ от повторяющейся работы.
exclude/include
Заjs
модуль, в общемnode_modules
каталог исключен.
noParse
Некоторые сторонние библиотеки совершенно нежелательныwebpack
для разбора, т.е. не желают применять какие-либоloader
rules, внутри библиотеки не будет зависимостей от других модулей, и вы можете использовать ее в это время.noParse
Игнорируй это.
Следующее означает игнорировать все имена файлов, включаяlodash
модули, эти модули по-прежнему будут упакованы в ресурсы, ноwebpack
Он не будет разобран никоим образом.
// webpack.config.js
module.exports = {
...
module: {
noParse: /lodash/
}
IgnorePlugin
IgnorePlugin
Плагины могут полностью исключать некоторые модули, и исключенные модули не будут упакованы в файлы ресурсов, даже если на них есть ссылки.
следующееmoment.js
Это библиотека обработки времени.Для локализации она загружает много языковых пакетов.Вообще говоря, она не используется и займет много места.Его можно использоватьIgnorePlugin
Игнорируй это.
Корневой каталог включаетpackage.json
,webpack.config.js
,src
,src
включить нижеmain.js
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"moment": "^2.29.1",
"webpack": "4.29.4",
"webpack-cli": "3.2.3"
}
}
// webpack.config.js
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
}
}
// src/main.js
import "moment"
console.log("main.js")
бегатьbuild
Скрипт упаковки, просмотр выходных ресурсов.
Исправлятьwebpack.config.js
,вresourceRegExp
соответствующие файлы ресурсов,contextRegExp
Соответствие каталогу поиска.
// webpack.config.js
const webpack = require("webpack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
plugins: [
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
],
}
снова бежатьbuild
Скрипт упаковки, просмотр выходных ресурсов.
DllPlugin
Раноwindows
Метод оптимизации памяти, называемый динамической библиотекой, возникает из-за того, что система ограничена проблемой небольшого объема памяти компьютера.Когда одна и та же подпрограмма вызывается несколькими программами, чтобы уменьшить потребление памяти, эта подпрограмма может храниться как исполняемый файл, который генерирует и использует один и тот же экземпляр в памяти только при вызове несколькими программами.
DllPlugin
Опираясь на эту идею, для сторонних модулей или некоторых модулей, которые изменяются нечасто, их можно предварительно скомпилировать и упаковать, а затем напрямую использовать в фактическом процессе построения проекта. При предварительной упаковке будет дополнительно формироваться список модулей, и этот список будет играть роль связывания и индексации при упаковке инженерных бизнес-модулей.
DllPlugin
иCode Splitting
Точно так же оба могут использоваться для извлечения общих модулей, но есть и существенные различия.Code Splitting
Это установка определенных правил и извлечение модулей в соответствии с правилами в процессе упаковки.DllPlugin
будетvendor
Полностью разделен, имеет свой собственный наборwebpack
Он настраивается и упаковывается независимо, и он больше не будет обрабатываться при создании фактического проекта, и его можно будет использовать напрямую. теоретическиDllPlugin
было бы лучше, чемCode Splitting
Скорость упаковки выше, но это также соответственно увеличивает сложность настройки и управления ресурсами. можно понимать какDllPlugin
Теоретически быстрее заменить один пакет двумя пакетами, первый пакет для редко меняющихся модулей, а второй пакет для бизнес-модулей.
dll упаковка
Корневой каталог включаетwebpack.config.js
,package.json
иsrc
,src
включить нижеmain.js
,index.html
.
// package.json
{
...
"scripts": {
"build": "webpack"
},
"devDependencies": {
"vue": "^2.6.12",
"webpack": "4.29.4",
"webpack-cli": "3.2.3"
}
}
// src/main.js
import "vue"
console.log("main.js")
Сначала создайте отдельный для динамической библиотеки.webpack
конфигурационный файл, назовите егоwebpack.dll.config.js
. вoutput.filename
имя динамической библиотеки,output.path
выходной путь библиотеки динамической компоновки,output.library
должен иDllPlugin
серединаname
Последовательный.DllPlugin
серединаpath
выходной путь манифеста модуля библиотеки динамической компоновки,path
заmanifest.json
в файлеname
значение поля.
// webpack.dll.config.js
const path = require("path")
const webpack = require("webpack")
const dllAssetPath = path.join(__dirname, "dist", "dll")
const dllLibraryName = "dll"
module.exports = {
entry: ["vue"],
output: {
path: dllAssetPath,
filename: "dll.js",
library: dllLibraryName,
},
plugins: [
new webpack.DllPlugin({
name: dllLibraryName,
path: path.join(dllAssetPath, "manifest.json"),
}),
],
}
затем настроитьpackage.json
, добавьте команду скрипта.
// package.json
{
...
"scripts": {
"dll": "webpack --config webpack.dll.config.js"
}
}
бегатьdll
команда скрипта, будет вdist
Под содержаниемdll
создается в папкеdll.js
иmanifest.json
. вdll.js
Имя переменной в приведенной выше конфигурацииoutput.library
,manifest.json
серединаname
вышеDllPlugin
серединаname
.
// dist/dll/dll.js
var dll = (function (params) {
...
})(...)
// dist/dll/manifest.json
{
"name": "dll",
"content": {
...
}
}
Наконец, вам нужно сделать ссылку в бизнес-кодеdll.js
.
// webpack.config.js
const path = require("path")
const webpack = require("webpack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "./[name].js",
},
plugins: [
new webpack.DllReferencePlugin({
manifest: require(path.join(__dirname, "dist/dll/manifest.json")),
}),
],
}
введение страницыscript
Таким образом, страница выполняется дляdll.js
глобальные переменные объявляются, когдаdll
,иmanifest
Эквивалент инъекцииmain.js
карта ресурсов,main.js
пройдет первымname
Имя найденного поляdll
изlibrary
, так что вwebpack.dll.config.js
серединаoutput.library
должен иDllPlugin
серединаname
Последовательный.
// src/index.html
<html lang="zh-CN">
<body>
<p>hello world</p>
<script src="./dll/dll.js"></script>
<script src="./main.js"></script>
</body>
</html>
проблема с идентификатором
Проверятьmanifest.json
, где каждый модуль имеетid
, значения которого расположены в порядке возрастания номеров,main.js
код ссылаетсяdll.js
также ссылайтесь на номера, когда модули вid
.
Может существовать после упаковки проектаdll.js
(пройти черезDllPlugin
Построить),utils.js@[chunkhash].js
,main.js
. вdll.js
содержитvue
,Тотid
за5
. При попытке добавить дополнительные модули вdll.js
Среднее время, после восстановленияvue
изid
стать6
.
так какutils
также цитируетсяvue
модуль, после восстановления егоchunkhash
Он изменится, но его собственное содержимое не изменится, и пользователю клиента останется только заново скачать ресурс.
Чтобы решить эту проблему, используйтеHashedModuleIdsPlugin
плагин.
// webpack.dll.config.js
module.exports = {
plugins: [
new webpack.DllPlugin({
...
}),
new webpack.HashedModuleIdsPlugin()
]
}
tree shaking
ES6 Module
Зависимости создаются во время компиляции кода, а не во время выполнения, на основе этой функции.webpack
при условииtree shaking
Он может обнаруживать модули, на которые нет ссылок в проекте в процессе упаковки.Эта часть кода никогда не будет выполнена, поэтому ее также называют «мертвым кодом».
webpack
пометит эту часть кода и удалит их из окончательногоbundle
удаленный.
следующееwebpack
при упаковкеbar
Функция добавляет флаг, а затем проходит через инструмент минификации для удаления мертвого кода.
// src/main.js
import { foo } from "./utils.js"
foo()
// src/utils.js
export function foo() {
console.log("foo")
}
export function bar() {
console.log("bar")
}
🎉 Напишите в конце
🍻Ребята, если вы видели это и считаете, что эта статья была вам полезна, ставьте лайк 👍 илиStar✨Поддержите!
Кодирование вручную, если есть ошибки, исправьте их в комментариях 💬~
Ваша поддержка — самая большая мотивация для меня обновляться💪~
GitHub,Blog,Наггетс,CSDNСинхронизированное обновление, подписывайтесь 😉~