Адрес репозитория на гитхабе:GitHub.com/Эвелин ззз/день…
Версия:Webpack 4.39.1
Связанные зависимости:
- MiniCssExtractPlugin: 0.8.0
- style-loader: 1.0.0
- less-loader: 5.0.0
- postcss-loader: 3.0.0
- css-loader: 3.2.0
Определите, является ли это режимом разработки или режимом производства
При настройке Webpack необходимо различать, используется ли он в режиме разработки или в рабочем режиме. Например, нам нужно только сжимать CSS в рабочем режиме, в режиме разработки мы также хотим сгенерировать Sourcemap для отладки и горячего обновления стилей. Итак, как оценить режим разработки и производства в webpack.config.js?
Обычно я определяю три файла конфигурации веб-пакета:
- webpack.config.base.js: Общая конфигурация, такая как вход, выход, плагин, загрузчик и т. д. Следующие два файла конфигурации введут эту конфигурацию, а затем изменят и добавят другие конфигурации.
- webapck.config.dev.js: В режиме разработки запустите webpack-dev-server.
- webapck.config.prod.js: В рабочем режиме компилировать и упаковывать.
Затем настройте его отдельно в package.jsonstart
а такжеbuild
сценарий:
{
"scripts": {
"start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js --open",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js --progress --colors -p"
}
}
Обратите внимание, что переменная определяется в команде какNODE_ENV
, поэтому в webpack.config.base.js вы можете передатьprocess.env.NODE_ENV
Получает свое значение, таким образом оценивая режим производства или режим разработки.
const devMode = process.env.NODE_ENV === 'development'; // 是否是开发模式
Далее переходите к делу.
Извлечь CSS в отдельный файл
До Webpack 4 мы использовалиextract-text-webpack-pluginПлагин для извлечения файлов стилей, представленных в проекте, упакованных в отдельный файл. Начиная с Webpack 4, этот плагин устарел и его необходимо использовать.MiniCssExtractPlugin.
This plugin extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.
этот плагинСоздайте отдельный файл CSS для каждого файла JS, содержащего CSS.и поддерживает загрузку CSS и SourceMap по требованию.
Уведомление: Каждый JS-файл, содержащий CSS, упомянутый здесь, означает не JS-файл, соответствующий компоненту, а упакованный JS-файл! Это будет подробно объяснено далее.
Сценарий 1
Сначала рассмотрим пример базовой конфигурации.webpack.config.js:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
}),
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, 'css-loader','postcss-loader' // postcss-loader 可选
],
},{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader, 'css-loader','postcss-loader','less-loader' // postcss-loader 可选
],
}
],
},
};
В соответствии с приведенной выше конфигурацией, если в записи app.js есть ссылка на Root, Root вводит разделы. Ссылка на стиль main.css содержится в файле Root.js, а ссылка на файл Topics.css — в файле Topics.js.
// 入口文件 app.js
import Root from './components/Root'
// Root.js
import '../styles/main.less'
import Topics from './Topics'
// Topics.js
import "../styles/topics.less"
В этом случае Topics будут принадлежать тому же чанку, что и Root, поэтому они будут упакованы в app.js вместе, в результате main.less и Topics.less будут извлечены в один файл: app.css. вместо создания двух файлов css.
Asset Size Chunks Chunk Names
app.css 332 bytes 1 [emitted] app
app.js 283 KiB 1 [emitted] [big] app
Сценарий 2
Однако, если Root.js не вводит компонент Topics напрямую, а настраиваетразделение кода, например модульДинамичное введение, то результат другой:
Asset Size Chunks Chunk Names
app.css 260 bytes 1 [emitted] app
app.js 281 KiB 1 [emitted] [big] app
topics.bundle.js 2.55 KiB 4 [emitted] topics
topics.css 72 bytes 4 [emitted] topics
Поскольку на данный момент есть два фрагмента, соответствующие двум файлам JS, CSS из двух файлов JS будет извлечен для создания соответствующих файлов. Вот что на самом деле означает «создать отдельный файл CSS для каждого файла JS, содержащего CSS».
Сценарий третий
Но что, если вы разделите фрагменты и хотите сгенерировать только один файл CSS? Это также можно сделать. Но нужно использовать конфигурацию Webpackoptimization.splitChunks.cacheGroups
.
optimization.splitChunksДля чего это? До Webpack 4 мы использовалиCommonsChunkPlugin
Для извлечения повторно вводимых сторонних зависимостей, таких как извлечение React и Jquery в один файл. А начиная с Webpack 4,CommonsChunkPlugin
одеялоoptimization.splitChunks
заменены. Из названия также видно, что он используется для разделения чанков. Почему нам нужно использовать эту конфигурацию здесь? Давайте посмотрим, как пишется конфигурация:
optimization: {
splitChunks: {
cacheGroups: {
// Extracting all CSS/less in a single file
styles: {
name: 'styles',
test: /\.(c|le)ss$/,
chunks: 'all',
enforce: true,
},
}
}
},
Результат упаковки:
Asset Size Chunks Chunk Names
app.js 281 KiB 2 [emitted] [big] app
styles.bundle.js 402 bytes 0 [emitted] styles
styles.css 332 bytes 0 [emitted] styles
topics.bundle.js 2.38 KiB 5 [emitted] topics
Видно, что стили действительно извлекаются в файл styles.css. Но при этом есть еще один файл style.bundle.js, которыйoptimization.splitChunks.cacheGroups
Эффект. Конкретные принципы здесь не обсуждаются, если интересно, можете изучить.
MiniCssExtractPlugin vs. style-loader
Во-первых, назначение этих двух плагинов совершенно разное: MiniCssExtractPlugin извлекает CSS, представленный в JS, и упаковывает его в отдельный файл, а затем использует теги<link>
добавлено в шапку, передан style-loader<style>
Теги вставляют CSS непосредственно в DOM.
Обычно базовая конфигурация CSS выглядит примерно так. Сначала загрузчик стилей, затем загрузчик css.
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader', 'css-loader'
],
},
],
}
Но затем, поскольку вы хотите извлечь CSS в отдельный файл, вам нужно использовать MiniCssExtractPlugin. Итак, вопрос в том, возможна ли следующая конфигурация?
{
test: /\.css$/,
use: [
'style-loader', MiniCssExtractPlugin.loader, 'css-loader','postcss-loader'
],
}
производственный режим
согласно сДокументация по MiniCssExtractPluginКак уже упоминалось, этот плагин работает безstyle-loader
в производственном режиме и в режиме разработки, для которого требуется HMR.
This plugin should be used only on
production
builds withoutstyle-loader
in the loaders chain, especially if you want to have HMR indevelopment
.
То есть в режиме производства одновременно используется указанная выше конфигурация.style-loader
и MiniCssExtractPlugin не подходит (пробовал,style-loader
не будет работать).
Мы можем взять только одну из них. Его также можно комбинировать следующим образом, используя загрузчик стилей в режиме разработки и MiniCssExtractPlugin в режиме производства. Каждый берет то, что ему нужно, ведь роли у двоих все же очень разные.
{
test: /\.css$/,
use: [
devMode?'style-loader':MiniCssExtractPlugin.loader,'css-loader','postcss-loader'
]
}
Горячее обновление файла стиля (HMR)
Из приведенного выше предложения также видно, что в режиме разработки мы можем использовать MiniCssExtractPlugin для реализации стиля HMR (горячая замена модуля).
Что такое HMR файла стиля? Если HMR не настроен, в режиме разработки при изменении исходных файлов CSS страница не будет автоматически обновляться для загрузки измененных стилей. Страница должна быть обновлена вручную, чтобы загрузить изменения. HMR, с другой стороны, реализует горячее обновление модифицированного модуля, так что изменения сразу отображаются на странице, и больше не нужно обновлять всю страницу.
Но по фактуstyle-loader
Также реализует интерфейс HMR, как описано в документации Wepack.In a ModuleСказано в:
HMR is an opt-in feature that only affects modules containing HMR code. One example would be patching styling through the
style-loader
. In order for patching to work, thestyle-loader
implements the HMR interface; when it receives an update through HMR, it replaces the old styles with the new ones.
Поэтому в среде разработки оба плагина могут обновлять CSS в горячем режиме, но конфигурация MiniCssExtractPlugin может быть богаче. Например: style-loader только горячо обновляет стили, представленные в JS, если они переданы в index.html.<link>
Файл CSS на сервере импортируется:
<link rel="stylesheet" href="/vendors/test.css">
<!-- 通过配置 copy-webpack-plugin 在打包时把 html/vendors/test.css 拷贝到服务器根目录中,因此可以这么链接 -->
Если вы измените исходный код test.css в режиме разработки, загрузчик стилей не будет оперативно обновлять измененный CSS, а должен будет обновить всю страницу, но MiniCssExtractPlugin автоматически перезагрузит все стили. Могут быть и другие отличия, которые здесь не описаны.
Плагин MiniCssExtractPlugin может настроить HMR файлов Less следующим образом:
const devMode = process.env.NODE_ENV === 'development'; // 是否是开发模式
//......
module.exports = {
//......
module: {
rules:[
{
test: /\.less$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// 只在开发模式中启用热更新
hmr: devMode,
// 如果模块热更新不起作用,重新加载全部样式
reloadAll: true,
},
},
'css-loader','postcss-loader','less-loader'
]
},
// ......
]
}
}
эталонное чтение
- Документация MiniCssExtractPlugin:Веб-пакет.Просто .org/plugins/people…
- Загрузка CSS из документации Webpack:Веб-пакет. Просто .org/guides/as color…
- документация по загрузчику стилей:Веб-пакет.Просто .org/loaders/Sunshine…
- Горячий модуль Замена документации Webpack:Веб-пакет. Просто .org/concepts/ Хорошо…