предисловие
Знаком с конфигурацией webpack и webpack4.
Основное различие между webpack 4 и 3 заключается в т.н.零配置
, но для того, чтобы удовлетворить потребности нашего проекта, нам все равно придется настраивать его самим, но мы можем использовать некоторые пресеты веб-пакета. В то же время, webpack также разделен на две части, webpack и webpack-cli, обе из которых должны быть установлены локально.
У нас есть опыт реализации шаблона разработки vue (шаблон vue init webpack, который имеет мало общего с vue). В процессе настройки мы постараемся использовать контент, связанный с webpack4.
эта статьяне делайвеб-пакет настроенПолное введение, акцентируя внимание на моментах, на которые необходимо обратить внимание в процессе настройки. Просмотр комментариев к коду лучше для чтения, а полную конфигурацию и подробные комментарии можно увидеть в исходном коде. Конфигурация находится в папке сборки.
Главы, относящиеся к версии 4, будут добавляться с символом ④.
Следует отметить, что наш код веб-пакета работает в среде узла, и эта часть кода может использовать API узла, но наш бизнес-код (под src) не может использовать API узла.
Базовая общая конфигурация
Поскольку конфигурация загрузчиков в конфигурации веб-пакета, такая как контекст, запись (запись фрагмента), вывод (выход) и module.rules, в основном общие в режиме разработки и режиме производства, мы извлекаемwebpack.base.js
файл для повторного использования. Выходная часть выглядит следующим образом:
output: {
path: path.resolve(__dirname, '../dist/'), // 资源文件输出时写入的路径
filename: 'static/js/[name].[chunkhash].js', // 使用 chunkhash 加入文件名做文件更新和缓存处理
chunkFilename: 'static/js/[name].[chunkhash].js'
}
Примечание:
хэш имени файла
hash используется в имени выходного файла, например.[name].[hash].js
В общем, WebPack предоставляет три хэши:
-
[hash]
: Хэш всего контента, упакованного на этот раз. -
[chunkhash]
: каждый фрагмент рассчитывается на основе собственного содержимого. -
[contenthash]
: Предоставляется плагином извлечения css, рассчитывается на основе его собственного содержимого.
Использование трех хэшей, о нем мы поговорим в разделе оптимизации, сначала используйте сначала[chunkhash]
.
приоритет загрузчика
Приоритет загрузчика должен обратить внимание на два момента,
- Тестовые конфигурации с одинаковым приоритетом: несколько загрузчиков в одном тесте,Приоритетный загрузчик размещается после массива конфигурации, если для меньшей обработки, то:
{ test: /\.less$/, use: [ 'style-loader', 'css-loader', 'postcss-loader', 'less-loader' ] }
- Приоритет в разных тестах: если для обработки файлов js требуется настроить два теста отдельно, используйте
eslint-loader
а такжеbabel-loader
, но не может быть настроен в объекте конфигурации, вы можете использоватьenforce: 'pre'Подчеркнуть приоритет,eslint-loader
приоритет.{ test: /\.(js|vue)$/, loader: 'eslint-loader', enforce: 'pre', }, { test: /\.js$/, loader: 'babel-loader' }
настройка препроцессора css
Настраиваем его с загрузчиком меньшего файла['vue-style-loader', 'css-loader', 'postcss-loader', 'less-loader']
,использовать@import url(demo.less)
Например:
- less-loader сначала обрабатывает меньше синтаксиса
- postcss-loader выполняет другую обработку, такую как добавление префикса
- css-loader импортирует содержимое в файл css, где находится @import
- vue-style-loader будет генерировать теги стиля для вставки содержимого css в HTML.
vue-style-loader работает как style-loader
Но из-за однофайловой составляющей в vue он делится на два случая:
-
Стиль в файле .vue:
vue-loader
Будет обработан однофайловый компонент .vue, и для различных lang="type" в однофайловом компоненте .vue мы можемvue-loader
ОпцииНастроить разные загрузчики,из-заvue-loader
встроенныйpostcss
Процесс css, поэтому здесь его настраивать не нужноpostcss-loader
{ test: /\.vue$/, loader: 'vue-loader', options: { loaders: { less: ['// xxx-loaders'], scss: ['// xxx-loaders'], } } }
-
Добавьте файлы стилей в прямой импорт js:
Как в main.jsimport 'demo.less'
, файл стиля, представленный таким образом, вvue-loader
Обработка выходит за рамки, поэтому настройка по-прежнему требуетсяpostcss-loader
.
Из-за этой разницы мы инкапсулируем конфигурацию файла препроцессора css в виде функции, которая определяетсяusePostCss
Параметры генерируют соответствующую конфигурацию и помещают файл вutils.js
файл,vue-loader
настроить вvue-loader.js
внутри файла.
То есть нам нужно настроить препроцессор css вvue-loader
внутренняя гармонияwebpack
Настраивал два раза.
Во время написания этого README.md vue-loader выпустил версию v15, которую нужно использовать с плагином, поэтому нет необходимости настраивать его дважды.
postcss-loader
postcss-loaderЭто мощный инструмент обработки css.Мы разделяем конфигурацию postcss и создаем новыйpostcss.config.js
конфигурационный файл
module.exports = {
plugins: {
// 处理 @import
'postcss-import': {},
// 处理 css 中 url
'postcss-url': {},
// 自动前缀
'autoprefixer': {
"browsers": [
"> 1%",
"last 2 versions"
]
}
}
}
В дополнение к необходимым функциональным плагинам, перечисленным в комментариях, мы также можем использоватьnextcss
(обработка нового синтаксиса css),px2rem/px-to-viewport
Плагины, связанные с адаптацией мобильного терминала.
babel-loader
Мы используем babel для компиляции js и js-подобных синтаксисов, которые не распознаются браузерами, таких как экранирование ES6+, JSX и т. д. будет такжеbabel-loaderКонфигурация разделена и должна быть создана.babelrc
и настроить:
{
"presets": [
[
/* *
* babel-preset-env
* 可以根据配置的目标运行环境自动启用需要的 babel 插件。
*/
"env", {
"modules": false, // 关闭 babel 对 es module 的处理
"targets": { // 目标运行环境
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}
]
],
"plugins": [
"syntax-dynamic-import" // 异步加载语法编译插件
]
}
загрузчик медиаресурсов
Также нам нужно настроить загрузчик для картинок, видео, шрифтов и др. Взяв за пример файлы шрифтов, мы в основном используемurl-loader:
{
/**
* 末尾 \?.* 匹配带 ? 资源路径
* 我们引入的第三方 css 字体样式对字体的引用路径中可能带查询字符串的版本信息
*/
test: /\.(woff2|woff|eot|ttf|otf)(\?.*)?$/,
/**
* url-loader
* 会配合 webpack 对资源引入路径进行复写,如将 css 提取成独立文件,可能出现 404 错误可查看 提取 js 中的 css 部分解决
* 会以 webpack 的输出路径为基本路径,以 name 配置进行具体输出
* limit 单位为 byte,小于这个大小的文件会编译为 base64 写进 js 或 html
*/
loader: 'url-loader',
options: {
limit: 10000,
name: 'static/fonts/[name].[hash:7].[ext]',
}
}
Копия статического файла
Прямая ссылка (абсолютный путь) и путь к ресурсам, определенный при выполнении кода, должны существовать в виде статических файлов.Эти файлы ресурсов не будут компилироваться и обрабатываться вебпаком, поэтому мы помещаем их в отдельную папку (например, static) и в После того, как код упакован и скопирован в наш выходной каталог, мы используемcopy-webpack-pluginЧтобы сделать это автоматически:
const CopyWebpackPlugin = require('copy-webpack-plugin')
// 在开发模式下,会将文件写入内存
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: 'static',
ignore: ['.*']
}
])
Этот плагин вылетает, когда копируется слишком много файлов. Я не знаю, решена ли проблема.
производственный режим производства
Сначала мы настраиваем производственный режим.
Добавить команду сценария сценария
Добавить в package.json
"scripts": {
"build": "node build/build.js"`
}
затем используйтеnpm run build
команда может быть выполненаnode build/build.js
, мы не используем напрямуюwebpack webpack.prod.config.js
команду для выполнения файла конфигурации, но в build.js выполните некоторую обработку удаления файла, а затем запустите webpack.
Создать логику build.js
В основном две работы, представляяrimraf
Модуль удаляет указанные файлы, созданные в рамках веб-пакета, запускает веб-пакет и выдает разные подсказки на разных этапах.
// 在第一行设置当前为 生产环境
process.env.NODE_ENV = 'production'
const webpack = require('webpack')
const rm = require('rimraf')
const webpackConfig = require('./webpack.prod')
// 删除 webpack 输出目录下的内容,也可只删除子文件如 static 等
rm(webpackConfig.output.path, err => {
// webpack 按照生产模式配置启动
webpack(webpackConfig, (err, stats) => {
// 输出一些状态信息
})
}
Дополнительные сведения см. в комментариях к исходному коду..
Профиль производственного режима
новыйwebpack.prod.js
файл, использовать
const merge = require('webpack-merge') // 专用合并 webpack 配置的包
const webpackBaseConfig = require('./webpack.base')
module.exports = merge(webpackBaseConfig, {
// 生产模式配置
})
Объедините базовую конфигурацию и уникальную конфигурацию производственного режима, а затем мы начнем заполнять информацию о конфигурации веб-пакета в производственном режиме.
④ предустановка режима
Это новый API для webpack4 с тремя пресетами:development
,production
,none
, выбираем в производственном режимеmode: 'production'
, webpack4 под этой конфигурациейвключено по умолчаниюсейчас:
- плагин
- FlagDependencyUsagePlugin: должен удалять бесполезный код, другие плагины зависят от
- FlagIncludedChunksPlugin: должен удалять бесполезный код, другие плагины зависят от
- ModuleConcatenationPlugin: расширяет возможности хостинга webpack3.
- NoEmitOnErrorsPlugin: не выскакивать при обнаружении кодов ошибок
- OccurrenceOrderPlugin
- SideEffectsFlagPlugin
- UglifyJsPlugin: сжатие кода js
- Значение process.env.NODE_ENV установлено на производство
Поэтому нам не нужно настраивать это содержимое, включенное по умолчанию.
Последняя часть настройкиprocess.env.NODE_ENV 的值设为 production
Фактически, используйте плагин DefinePlugin:
new webpack.DefinePlugin({
"process.env.NODE_ENV": JSON.stringify("production")
})
Чтобы мы могли передать бизнес-кодprocess.env.NODE_ENV
, например, решить, следует ли использовать интерфейс разработки или онлайн-интерфейс. Если нам нужно судить о текущей среде в webpack, нам также нужна отдельная настройкаprocess.env.NODE_ENV = 'production'
, где мы также находимсяbuild.js
какая первая строка в .
Добавьте пакеты, сгенерированные webpack, в файл HTML.
- Когда мы используем веб-пакет для настройки записи, мы можем настроить только файл js в качестве записи, а пакеты, созданные веб-пакетом, не могут быть автоматически связаны с HTML-файлом нашего проекта.
- Нам нужно вручную добавить
<script src="./bundles.js"></script>
(может также включать файл css, извлеченный позже) в файл HTML. - мы можем использоватьhtml-webpack-pluginПлагин делает это автоматически.
- Этот шаг не требуется, если с веб-пакетом связан только js и файлы HTML не требуются.
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
filename: path.join(__dirname, '../dist/index.html'),// 文件写入路径
template: path.join(__dirname, '../src/index.html'),// 模板文件路径
inject: true // js 等 bundles 插入 html 的位置 head/body等
})
]
Если HtmlWebpackPlugin не настроен, он создаст файл HTML сfilename
Это более важно в режиме разработки.
④ Извлеките css-часть js в отдельный файл.
Студенты, которые использовали webpack3, должны быть правыextract-text-webpack-pluginПлагин (названный в честь старого плагина) более привычный, чтобы попробовать webpack4, я не хочу использовать этот плагин@next
версии, поэтому был выбран новый альтернативный плагинmini-css-extract-plugin(называемый новым плагином).
Так же, как и старый плагин, его также необходимо настроить как в разделе загрузчика, так и в разделе плагинов веб-пакета, разница в том, что новый плагин предоставляет отдельный загрузчик, который не настраивается так же, как старый плагин в раздел загрузчика. Конфигурация выглядит следующим образом:
-
секция погрузчика
```js const MiniCssExtractPlugin = require("mini-css-extract-plugin") // ... [ { loader: MiniCssExtractPlugin.loader, options: { /* * 复写 css 文件中资源路径 * webpack3.x 配置在 extract-text-webpack-plugin 插件中 * 因为 css 文件中的外链是相对与 css 的, * 我们抽离的 css 文件在可能会单独放在 css 文件夹内 * 引用其他如 img/a.png 会寻址错误 * 这种情况下所以单独需要配置 ../,复写其中资源的路径 */ publicPath: '../' }, { loader: 'css-loader', options: {} }, { loader: 'less-loader', options: {} } ] ```
-
раздел плагинов
```js new MiniCssExtractPlugin({ // 输出到单独的 css 文件夹下 filename: "static/css/[name].[chunkhash].css" }) ```
Вы можете видеть, что этот загрузчик также настроен в разделе препроцессора css, мы извлекли конфигурацию препроцессора css в функцию файла utils.js, поэтому здесь мы также используемextract
Параметр определяет, требуется ли извлечение.
Напомним, ранее использовавшийсяstyle-loader
илиvue-style-loader
, они создают теги для вставки содержимого css непосредственно в HTML. После извлечения в отдельный файл css работа по вставке в HTML выполняетсяhtml-webpack-plugin
Плагин сделан, и эта часть обязанностей у двоих дублируется, поэтому нам нужно использоватьextract
Параметры обрабатываются следующим образом:
if (options.extract) {
return [MiniCssExtractPlugin.loader, ...otherLoaders]
} else {
return ['vue-style-loader', ...otherLoaders]
}
④ Разделить код js
Это очень важная часть настройки вебпака.Она влияет на рациональность использования нами кеширования браузера и скорость загрузки ресурсов страницы.Разумное разбиение js может эффективно уменьшить диапазон файлов, затрагиваемых каждым обновлением кода. .
Студенты, которые использовали webpack3, должны знать, что мы обычно извлекаем эти файлыmanifest.js
(Когда работает webpack, то есть webpack анализирует код других бандлов и т.д.),vendor.js
(библиотеки в node_modules), app.js (реальный бизнес-код проекта). В webpack3 мы используемwebpack.optimize.CommonsChunkPlugin
Плагин извлечен, и мы можем использовать его прямо в webpack4.optimizationЭлементы конфигурации для настройки (конечно, вы все еще можете использовать конфигурацию плагина):
/**
* 优化部分包括代码拆分
* 且运行时(manifest)的代码拆分提取为了独立的 runtimeChunk 配置
*/
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
// 提取 node_modules 中代码
vendors: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
},
commons: {
// async 设置提取异步代码中的公用代码
chunks: "async"
name: 'commons-async',
/**
* minSize 默认为 30000
* 想要使代码拆分真的按照我们的设置来
* 需要减小 minSize
*/
minSize: 0,
// 至少为两个 chunks 的公用代码
minChunks: 2
}
}
},
/**
* 对应原来的 minchunks: Infinity
* 提取 webpack 运行时代码
* 直接置为 true 或设置 name
*/
runtimeChunk: {
name: 'manifest'
}
}
Вы также можете настроить неизмененные зависимости разработки в отдельные записи, например:
entry: {
app: 'index.js',
vendor2: ['vue', 'vue-router', 'axios']
}
режим разработки
Разница между режимом разработки и производственным режимом заключается в том, что код часто запускается во время разработки, поэтому многие вещи не рекомендуется настраивать в режиме разработки, например извлечение файлов css, сжатие кода и т. д. Итак, для некоторых функций, которые записаны в общедоступный файл конфигурации, но не требуются в режиме разработки, нам необходимо внести аналогичные изменения:process.env.NODE_ENV === 'production' ? true : false
, например, настраивать ли загрузчик извлечения в предварительной обработке cssMiniCssExtractPlugin.loader
. Кроме того, некоторые из них настраиваются только в рабочем режиме, напримерMiniCssExtractPlugin
и оптимизация разделения кода js.
режим разработки нам нуженслужба разработки, помогите нам завершить обновление в реальном времени, прокси-сервер интерфейса и другие функции. Мы используемwebpack-dev-server
. Требуется установка npm.
Добавить команду сценария сценария
Точно так же в package.json добавьте
"scripts": {
"dev": "webpack-dev-server --config ./build/webpack.dev.js"
}
использовать--config
Укажите файл конфигурации.Поскольку команда напрямую вызывает webpack-dev-server для запуска, мы можем просто написать конфигурацию напрямую, и мы можем написать логику вызова, в отличие от производственного режима.
Файл конфигурации режима разработки
новыйwebpack.dev.js
файл, также используйте:
// 在第一行设置当前环境为开发环境
process.env.NODE_ENV = 'development'
const merge = require('webpack-merge') // 专用合并webpack配置的包
const webpackBaseConfig = require('./webpack.base')
module.exports = merge(webpackBaseConfig, {
// 开发模式配置
})
④ предустановка режима
Точно так же в режиме разработки мы можем поставитьmode
настроен какdevelopment
,такой жевключено по умолчаниюнекоторые функции:
- плагин
- NamedChunksPlugin: использовать имя записи в качестве идентификатора чанка
- NamedModulesPlugin: используйте относительный путь модуля, чтобы не увеличивать идентификатор в качестве идентификатора модуля.
- Значение process.env.NODE_ENV установлено на разработку
Конфигурация службы разработки devServer
devServer: {
clientLogLevel: 'warning',
inline: true,
// 启动热更新
hot: true,
// 在页面上全屏输出报错信息
overlay: {
warnings: true,
errors: true
},
// 显示 webpack 构建进度
progress: true,
// dev-server 服务路径
contentBase: false,
compress: true,
host: 'localhost',
port: '8080',
// 自动打开浏览器
open: true,
// 可以进行接口代理配置
proxy: xxx,
// 跟 friendly-errors-webpack-plugin 插件配合
quiet: true,
publicPath: '/'
}
другие плагины
Плагин требуется, когда devServer использует горячее обновление:
plugins: [
new webpack.HotModuleReplacementPlugin()
]
Чтобы оптимизировать вывод информации веб-пакета, вам необходимо настроить:
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
plugins: [
new FriendlyErrorsPlugin()
]
Меры предосторожности
- Горячее обновление: при использовании горячего обновления нельзя использовать имя нашего чанка.
[hash]
Для идентификации изменение имени файла не может быть обновлено в горячем режиме, поэтому вам необходимо записать конфигурацию имени файла в выходных данных, изначально настроенных в общедоступной конфигурации, в конфигурации режима производства и разработки и удалить режим разработки.[hash]
filename: 'static/[name].js', chunkFilename: 'static/[id].js'
- HtmlWebpackPlugin: в производственном режиме мы записываем html-файлы в dist, но в режиме разработки нет фактического процесса записи, и
devServer
Содержимое службы после запуска такое же, какcontentBase
связаны, они должны быть согласованы, поэтому мы будемHtmlWebpackPlugin
Конфигурация также разделена на режим производства и разработки, используйте в режиме разработки:new HtmlWebpackPlugin({ filename: 'index.html', // 文件写入路径,前面的路径与 devServer 中 contentBase 对应 template: path.resolve(__dirname, '../src/index.html'),// 模板文件路径 inject: true })
оптимизация
Извлечение конфигурации
- Некоторые функции режима разработки и производственного режима включены, например, извлекается CSS или нет.
- Конфигурация пути, например путь к выходному файлу и имя файла, publicPath в выходных данных (настраивается только в выходных данных кодаpath, не настроеноpublicPath, напишите статическую часть этой части пути к выходному имени каждого ресурса, вы можете обратиться кПодробное объяснение publicPath в Webpack), конфигурация службы, такая как порт и т. д.
Мы можем извлечь независимый файл конфигурации (этот код не выполняется).
разделить js-код
в производственном режиме拆分 js 代码
Мы уже говорили о том, как разделить, поэтому, чтобы лучше проанализировать, разумно ли наше разделение, мы можем настроить плагин для анализа состава бандла.
const BundleAnalyzer = require('webpack-bundle-analyzer')
plugins: [
new BundleAnalyzer.BundleAnalyzerPlugin()
]
отверждение гашиша
Мы используем изменение хеша в имени файла для обновления файла ресурсов, поэтому при разумном использовании кеша мы должны разумно разбивать файл и минимально влиять на хеш в имени файла при обновлении содержимого. используется здесь[hash]
,[chunkhash]
,[contenthash]
. Однако стандартная обработка хэша веб-пакетом неудовлетворительна.Для оптимизации этой части см.Схема постоянного кэширования на основе веб-пакета
несколько страниц
Код многостраничной конфигурации находится по адресумногостраничная ветка. Нам нужно всего лишь внести несколько изменений, в качестве примера возьмем страницу входа и страницу индекса.
изменения записи
Настройте запись js обеих страниц вwebpack
изentry
середина:
entry: {
/**
* 入口,chunkname: 路径
* 多入口可配置多个
*/
main: './src/main.js',
entry: './src/entry.js'
}
Вы также можете сами задать структуру проекта и использовать API узла для динамического чтения текущей многостраничной записи.
Изменения HtmlWebpackPlugin
Необходимо настроить несколько в зависимости от количества страницHtmlWebpackPlugin
:
new HtmlWebpackPlugin({
filename: path.join(__dirname, '../dist/main.html'),// 文件写入路径
template: path.join(__dirname, '../src/index.html'),// 模板文件路径
inject: true, // 插入位置
chunks: ['manifest', 'vendors', 'common', 'main']
}),
new HtmlWebpackPlugin({
filename: path.join(__dirname, '../dist/entry.html'),// 文件写入路径
template: path.join(__dirname, '../src/index.html'),// 模板文件路径
inject: true, // 插入位置
chunks: ['manifest', 'vendors', 'common', 'entry']
}),
Среди них нужно вручную указать вставляемые чанки (синхронизированные) каждой страницы, иначе файлы других страниц тоже будут вставляться в текущую страницу.
④ Открытое извлечение js
На одной странице, как правило, нет проблем с извлечением общего кода (non-node_modules) неасинхронных js-файлов.На нескольких страницах наши страницы могут совместно использовать API, файлы конфигурации и другие файлы.В настоящее время вы можете добавить:
'common': {
// initial 设置提取同步代码中的公用代码
chunks: 'initial',
// test: 'xxxx', 也可使用 test 选择提取哪些 chunks 里的代码
name: 'common',
minSize: 0,
minChunks: 2
}
Извлечение общего кода в синхронном коде