предисловие
Vuepress имеет три набора конфигурации веб-пакета: базовая конфигурация, конфигурация разработки, конфигурация сборки, которая, кажется, ничем не отличается от обычного внешнего проекта, но использует цепочку веб-пакетов для генерации конфигурации вместо традиционной жестко запрограммированной конфигурации.
См. связанный исходный кодcreateBaseConfig.js,createClientConfig,createServerConfig.
Введение в цепочку webpack
обертка цепи
После введения webpack-chain вся наша конфигурация webpack может быть сгенерирована через обёртку цепочки:
const Config = require('webpack-chain');
const config = new Config();
// 链式生成配置
...
// 导出 webpack 配置对象
export default config.toConfig();
Прежде чем представить подробные примеры, давайте представим две структуры данных, встроенные в цепочку webpack: ChainMap и ChainSet.
ChainedSet
Коллекция со связанными методами.
Очевидно, это то же самое, что и ES6.SetТочно так же у обоих есть пары ключ-значение, но стоит упомянуть, что он работает через цепные методы.
В цепочке webpack принадлежащие ChainedSet:config.entry(name)
,config.resolve.modules
Ждать.
Если нам нужно указать вход в конфигурацию веб-пакета, нам просто нужно сделать это:
config
.entry('app')
.add('src/index.js')
Это эквивалентно этой части объекта конфигурации webpack:
entry: {
app: './src/index.js'
}
Конечно, реальная сила ChainedSet, которую я хочу подчеркнуть, заключается во встроенных методах, предоставляемых ChainedSet: add(value), delete(value), has(value) и т. д.
Это может помочь нам CRUD проверить любую часть всей конфигурации веб-пакета.
ChainedMap
Хеш-таблица со связанными методами.
То же самое, это то же самое, что и ES6.MapТочно так же он также работает с помощью цепных методов.
В цепочке webpack принадлежащие ChainedMap:config
,config.resolve
Ждать.
Читатели, которые хотят узнать больше об использовании API, могут перейти наДокументация.
Знакомство с принципом работы webpack-chain
Открываем исходный каталог:
Есть три типа: Chainable, ChainedSet или ChainedMap, другие.
цепной вызов
Chainable реализует функцию вызова цепочки, и ее код очень лаконичен:
module.exports = class {
constructor(parent) {
this.parent = parent;
}
batch(handler) {
handler(this);
return this;
}
end() {
return this.parent;
}
};
Отсюда происходит наиболее часто вызываемый конечный метод, который возвращает объект на переднем конце цепочки вызовов.
Например, у нас есть этот фрагмент кода в vuepress:
config
.use('cache-loader')
.loader('cache-loader')
.options({
cacheDirectory,
cacheIdentifier
})
.end()
.use('babel-loader')
.loader('babel-loader')
.options({
// do not pick local project babel config
babelrc: false,
presets: [
require.resolve('@vue/babel-preset-app')
]
})
Возврат в end() в конце восьмой строки сноваconfig
.
И ChainedSet, и ChainedMap наследуются от Chainable, и большинство других классов наследуются от ChainedSet или ChainedMap, за исключением классов Use и Plugin, обернутых функцией высшего порядка Orderable (эквивалентной декоратору), целью которой является решение проблемы при использовании module.use или плагин Проблема корректировки порядка. Заинтересованные читатели могут прочитать самостоятельноисходный код~
Приложение в Vuepress
Мы не будем вдаваться в детали трех конфигураций, ведь это можно сделать и в проектах, которые вы обычно разрабатываете. Что я должен упомянуть здесь, так это то, чтоНапишите функцию для генерации конфигурации webpack:
Например, в createBaseConfig есть такая функция:
function createCSSRule (lang, test, loader, options) {
const baseRule = config.module.rule(lang).test(test)
const modulesRule = baseRule.oneOf('modules').resourceQuery(/module/)
const normalRule = baseRule.oneOf('normal')
applyLoaders(modulesRule, true)
applyLoaders(normalRule, false)
function applyLoaders (rule, modules) {
if (!isServer) {
if (isProd) {
rule.use('extract-css-loader').loader(CSSExtractPlugin.loader)
} else {
rule.use('vue-style-loader').loader('vue-style-loader')
}
}
rule.use('css-loader')
.loader(isServer ? 'css-loader/locals' : 'css-loader')
.options({
modules,
localIdentName: `[local]_[hash:base64:8]`,
importLoaders: 1,
sourceMap: !isProd
})
rule.use('postcss-loader').loader('postcss-loader').options(Object.assign({
plugins: [require('autoprefixer')],
sourceMap: !isProd
}, siteConfig.postcss))
if (loader) {
rule.use(loader).loader(loader).options(options)
}
}
}
Он делает одну вещь: модульная и немодульная обработка css для определенного языка стилей в следующем порядке: загрузчик -> postcss-загрузчик -> css-загрузчик -> vue-style-loader или Extract-css -loader. Он используется следующим образом:
createCSSRule('css', /\.css$/)
createCSSRule('postcss', /\.p(ost)?css$/)
createCSSRule('scss', /\.scss$/, 'sass-loader', siteConfig.scss)
createCSSRule('sass', /\.sass$/, 'sass-loader', Object.assign({ indentedSyntax: true }, siteConfig.sass))
createCSSRule('less', /\.less$/, 'less-loader', siteConfig.less)
createCSSRule('stylus', /\.styl(us)?$/, 'stylus-loader', Object.assign({
preferPathResolver: 'webpack'
}, siteConfig.stylus))
Уменьшает ли это объем написания конфигурации? Он также гибко поддерживает определяемые пользователем параметры и более поздние изменения кода.
Эпилог
Когда следует использовать webpack-chain? Ведь его внедрение удорожает проект, мой ответ таков:
- Когда конфигурацию веб-пакета проекта необходимо сгенерировать в соответствии с некоторой логикой, рекомендуется ввести webpack-chain для декларативного написания конфигурации веб-пакета.
- Если конфигурация веб-пакета проста или вы просто пишете объект напрямую, не рекомендуется вводить цепочку веб-пакетов, Если есть несколько конфигураций, которые необходимо объединить, вы можете ввести веб-слияние.