1 базовый обзор
Прежде всего, давайте рассмотрим общую конфигурацию веб-пакета, поскольку она будет использоваться позже, поэтому я кратко представлю ее.
1.1 Общая конфигурация веб-пакета
// 入口文件
entry: {
app: './src/js/index.js',
},
// 输出文件
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/' //确保文件资源能够在 http://localhost:3000 下正确访问
},
// 开发者工具 source-map
devtool: 'inline-source-map',
// 创建开发者服务器
devServer: {
contentBase: './dist',
hot: true // 热更新
},
plugins: [
// 删除dist目录
new CleanWebpackPlugin(['dist']),
// 重新穿件html文件
new HtmlWebpackPlugin({
title: 'Output Management'
}),
// 以便更容易查看要修补(patch)的依赖
new webpack.NamedModulesPlugin(),
// 热更新模块
new webpack.HotModuleReplacementPlugin()
],
// 环境
mode: "development",
// loader配置
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
}
]
}
Здесь мы сосредоточимся на свойствах модуля и плагинов, потому что сегодня речь пойдет о написании загрузчика и плагина, и эти два свойства нужно настроить.
1.2 Принцип упаковки
- Определите входной файл
- Определите зависимости модуля слой за слоем. (Импорт Commonjs, amd или es6, webpack проанализирует его. Для получения зависимостей кода)
- Все, что делает webpack, — анализирует код. Преобразование кода, компиляция кода, вывод кода
- Наконец, упакованный код формируется
Это некоторые основные знания WebPack, которые полезны для понимания рабочего механизма WebPack.
2 loader
Хорошо, первый главный герой дебютирует сегодня
2.1 Что такое загрузчик?
Загрузчик — это загрузчик файлов, который может загружать файлы ресурсов, выполнять некоторую обработку этих файлов, такую как компиляция, сжатие и т. д., и, наконец, упаковывать их вместе в указанный файл.
- Для обработки файла можно использовать несколько загрузчиков, причем порядок выполнения загрузчиков противоположен самому себе, то есть последний загрузчик выполняется первым, а первый загрузчик выполняется последним.
- Первый запущенный загрузчик получает в качестве параметра содержимое исходного файла, а остальные загрузчики получают в качестве параметра возвращаемое значение предыдущего выполненного загрузчика. Последний выполненный загрузчик вернет исходный код JavaScript этого модуля.
2.2 рукописный ввод загрузчика
нужно:
- Обрабатывать файлы .txt
- перевернуть строку
- заглавные буквы
Например: abcdefg преобразовано в Gfedcba
Хорошо, давайте начнем
1) Сначала создайте два загрузчика (здесь в качестве примера взят локальный загрузчик)
Зачем создавать два лаода? Причина будет объявлена позже
reverse-loader.js
module.exports = function (src) {
if (src) {
console.log('--- reverse-loader input:', src)
src = src.split('').reverse().join('')
console.log('--- reverse-loader output:', src)
}
return src;
}
uppercase-loader.js
module.exports = function (src) {
if (src) {
console.log('--- uppercase-loader input:', src)
src = src.charAt(0).toUpperCase() + src.slice(1)
console.log('--- uppercase-loader output:', src)
}
// 这里为什么要这么写?因为直接返回转换后的字符串会报语法错误,
// 这么写import后转换成可以使用的字符串
return `module.exports = '${src}'`
}
Смотрите, это структура погрузчика очень проста, это нормально, чтобы получить параметр и вернуть контент.
Затем создайте текстовый файл
2) mytest.txt
abcdefg
3) Теперь приступайте к настройке веб-пакета.
module.exports = {
entry: {
index: './src/js/index.js'
},
plugins: [...],
optimization: {...},
output: {...},
module: {
rules: [
...,
{
test: /\.txt$/,
use: [
'./loader/uppercase-loader.js',
'./loader/reverse-loader.js'
]
}
]
}
}
На этом настройка завершена
4) Импортируем этот скрипт в файл входа
Зачем нам импортировать сюда, разве мы не настраиваем webapck для обработки всех файлов .txt?
Поскольку веб-пакет будет фильтровать, если на файл нет ссылки, веб-пакет не будет упаковывать файл, и ваш загрузчик не будет выполняться.
import _ from 'lodash';
import txt from '../txt/mytest.txt'
import '../css/style.css'
function component() {
var element = document.createElement('div');
var button = document.createElement('button');
var br = document.createElement('br');
button.innerHTML = 'Click me and look at the console!';
element.innerHTML = _.join('【' + txt + '】');
element.className = 'hello'
element.appendChild(br);
element.appendChild(button);
// Note that because a network request is involved, some indication
// of loading would need to be shown in a production-level site/app.
button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
var print = module.default;
print();
});
return element;
}
document.body.appendChild(component());
Конфигурация package.json
{
...,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.js",
"start": "webpack-dev-server --open --config webpack.dev.js",
"server": "node server.js"
},
...
}
затем выполните команду
npm run build
На этом наш загрузчик закончен.
Теперь ответьте, зачем писать два загрузчика?
Смотрите порядок выполнения, наша конфигурация такая
use: [
'./loader/uppercase-loader.js',
'./loader/reverse-loader.js'
]
Как упоминалось ранее,Для обработки файла можно использовать несколько загрузчиков, и порядок выполнения загрузчиков противоположен порядку их выполнения.
Мы также можем написать свой собственный загрузчик для разбора пользовательских шаблонов.Например, vue-loader очень сложен.Он будет писать много парсинга файлов .vue внутри, а затем генерировать соответствующие html, js и css.
Здесь мы описываем только самое основное использование, если вам нужно больше, вы можете проверить"официальная документация загрузчика"
3 plugin
3.1 Что такое плагин?
В течение жизненного цикла работы Webpack многие события транслируются, и плагин может прослушивать эти события и изменять выходные результаты через API, предоставляемый Webpack, в нужное время.
В чем разница между плагином и загрузчиком?
Для загрузчика это преобразователь, который компилирует файл A для формирования файла B. Операция здесь представляет собой файл, например преобразование A.scss или A.less в B.css, простой процесс преобразования файла.
Плагин является расширителем, который обогащает сам веб-пакет.В течение всего процесса упаковки веб-пакета после завершения работы загрузчика он не манипулирует файлами напрямую, а работает на основе механизма событий.Он отслеживает определенные узлы в процессе упаковки веб-пакета и выполняет широкий спектр задач.
3.2 Минимальный плагин
/plugins/MyPlugin.js (локальный плагин)
class MyPlugin {
// 构造方法
constructor (options) {
console.log('MyPlugin constructor:', options)
}
// 应用函数
apply (compiler) {
// 绑定钩子事件
compiler.plugin('compilation', compilation => {
console.log('MyPlugin')
))
}
}
module.exports = MyPlugin
конфигурация веб-пакета
const MyPlugin = require('./plugins/MyPlugin')
module.exports = {
entry: {
index: './src/js/index.js'
},
plugins: [
...,
new MyPlugin({param: 'xxx'})
],
...
};
Это самый простой плагин (хотя мы ничего не делали)
- После запуска веб-пакета в процессе чтения конфигурации он сначала выполнит новый MyPlugin(options), чтобы инициализировать MyPlugin для получения его экземпляра.
- После инициализации объекта компилятора вызовите myPlugin.apply(compiler), чтобы передать объект компилятора экземпляру плагина.
- После того, как экземпляр плагина получит объект компилятора, он может прослушивать события, транслируемые Webpack, через компилятор.plugin(имя события, функция обратного вызова).
- И вы можете управлять веб-пакетом через объект компилятора.
Увидев это, вы можете спросить, что такое компилятор и что такое компиляция?
-
Объект Compiler содержит всю информацию о конфигурации среды Webpack., включая параметры, загрузчики, плагины, этот объект создается при запуске Webpack, он глобально уникален, и его можно просто понимать как экземпляр Webpack;
-
Объект Compilation содержит текущие ресурсы модуля, скомпилированные ресурсы, измененные файлы и т. д.. Когда Webpack работает в режиме разработки, каждый раз, когда обнаруживается изменение файла, будет создаваться новая компиляция. Объект Compilation также предоставляет множество обратных вызовов событий для расширений плагинов. Объекты компилятора также можно прочитать с помощью Compilation.
Разница между компилятором и компиляцией заключается в следующем:
Компилятор представляет собой весь жизненный цикл Webpack от запуска до завершения работы, а компиляция просто представляет собой новую компиляцию.
3.3 Поток событий
- Webpack использует Tapable для организации этой сложной производственной линии.
- Механизм потока событий webpack обеспечивает упорядоченность плагинов, делая всю систему очень масштабируемой.
- Механизм потоковой передачи событий webpack применяет шаблон наблюдателя, который очень похож на EventEmitter в Node.js.
привязать событие
compiler.plugin('event-name', params => {
...
});
триггерное событие
compiler.apply('event-name',params)
3.4 На что следует обратить внимание
- Пока вы можете получить компилятор или объект компиляции, вы можете транслировать новые события, поэтому вы также можете транслировать события в недавно разработанных плагинах для других плагинов для мониторинга и использования.
- Объекты Compiler и Compilation, передаваемые каждому подключаемому модулю, являются одной и той же ссылкой. Другими словами, изменение свойств компилятора или объекта компиляции в одном плагине повлияет на последующие плагины.
- Некоторые события являются асинхронными. Эти асинхронные события будут иметь два параметра. Второй параметр — это функция обратного вызова. Когда плагин завершает обработку задачи, ему необходимо вызвать функцию обратного вызова, чтобы уведомить веб-пакет перед переходом к следующему процессу обработки.. Например:
compiler.plugin('emit',function(compilation, callback) {
...
// 处理完毕后执行 callback 以通知 Webpack
// 如果不执行 callback,运行流程将会一直卡在这不往下执行
callback();
});
Что касается компиляции и компиляции, webpack определяет большое количество событий ловушек. Разработчики могут настроить обработку в любом месте в соответствии со своими потребностями.
3.5 Написать плагин вручную
Сцены:
Проект апплета mpvue компилируется webpack для создания подпакетов (которые мы вводим в основную программу как подпакеты), а затем допускаются к основному пакету. После того, как подпакет сгенерирован, адрес ссылки wxss публичного статического ресурса в нем необходимо добавить с префиксом подпакета: /subPages/enjoy_given.
До написания плагина сгенерированные ресурсы выглядят так: если этот путь импортировать в основной пакет как подпакет, он не сможет нормально получить доступ к ресурсам.
Итак, требование:
Измените путь к общедоступным ресурсам, представленным файлами стилей (файлами wxss) всех страниц в каталоге dist/static/css/pages.
Поскольку все стили страниц ссылаются на общий стиль vendor.wxss
那么就需要把@import "/static/css/vendor.wxss"; 改为:@import "/subPages/enjoy_given/static/css/vendor.wxss";
Хорошо, чтобы начать!
1) Создайте файл плагина CssPathTransfor.js
CssPathTransfor.js
class CssPathTransfor {
apply (compiler) {
compiler.plugin('emit', (compilation, callback) => {
console.log('--CssPathTransfor emit')
// 遍历所有资源文件
for (var filePathName in compilation.assets) {
// 查看对应的文件是否符合指定目录下的文件
if (/static\/css\/pages/i.test(filePathName)) {
// 引入路径正则
const reg = /\/static\/css\/vendor\.wxss/i
// 需要替换的最终字符串
const finalStr = '/subPages/enjoy_given/static/css/vendor.wxss'
// 获取文件内容
let content = compilation.assets[filePathName].source() || ''
content = content.replace(reg, finalStr)
// 重写指定输出模块内容
compilation.assets[filePathName] = {
source () {
return content;
},
size () {
return content.length;
}
}
}
}
callback()
})
}
}
module.exports = CssPathTransfor
Выглядит много, но на самом деле проходит через модульcompile.assets. Регулярная замена соответствующих файлов.
2) Изменить конфигурацию веб-пакета
var baseWebpackConfig = require('./webpack.base.conf')
var CssPathTransfor = require('../plugins/CssPathTransfor.js')
var webpackConfig = merge(baseWebpackConfig, {
module: {...},
devtool: config.build.productionSourceMap ? '#source-map' : false,
output: {...},
plugins: [
...,
// 配置插件
new CssPathTransfor(),
]
})
После того, как плагин будет написан, выполните команду компиляции
получить это~
Если у вас есть дополнительные потребности, см."Как написать плагин"