Initial
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
.idea
|
||||||
|
|
||||||
# ---> Node
|
# ---> Node
|
||||||
# Logs
|
# Logs
|
||||||
logs
|
logs
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
## Версия 0.2.0 ()
|
||||||
|
* Перевод кода на TypeScript.
|
||||||
|
*
|
||||||
|
|
||||||
|
## Версия 0.1.2 (22 апреля 2022 г.)
|
||||||
|
* Добавлены поле `editor` и методы `addEditorButton` и `generateEditorButtons`.
|
||||||
|
|
||||||
|
## Версия 0.1.1
|
||||||
|
* Добавлен метод `addAuthorEditor`.
|
||||||
|
|
||||||
|
## Версия 0.1.0
|
||||||
|
* Начальная версия.
|
||||||
|
* Обработка событий `pun_main_ready`, `pun_preview`, `pun_post`, `pun_edit`, `spoiler.firstOpen`.
|
||||||
|
* Методы `addAdapter`, `addTag`.
|
||||||
@@ -1,3 +1,16 @@
|
|||||||
# mybbcode
|
# MyBBCode
|
||||||
|
|
||||||
Гибкий инструмент для работы с BB-кодами на форумах, основанных на платформе mybb.ru.
|
Гибкий инструмент для работы с BB-кодами на форумах, основанных на платформе mybb.ru.
|
||||||
|
|
||||||
|
# F.A.Q.
|
||||||
|
|
||||||
|
## Зачем нужна эта утилита?
|
||||||
|
Недавние изменения на MyBB, в частности, добавление пользовательских тегов и ajax в форме ответа, несколько изменили методы работу с пользовательскими тегами: первое изменение упростило, второе же усложнило. Это, впрочем, нормально, но, по меньшей мере, у меня случилась некоторая фрустрация оттого, как в некоторых местах приходиться работать с некоторыми тегами. Фрустрацию я преодолел, написав прослойку, которая позволяет при помощи относительно короткого и простого кода добавить методы для модификации.
|
||||||
|
|
||||||
|
## Что утилита делает?
|
||||||
|
Если простыми словами, то данный скрипт не делает ничего сам по себе, но он помогает облегчить жизнь тем, кто использует различные скрипты для модификации сообщений на форумах, обеспечивая простой доступ к
|
||||||
|
* обработке сообщений, в том числе загруженных через ajax, добавленных в предпросмотр и других местах,
|
||||||
|
* добавлению кнопок в форме ответа, а так же изменению порядка их отображения.
|
||||||
|
|
||||||
|
И всё это с использованием последних новинок на сервисе MyBB, которые могут позволить минимизировать количество кода для реализации простых функций.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"name": "mybbcode",
|
||||||
|
"version": "0.1.3",
|
||||||
|
"description": "Гибкий инструмент для работы с BB-кодами на форумах, основанных на платформе mybb.ru",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --mode=production --node-env=production",
|
||||||
|
"build:dev": "webpack --mode=development",
|
||||||
|
"build:prod": "webpack --mode=production --node-env=production",
|
||||||
|
"watch": "webpack --watch"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/kozhilya/mybbcode.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"mybb",
|
||||||
|
"bb",
|
||||||
|
"codes"
|
||||||
|
],
|
||||||
|
"author": "kozhilya",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/kozhilya/mybbcode/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/kozhilya/mybbcode#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.21.0",
|
||||||
|
"@babel/core": "^7.21.3",
|
||||||
|
"@babel/preset-env": "^7.20.2",
|
||||||
|
"@babel/preset-typescript": "^7.21.0",
|
||||||
|
"@types/jquery": "^3.5.29",
|
||||||
|
"@webpack-cli/generators": "^3.0.1",
|
||||||
|
"babelify": "^10.0.0",
|
||||||
|
"grunt": "^1.6.1",
|
||||||
|
"grunt-browserify": "^6.0.0",
|
||||||
|
"grunt-contrib-uglify": "^5.2.2",
|
||||||
|
"grunt-jsdoc-to-markdown": "^6.0.0",
|
||||||
|
"html-loader": "^4.2.0",
|
||||||
|
"jsdoc-babel": "^0.5.0",
|
||||||
|
"jsdoc-to-markdown": "^8.0.0",
|
||||||
|
"markdown-it": "^13.0.1",
|
||||||
|
"markdown-it-container": "^3.0.0",
|
||||||
|
"prettier": "^2.8.2",
|
||||||
|
"terser-webpack-plugin": "^5.3.7",
|
||||||
|
"ts-loader": "^9.4.2",
|
||||||
|
"tsify": "^5.0.4",
|
||||||
|
"typescript": "^5.3.3",
|
||||||
|
"uglify-js": "^3.17.4",
|
||||||
|
"webpack": "^5.76.3",
|
||||||
|
"webpack-cli": "^5.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"webpack-utf8-bom": "^1.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
export class Editor {
|
||||||
|
/**
|
||||||
|
* Порядок отображения кнопок формы ответа.
|
||||||
|
*/
|
||||||
|
buttons: string[] = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Массив из 2 значений, которые являются HTML-кодами, что будут добавлены до и после списка кнопок.
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
wrapper: string[] = ['<table><tr>', '</tr></table>'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Метод для генерации кнопок.
|
||||||
|
* @param {string} key Название кода, ключ объекта `FORUM.editor`.
|
||||||
|
* @param value Набор правил кода, соответствующее ключу key значения объекта `FORUM.editor[key]`.
|
||||||
|
*/
|
||||||
|
generator(key: string, value: any): string {
|
||||||
|
return `<td class="form-buttons-button" id="button-${key}" title="${value.name}"><img onclick="FORUM.get("editor.${key}.onclick()")" src="/i/blank.gif" alt=" " /></td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Дополнительные элементы, которые могут быть добавлены наряду с другими формы ответа
|
||||||
|
* @type {Object.<string, string>}
|
||||||
|
*/
|
||||||
|
specials: {[key: string] : string} = {
|
||||||
|
'|': '<td class="form-buttons-splitter"> </td>',
|
||||||
|
'~': '<td class="form-buttons-filler"> </td>',
|
||||||
|
'\n': '</tr><tr>',
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import MybbCode from "./mybb-code";
|
||||||
|
|
||||||
|
(window as any).MyBBCode = (window as any).MyBBCode || (() => {
|
||||||
|
return new MybbCode();
|
||||||
|
})();
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
import {AdapterCallback, AuthorEditorCallback, EventResolver, TagCallback} from "./types";
|
||||||
|
import {FORUM, MybbEditorTag} from "./mybb-editor";
|
||||||
|
import {Editor} from "./editor";
|
||||||
|
|
||||||
|
export default class MybbCode {
|
||||||
|
/**
|
||||||
|
* Текст, который будет установлен при вызове `set_html(false)` в обработчиках тегов,
|
||||||
|
* добавленных при помощи метода `addTag`.
|
||||||
|
* @type loadingText {string}
|
||||||
|
* @see addTag
|
||||||
|
*/
|
||||||
|
loadingText = '\u0421\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044F...';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Набор тегов
|
||||||
|
*/
|
||||||
|
private tags: {[key: string]: TagCallback} = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Набор адаптеров
|
||||||
|
*/
|
||||||
|
private adapters: AdapterCallback[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Набор обработчиков столбца автора
|
||||||
|
*/
|
||||||
|
private authorEditors: AuthorEditorCallback[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Выделение контейнеров сообщений для событий
|
||||||
|
*/
|
||||||
|
events: {[key: string]: EventResolver} = {
|
||||||
|
'pun_preview': (_) => $('#post-preview .post-content'),
|
||||||
|
'pun_post': (_) => $('.topic .new-ajax .post-content'),
|
||||||
|
'pun_edit': (e) => $(e.sender),
|
||||||
|
'pun_main_ready': (_) => $('.post-content'),
|
||||||
|
'spoiler.firstOpen': (e) => $(e.sender).parent().find('blockquote').eq(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Набор правил для генерации кнопок формы ответа. Удаление полей настоятельно не рекомендуется.
|
||||||
|
*/
|
||||||
|
editor: Editor = new Editor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Конструктор класса `MyBBCode`.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
$(document).on(Object.keys(this.events).join(' '), (event) => {
|
||||||
|
const blocks = this.events[event.type](event);
|
||||||
|
|
||||||
|
this.processPostContents(blocks);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (FORUM.editor) {
|
||||||
|
this.editor.buttons = Object.keys(FORUM.editor).filter((v) => v !== 'settings');
|
||||||
|
$(document).on('pun_main_ready', () => this.generateEditorButtons());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление нового события, который будет запускать обработчики сообщений и обработчики пользовательских кодов.
|
||||||
|
* @param {string} name Отслеживаемое DOM-событие, используемое методом `jQuery.on(name)`, и которое можно
|
||||||
|
* вызвать методом `jQuery.trigger(name)`.
|
||||||
|
* @param {EventResolver} resolver Это должна быть функция, которые на основе объекта события (`event`, он
|
||||||
|
* подаётся на вход этой функции), определяет, какие контейнеры должны быть
|
||||||
|
* обработаны обработчиками.
|
||||||
|
*/
|
||||||
|
registerEvent(name: string, resolver: EventResolver): void {
|
||||||
|
$(document).on(name, (event) => this.processPostContents(resolver(event)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Установка HTML загружающегося тега.
|
||||||
|
* @param {JQuery} elem Цель установки
|
||||||
|
* @param {string|false} html HTML-код для установки
|
||||||
|
*/
|
||||||
|
private setHtml(elem: JQuery, html: string|false): void {
|
||||||
|
if (html === false) {
|
||||||
|
elem.html(this.loadingText).addClass('loading');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
elem.html(html).removeClass('loading');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обработка контейнера сообщения всеми зарегистрированными обработчиками.
|
||||||
|
* @param containers jQuery-объект, ссылающийся на контейнер (или контейнеры), который содержит необработанное сообщение.
|
||||||
|
*/
|
||||||
|
private processPostContents(containers: JQuery): void {
|
||||||
|
containers.each((_, container) => {
|
||||||
|
const $container = $(container);
|
||||||
|
|
||||||
|
$.each(this.tags, (tag, action) => {
|
||||||
|
$('.custom_tag_' + tag, $container).each((i, elem) => {
|
||||||
|
const $elem = $(elem);
|
||||||
|
|
||||||
|
let id = $elem.prop('id') || (tag + '-' + i);
|
||||||
|
|
||||||
|
if ($elem.hasClass('processed')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
action($elem, '.custom_tag_' + tag + '#' + id, this.setHtml.bind(this, $elem));
|
||||||
|
|
||||||
|
$elem.addClass('processed');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$.each(this.adapters, (i, action) => {
|
||||||
|
action($container);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($container.hasClass('post-content')) {
|
||||||
|
const ul = $container.parents('.post').find('.post-author ul');
|
||||||
|
|
||||||
|
if (!ul.hasClass('mybbcode-processed')) {
|
||||||
|
$.each(this.authorEditors, (i, action) => {
|
||||||
|
action(ul);
|
||||||
|
});
|
||||||
|
|
||||||
|
ul.addClass('mybbcode-processed')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление обработчиков пользовательских тегов, добавленных через систему пользовательских тегов
|
||||||
|
* (/admin_forms.php — "Пользовательские bb-теги"). Для корректной работы обработчика рекомендуется
|
||||||
|
* (но НЕ необходимо) указать для тега флаг `u` (unique).
|
||||||
|
* @param {string} name Строка, название тега. Должно совпадать с названием тега в поле "Пользовательские bb-теги".
|
||||||
|
* @param {TagCallback} callback Функция, которая будет вызываться по событию.
|
||||||
|
*/
|
||||||
|
addTag(name: string, callback: TagCallback): void {
|
||||||
|
if (this.tags[name]) {
|
||||||
|
console.warn('[MyBBCode] Tag "' + name + '" declared more than one time!');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tags[name] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление общих обработчиков, которые будут применяться к сообщениям.
|
||||||
|
* @param {AdapterCallback} callback
|
||||||
|
*/
|
||||||
|
addAdapter(callback: AdapterCallback): void {
|
||||||
|
this.adapters.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление обработчика, изменяющего столбец автора сообщения.
|
||||||
|
* После обработки, к ul-элементу будет добавлен класс `mybbcode-processed`; если элемент имеет этот класс,
|
||||||
|
* обработчик не будет применён.
|
||||||
|
* @param {AuthorEditorCallback} callback
|
||||||
|
*/
|
||||||
|
addAuthorEditor(callback: AuthorEditorCallback): void {
|
||||||
|
this.authorEditors.push(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сгенерировать кнопку
|
||||||
|
* @param {string} key id кнопки
|
||||||
|
* @returns {string} Код кнопки
|
||||||
|
*/
|
||||||
|
private generateEditorButton(key: string): string {
|
||||||
|
if (!FORUM.editor) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key in this.editor.specials) {
|
||||||
|
return this.editor.specials[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key in FORUM.editor) {
|
||||||
|
const value = FORUM.editor[key];
|
||||||
|
return this.editor.generator(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сгенерировать заново строку с кнопками редактора.
|
||||||
|
*/
|
||||||
|
generateEditorButtons(): void {
|
||||||
|
if (!FORUM.editor || (this.editor.buttons === null)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const old = Object.keys(FORUM.editor).filter((v) => v !== 'settings');
|
||||||
|
let changed = old.length !== this.editor.buttons.length;
|
||||||
|
for (let i = 0; !changed && (i < old.length); i++) {
|
||||||
|
changed = changed || (old[i] !== this.editor.buttons[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = this.editor.wrapper[0];
|
||||||
|
|
||||||
|
for (const key of this.editor.buttons) {
|
||||||
|
result += this.generateEditorButton(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
result += this.editor.wrapper[1];
|
||||||
|
|
||||||
|
$('#form-buttons').empty().html(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Добавление кнопки формы.
|
||||||
|
* После объявления при помощи этого метода, объект `data` будет доступен после объявления как `FORUM.editor.key`.
|
||||||
|
* @param {string} key Идентификатор кнопки, который будет добавлен к `td.button#button-key`.
|
||||||
|
* @param {MybbEditorTag} data Данные поля, которые будут использоваться стандартными скриптами.
|
||||||
|
* Этому объектов можно указать и другие поля, однако указанные обязательны.
|
||||||
|
* @param {string} data.name Строка, название кнопки.
|
||||||
|
* @param {function} data.onclick Функция, которая будет вызвана при нажатии кнопки.
|
||||||
|
* @param {number|string|false} [before] Указание, перед каким элементом необходимо добавить кнопку. Допустимые значения:
|
||||||
|
* Число `i` — тогда кнопка будет добавлена перед `i`-м элементом массива `MyBBCode.editor.buttons`.
|
||||||
|
* Строкой-идентификатором кнопки `key` — тогда новая кнопка будет помещена перед кнопкой с идентификатором `key`.
|
||||||
|
*/
|
||||||
|
addEditorButton(key: string, data: MybbEditorTag, before: number|string|false = false): void {
|
||||||
|
if (!('FORUM' in window) || !('editor' in FORUM)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(key in this.editor.specials)) {
|
||||||
|
FORUM.editor[key] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.editor.buttons !== null) {
|
||||||
|
let index: number|false;
|
||||||
|
|
||||||
|
if (before === false) {
|
||||||
|
index = false;
|
||||||
|
}
|
||||||
|
else if (typeof before === "string") {
|
||||||
|
index = this.editor.buttons.indexOf(before);
|
||||||
|
index = (index < 0) ? false : index;
|
||||||
|
}
|
||||||
|
else if ((typeof before === "number") && (before >= 0) && (before < this.editor.buttons.length)) {
|
||||||
|
index = before;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index === false) {
|
||||||
|
this.editor.buttons.push(key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.editor.buttons.splice(index, 0, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
declare module 'FORUM' {
|
||||||
|
let FORUM: {
|
||||||
|
editor: MybbEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MybbEditorTag {
|
||||||
|
/**
|
||||||
|
* @param {string} name Строка, название кнопки.
|
||||||
|
*/
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {function} onclick Функция, которая будет вызвана при нажатии кнопки.
|
||||||
|
*/
|
||||||
|
onclick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MybbEditorSettings = {
|
||||||
|
autofocus: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MybbEditor = {
|
||||||
|
settings: MybbEditorSettings;
|
||||||
|
[key: string]: MybbEditorTag | MybbEditorSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function quote(e: string, t: string, i: string): void;
|
||||||
|
|
||||||
|
export function bbcode(tagStart: string, tagEnd: string): void;
|
||||||
|
|
||||||
|
export function changeVisibility(areaName: string): void;
|
||||||
|
|
||||||
|
export function insert(value: string): void;
|
||||||
|
|
||||||
|
export function smile(emote: string): void;
|
||||||
|
|
||||||
|
export function tag_table(rows: number, columns: number): void;
|
||||||
|
|
||||||
|
export function MYBB_vsi(element: HTMLElement, event: any): void;
|
||||||
|
|
||||||
|
export function insertUploadedImage(element: HTMLElement | JQuery): void;
|
||||||
|
|
||||||
|
export function tag_spoiler(spoilerType: string): void;
|
||||||
|
|
||||||
|
export function keyboard(character: string): void;
|
||||||
|
|
||||||
|
export function to(target: string): void;
|
||||||
|
|
||||||
|
export class MYBB_vsc {
|
||||||
|
cH: any;
|
||||||
|
RG: { [key: string]: MYBB_vsc_item };
|
||||||
|
checkHost: (hostingItem: MYBB_vsc_item, input: string) => boolean;
|
||||||
|
clickHost: (element: HTMLAnchorElement) => void;
|
||||||
|
parse: () => void;
|
||||||
|
isLink: (input: string) => boolean;
|
||||||
|
message: (html: string) => void;
|
||||||
|
reInit: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MYBB_vsc_item = {
|
||||||
|
l: "0" | "1";
|
||||||
|
t: string;
|
||||||
|
x: RegExp;
|
||||||
|
nf: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
export type AdapterCallback = (container: JQuery) => void;
|
||||||
|
|
||||||
|
export type TagCallback = (elem: JQuery,
|
||||||
|
selector: string,
|
||||||
|
set_html: string | boolean) => void;
|
||||||
|
|
||||||
|
export type AuthorEditorCallback = (container: JQuery) => void;
|
||||||
|
|
||||||
|
export type EventResolver = (e: any) => JQuery
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"module": "es6",
|
||||||
|
"target": "es2017",
|
||||||
|
"allowJs": true,
|
||||||
|
"declaration": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"typeRoots": [
|
||||||
|
"./node_modules/@types",
|
||||||
|
"./src/types"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const BomPlugin = require("webpack-utf8-bom");
|
||||||
|
const { exec } = require("node:child_process");
|
||||||
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
|
||||||
|
const isProduction = process.env.NODE_ENV === "production";
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
entry: "./src/main.ts",
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "dist"),
|
||||||
|
filename: () => "mybbcode" + (isProduction ? ".min" : "") + ".js",
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new BomPlugin(true),
|
||||||
|
{
|
||||||
|
apply: (compiler) => {
|
||||||
|
compiler.hooks.afterEmit.tap("AfterEmitPlugin", (compilation) => {
|
||||||
|
exec("./upload.sh", (err, stdout, stderr) => {
|
||||||
|
if (stdout) process.stdout.write(stdout);
|
||||||
|
if (stderr) process.stderr.write(stderr);
|
||||||
|
console.log("Uploaded.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Add your plugins here
|
||||||
|
// Learn more about plugins from https://webpack.js.org/configuration/plugins/
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(ts|tsx)$/i,
|
||||||
|
loader: "ts-loader",
|
||||||
|
exclude: ["/node_modules/"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
|
||||||
|
type: "asset",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/i,
|
||||||
|
loader: "html-loader",
|
||||||
|
},
|
||||||
|
// Add your rules for custom modules here
|
||||||
|
// Learn more about loaders from https://webpack.js.org/loaders/
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".tsx", ".ts", ".jsx", ".js", "..."],
|
||||||
|
},
|
||||||
|
externals: {
|
||||||
|
jquery: "jQuery",
|
||||||
|
},
|
||||||
|
watchOptions: {
|
||||||
|
aggregateTimeout: 20,
|
||||||
|
},
|
||||||
|
optimization: {
|
||||||
|
minimize: isProduction,
|
||||||
|
minimizer: [new TerserPlugin({
|
||||||
|
terserOptions: {
|
||||||
|
compress: true,
|
||||||
|
},
|
||||||
|
minify: TerserPlugin.uglifyJsMinify,
|
||||||
|
})],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
if (isProduction) {
|
||||||
|
config.mode = "production";
|
||||||
|
} else {
|
||||||
|
config.mode = "development";
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user