Основное введение
Webpack
Он также постоянно оптимизируется и дорабатывается, на данный момент он обновлен до версии 4.16.0;Webpack4
В этой версии, на основе оригинала, сделано много оптимизаций, а также введено много новых функций. В новой версии будет больше типов модулей и.mjs
Поддержка, лучшее значение по умолчанию, более краткие настройки режима, более интеллектуальное разделениеChunk
Добавить новоеsplitChunks
настроить разделенные блоки кода и многое другое. Обновление до новой версииWebpack
проект, в пакете构建速度
,代码块体积&数量
,так же как运行效率
, будет качественный скачок.
так лицоWebpack4
Превосходная функциональность для преобразования нативных проектов из оригинала2.7.0
Одноэтапное обновление до4.16.0
, а связанные зависимости и файлы конфигурации необходимо изменить соответствующим образом.
процесс обновления webpack4.0
среда узла
больше не поддерживаетсяNode4
, Рекомендуемые старшие версииnode
, для обновления используется следующееnode v8.11.1
а такжеnpm v5.6.0
тип модуля
До веб-пакета 4 js был единственным типом модуля в веб-пакете и, следовательно, не мог эффективно упаковывать другие типы файлов. И webpack 4 предоставляет 5 типов модулей:
- javascript/auto: (тип по умолчанию в webpack 3) поддерживает все модульные системы JS: CommonJS, AMD, ESM
- javascript/esm: модули EcmaScript, недоступные в других модульных системах (файл .mjs по умолчанию)
- javascript/динамический: поддерживает только CommonJS и AMD, модули EcmaScript недоступны
- json: данные в формате JSON, которые можно импортировать с помощью require и import (по умолчанию файлы .json).
- webassembly/experimental: модули WebAssembly (экспериментальные, по умолчанию файлы .wasm)
Кроме того, webpack 4 по умолчанию будет анализировать файлы с суффиксами .wasm, .mjs, .js и .json.
webpack-cli
После обновленияwebpack4
Затем запустите команду упаковки проекта напрямуюnpm run build
, вам будет предложено установитьwebpack-cli/webpack-command
, вы можете выбрать установку в соответствии с вашими потребностями, я выбираюwebpack-cli
.
Обновление конфигурации
режим добавить
webpack4
По умолчаниюmode
установить это生产环境
еще开发环境
, так и должно бытьwebpack.dev.conf.js
а такжеwebpack.prod.conf.js
увеличить соответствующийmode
Элементы конфигурации и удалите код, устанавливающий переменную среды передprocess.env.NODE_ENV = 'production'
А способ установки переменных окружения в конфигурации плагина, код фрагмента следующий:
// webpack.dev.conf.js
module.exports = merge(baseWebpackConfig, {
mode: 'development',
// 省略
plugins: [
new webpack.DefinePlugin({
'process.env': config.dev.env
}),
]
}
// webpack.prod.conf.js
var webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
// 省略
plugins: [
new webpack.DefinePlugin({
'process.env': env
}),
]
}
Примечание: новый webpack.DefinePlugin гарантированно доступен в сценариях браузера.
process.env
переменные для выполнения соответствующих логических операций
режим разработки:
- 1. В основном оптимизирована инкрементная скорость сборки и опыт разработки.
- 2. Значение process.env.NODE_ENV не нужно определять заново, по умолчанию это development
- 3. Комментарии и подсказки поддерживаются в режиме разработки, а исходные карты под eval поддерживаются
режим производства:
- 1. Многие оптимизации кода (минимизация, разделение и т. д.) включены по умолчанию в рабочей среде.
- 2. Включите просмотр и проверку во время разработки и автоматически добавьте eval devtool
- 3. Рабочая среда не поддерживает просмотр, а среда разработки оптимизирует скорость переупаковки
- 4. Подъем области действия и встряхивание деревьев включены по умолчанию (исходный плагин ModuleConcatenation).
- 5. Автоматически устанавливать process.env.NODE_ENV для разных окружений, то есть не нужно, чтобы DefinePlugin делал это
- 6. Если вы установите для режима значение none, все конфигурации по умолчанию будут удалены.
- 7. Если вы не добавите эту конфигурацию, веб-пакет напомнит вам, поэтому добавьте ее.
использование плагина mini-css-extract
потому чтоextract-text-webpack-plugin
Последняя официальная версия еще не поддерживает webpack4.x, даже используяextract-text-webpack-plugin@next
версия все равно появитсяcontenthash
ошибка, поэтому рекомендуется использоватьmini-css-extract-plugin
, разумеется, это тоже официально рекомендуется.
Главное надо доработатьwebpack.prod.conf.js
конфигурация плагина в иloaders
Загруженная служебная функцияutils.js
, измените код фрагмента следующим образом:
// webpack.dev.conf.js
module.exports = merge(baseWebpackConfig, {
// 省略
plugins: [
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
]
}
// utils.js
if (options.extract) {
return [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../../'
}
}
].concat(loaders)
} else {
return ['vue-style-loader'].concat(loaders)
}
Примечание: где
utils.js
Средняя конфигурацияpublicPath
В основном решить проблему ошибки пути в ссылочных изображениях в css.
элемент конфигурации оптимизации
Запустите соответствующую команду упаковки еще раз, и вы увидите следующее сообщение об ошибке.Код фрагмента выглядит следующим образом:
Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.
at Object.get [as CommonsChunkPlugin] (/data/test/node_modules/webpack/lib/webpack.js:159:10)
В основном потому, чтоwebpack4
Удаленоwebpack.optimize.CommonsChunkPlugin
и использоватьoptimization
серединаsplitChunk
заменить
Главное надо доработатьwebpack.prod.conf.js
файл и удалить всеwebpack.optimize.CommonsChunkPlugin
Соответствующий код, код фрагмента выглядит следующим образом:
var webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
entry: {
charts: ['echarts'],
vendors: ['vue', 'vuex', 'vue-router', 'moment'],
iconfonts: ['ga-iconfont']
},
// 省略
optimization: {
// minimizer: true, // [new UglifyJsPlugin({...})]
providedExports: true,
usedExports: true,
//识别package.json中的sideEffects以剔除无用的模块,用来做tree-shake
//依赖于optimization.providedExports和optimization.usedExports
sideEffects: true,
//取代 new webpack.optimize.ModuleConcatenationPlugin()
concatenateModules: true,
//取代 new webpack.NoEmitOnErrorsPlugin(),编译错误时不打印输出资源。
noEmitOnErrors: true,
splitChunks: {
// maxAsyncRequests: 1, // 最大异步请求数, 默认1
// maxInitialRequests: 1, // 最大初始化请求数,默认1
cacheGroups: {
// 抽离第三方插件
commons: {
// test: path.resolve(__dirname, '../node_modules'),
chunks: 'all',
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0, // This is example is too small to create commons chunks
name: 'common'
}
}
},
}
test
В основном за счет регулярного сопоставленияentry
Настроить сторонние библиотеки в, конечно, можно и сюда написатьpath.resolve(__dirname, '../node_modules')
соответствовать проектуnode_modules
Импортированные файлы библиотеки.
chunks
Форма имеет три значения (если настроеноentry
, то извлекается из файла входа по умолчанию, если не настроеноentry
настроенtest
, по умолчанию согласноtest
Регулярное сопоставление в ) рекомендуется для личного сравненияall
илиasync
:
-
когда значение
all
Когда эффект заключается в том, является ли он асинхронным или синхронным, запись будетentry
Публичная часть настроенного пакета извлекается, преимущество в том, что другие файлы очень маленькие, а публичные файлы будут загружены только один раз.enrty
Слишком много сконфигурированных пакетов может привести к большому размеру файла. Эффект в основном следующий: -
когда значение
async
, эффект в том, что входentry
Настроенный пакет извлекается из асинхронной общедоступной части, в основном для просмотраentry
Является ли внедрение среднего пакета асинхронным? Эффект в основном следующий: -
когда значение
initial
на самом деле, эффект не так хорош, какall
а такжеasync
При инициализации пакет, участвующий в каждой странице из JS на соответствующих страницах, из файлов JS на соответствующих страницах, будет упакован для JS каждой страницы в соответствии со страницей. Эффект в основном следующий:
sideEffects
При включении бесполезные модули можно исключить и использовать для выполненияtree-shake
. когда модульpackage.json
Когда это поле добавляется в , это означает, что модуль не имеет побочных эффектов, а это означает, чтоwebpack
Код, используемый для реэкспорта, можно безопасно очистить.
concatenateModules
замененыwebpack.optimize.ModuleConcatenationPlugin()
плагин
noEmitOnErrors
замененыnew webpack.NoEmitOnErrorsPlugin()
плагин.
minChunks
даsplit
Раньше были общие модулиchunks
Минимальное количество , по умолчанию 1, но код в примере находится вdefault
Переписывается как 2 в , исходя из здравого смысла,minChunks = 2
Это должен быть разумный выбор.
Уведомление:
webpack.optimize.UglifyJsPlugin
Сейчас нет необходимости, просто используйтеoptimization.minimize
дляtrue
Просто хорошо,production mode
Далее автоматическиtrue
, конечно, если вы хотите использовать сторонний плагин сжатия, вы также можетеoptimization.minimizer
настроен в списке массивов
Обновление плагина HTML-WebPack
Рекомендуется обновить до последней версии@4.0.0-alpha
, здесь нужно поставить по умолчаниюchunksSortMode: dependency
удалены, в основном потому, чтоwebpack4
Удалены связанныеCommonsChunkPlugin
API тоже.
обновление vue-загрузчика
На самом деле это не нужно обновлять, но если вы обновитесь до версии 15.x или выше, вам нужно выполнить это во время использования.VueLoaderPlugin
Метод плагина, другие способы использования такие же, как и раньше, код фрагмента выглядит следующим образом:
// webpack.prod.conf.js
const { VueLoaderPlugin } = require('vue-loader')
// 省略
plugins: [
new VueLoaderPlugin(),
]
нужно открыть исходную карту
webpack4
Вам будет предложено включить по умолчаниюsourceMap
, так что пока соответствующиеloader
в конфигурацииoptions
настроитьsourceMap:true
Вот и все.
Другие связанные обновления пакетов
Соответствующие загрузчики рекомендуется обновлять единым способом, базовое обновление выглядит следующим образом:
- babel-loader 7.1.5
- css-loader 1.0.0
- file-loader 1.1.11
- less-loader 4.1.0
- url-loader 1.0.1
- vue-style-loader 4.1.0
- vue-template-compiler 2.5.16
Полная конфигурация
webpack.dev.conf.js
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})
baseWebpackConfig.output.chunkFilename = '[name].[chunkhash].js'; // 路由js命名 这个拆分路由 模块依赖脚本文件
module.exports = merge(baseWebpackConfig, {
mode: 'development',
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
},
devtool: '#cheap-module-eval-source-map',
optimization: {
// minimizer: true,
providedExports: true,
usedExports: true,
//识别package.json中的sideEffects以剔除无用的模块,用来做tree-shake
//依赖于optimization.providedExports和optimization.usedExports
sideEffects: true,
//取代 new webpack.optimize.ModuleConcatenationPlugin()
concatenateModules: true,
//取代 new webpack.NoEmitOnErrorsPlugin(),编译错误时不打印输出资源。
noEmitOnErrors: true,
splitChunks: {
chunks: 'initial', //'all'|'async'|'initial'(全部|按需加载|初始加载)的chunks
},
//提取webpack运行时的代码
runtimeChunk: {
name: 'manifest'
}
},
plugins: [
new VueLoaderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
}),
new FriendlyErrorsPlugin()
]
})
webpack.prod.conf.js
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
var webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
entry: {
charts: ['echarts'],
vendors: ['vue', 'vuex', 'vue-router', 'moment'],
iconfonts: ['ga-iconfont']
},
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true
})
},
devtool: config.build.productionSourceMap ? '#source-map' : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
publicPath: './'
},
optimization: {
// minimizer: true,
providedExports: true,
usedExports: true,
//识别package.json中的sideEffects以剔除无用的模块,用来做tree-shake
//依赖于optimization.providedExports和optimization.usedExports
sideEffects: true,
//取代 new webpack.optimize.ModuleConcatenationPlugin()
concatenateModules: true,
//取代 new webpack.NoEmitOnErrorsPlugin(),编译错误时不打印输出资源。
noEmitOnErrors: true,
splitChunks: {
// maxAsyncRequests: 1, // 最大异步请求数, 默认1
// maxInitialRequests: 1, // 最大初始化请求书,默认1
cacheGroups: {
// test: path.resolve(__dirname, '../node_modules'),
commons: {
chunks: 'all',
minChunks: 2,
maxInitialRequests: 5, // The default limit is too small to showcase the effect
minSize: 0, // This is example is too small to create commons chunks
name: 'common'
}
}
},
//提取webpack运行时的代码
runtimeChunk: {
name: 'manifest'
}
},
plugins: [
new VueLoaderPlugin(),
// 解决moment语言包问题
new webpack.ContextReplacementPlugin(
/moment[\\\/]locale$/,
/^\.\/(zh-cn)$/
),
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css')
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true,
discardComments: { removeAll: true }
}
}),
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
hash:true,// 防止缓存
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
}),
new webpack.HashedModuleIdsPlugin(),
new CopyWebpackPlugin([{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}])
]
})
if (config.build.productionGzip) {
var CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
Меры предосторожности
ошибка предварительной загрузки плагина
Если используется в проектеpreload-webpack-plugin
Плагин, вы должны обновить до3.0.0-beta.1
Версия, вы можете запустить следующую команду:
npm i preload-webpack-plugin@next -D
В то же время необходимоhtml-webpack-plugin
Версия плагина возвращается к3.2.0
Просто сделайте это, а затем добавьте его в файл конфигурации в следующем порядке, код фрагмента выглядит следующим образом:
// 省略
plugins: [
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
}),
new PreloadWebpackPlugin({
rel: 'prefetch',
}),
new PreloadWebpackPlugin({
rel: 'preload'
}),
// 省略
]
html-webpack-plugin-after-emit
Обновитьwebpack4
После этого вdev
среды, вы обнаружите, что изменение любого кода приведет к обновлению всей страницы и сообщитcb is not a function
, причина этогоhtml-webpack-plugin-after-emit
Плагин для старшей версииwebpack4
а такжеhtml-webpack-plugin3.2.0
Он устарел, плагина на замену пока не найдено. Вы можете временно закомментировать этот код. Код находится вbuild/dev-server.js
, код фрагмента выглядит следующим образом:
compiler.plugin('compilation', function(compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function(data, cb) {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})
Суммировать
В соответствии с приведенной выше модификацией его можно в принципе дополнитьwebpack4
После обновления лично мне кажется, что конфигурация стала проще, раньше удалялось много громоздкой конфигурации плагинов, много функцийwebpack4
По умолчанию идет вместе с ним.После тестирования скорость упаковки была улучшена более чем на 50%.До модификации время упаковки было143894ms
О, после апгрейда время в основном58080ms
Эффект в основном следующий:
Если вы упакуете его снова, время в основном27534ms
Эффект в основном следующий:
21.07.2018 Дополнение
О конфигурации входа и оптимизации
Выше описано, какoptimization
Путем определения сопряженийentry
Упаковка, если окончательная упаковка выполнена в соответствии с приведенной выше конфигурацией, она действительно будет сгенерирована.charts
,vendors
,iconfonts
Три js файла, но будут сомнения по поводу размера js, ибо размер в основном в199 bytes
Следующее, это кажется немного странным, прямо откройте эти три js, чтобы увидеть, код выглядит следующим образом:
// charts.js
(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{21:function(n,o,p){n.exports=p("K8M1")}},[[21,1,0]]]);
//# sourceMappingURL=charts.2e5cbbfa2a894d2bb5aa.js.map
// iconfonts.js
(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{19:function(n,o,p){n.exports=p("t+cQ")}},[[19,1,0]]]);
//# sourceMappingURL=iconfonts.e90fd0507d501ef81b69.js.map
// vendors.js
(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{20:function(n,o,w){w("oCYn"),w("L2JU"),w("jE9Z"),n.exports=w("wd/R")}},[[20,1,0]]]);
//# sourceMappingURL=vendors.5c535f00ba89522ba93b.js.map
На самом деле, эти три абзаца js помечены вместе.common.js
Итак, с точки зрения загрузки ресурсов проекта, три приведенных выше абзаца кажутся избыточными js, так как же удалить этот бесполезный js?entry
Весь код конфигурации закомментирован, в основном следующим образом:
entry: {
// charts: ['echarts'],
// vendors: ['vue', 'vuex', 'vue-router', 'moment'],
// iconfonts: ['ga-iconfont']
}
Согласно приведенной выше модификации, мы можем упаковать на три js меньше, которые кажутся бесполезными.Спасибо нашим маленьким партнерам в группе фронтенда за обнаружение этой проблемы.
Итак, вопрос, как мы можем сделать три пакета js в соответствии с конфигурацией входного файла?Следующая конфигурация может быть следующей, и код фрагмента выглядит следующим образом:
// 前提是不注释entry中的代码
// 省略
optimization: {
// 省略
splitChunks: {
cacheGroups: {
charts: {
chunks: 'async',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
name: 'charts'
},
vendors: {
chunks: 'async',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
name: 'vendors'
},
iconfonts: {
chunks: 'async',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
name: 'iconfonts'
}
}
},
// 省略
}
// 省略
Сфокусируйся наcacheGroups
Конфигурация внутри изменила исходные общие до трех, и в то же времяchunks
необходимо изменить наasync
, результаты упаковки в основном следующие:
Относительно скорости упаковки
Количество страниц проекта для следующей тестовой скорости — 26 страниц, более десяти бизнес-компонентов, набор библиотек UI-компонентов, разработанных внутри группы, и несколько сторонних библиотек. Фактическое время будет зависеть от того, сколько соответствующих файлов проекта.
использоватьHappyPack
Плагины позволяют повысить скорость упаковки и компиляции.Вы можете обратиться к следующим модификациям.Основные модификации следующие:
// webpack.base.conf.js
// 在rules中的babel-loader改用happypack中的loader
// 省略
module: {
rules: [{
test: /\.js$/,
loader: 'happypack/loader', // 增加新的HappyPack构建loader
include: [resolve('src')],
exclude: /node_modules/,
options: {
sourceMap: true,
}
}
}
// 省略
// webpack.prod.conf.js
// 省略
plugins: [
new HappyPack({
loaders: [{
loader: 'babel-loader',
options: {
babelrc: true,
cacheDirectory: true
}
}],
threadPool: happyThreadPool
})
]
// 省略
Ниже приведено время, необходимое для упаковки до того, как немодифицированный26831ms
:
После модификации скорость упаковки составляет20387ms
, уменьшение почти6.5s
о:
установивbabel-loader
серединаcacheDirectory
Свойства также могут повысить скорость компиляции. Многие онлайн-настройки выглядят следующим образом, но будет сообщено об ошибке. Код фрагмента выглядит следующим образом:
// 这是错误用法,我实测发现报错
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory=true', // 或者loader: 'babel-loader?cacheDirectory'
include: [resolve('src')],
exclude: /node_modules/,
options: {
sourceMap: true,
}
}
На самом деле, это может бытьcacheDirectory
как свойство, настроенное вoptions
, основной код выглядит следующим образом:
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src')],
exclude: /node_modules/,
options: {
sourceMap: true,
cacheDirectory: true
}
}
Добавьте вышеуказанную модификацию, скорость упаковки20593ms
, который, похоже, не сильно изменился по сравнению с предыдущим:
После финального теста для моего проектаHappyPack
а такжеcacheDirectory
Эффекты нельзя накладывать друг на друга, с помощью любого из них можно добиться20s
все время.
Выше приведено все содержание, если что-то не так, добро пожаловать, чтобы упомянутьissues