diff --git a/package-lock.json b/package-lock.json index 4c6a7e0..89f0c97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "mini-css-extract-plugin": "^2.4.4", "node-sass": "^6.0.1", "sass-loader": "^12.3.0", + "terser-webpack-plugin": "^5.3.0", "webpack": "^5.62.1", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.4.0", @@ -6624,9 +6625,9 @@ "dev": true }, "node_modules/jest-worker": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", - "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", + "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", "dev": true, "dependencies": { "@types/node": "*", @@ -10418,12 +10419,12 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz", - "integrity": "sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", + "integrity": "sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==", "dev": true, "dependencies": { - "jest-worker": "^27.0.6", + "jest-worker": "^27.4.1", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", "source-map": "^0.6.1", @@ -17202,9 +17203,9 @@ "dev": true }, "jest-worker": { - "version": "27.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", - "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", + "version": "27.4.5", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", + "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", "dev": true, "requires": { "@types/node": "*", @@ -20064,12 +20065,12 @@ } }, "terser-webpack-plugin": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.2.5.tgz", - "integrity": "sha512-3luOVHku5l0QBeYS8r4CdHYWEGMmIj3H1U64jgkdZzECcSOJAyJ9TjuqcQZvw1Y+4AOBN9SeYJPJmFn2cM4/2g==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz", + "integrity": "sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==", "dev": true, "requires": { - "jest-worker": "^27.0.6", + "jest-worker": "^27.4.1", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.0", "source-map": "^0.6.1", diff --git a/package.json b/package.json index 9660ec7..ea8ca58 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "mini-css-extract-plugin": "^2.4.4", "node-sass": "^6.0.1", "sass-loader": "^12.3.0", + "terser-webpack-plugin": "^5.3.0", "webpack": "^5.62.1", "webpack-cli": "^4.9.1", "webpack-dev-server": "^4.4.0", diff --git a/src/constants/constants.js b/src/constants/constants.js index ed6aee8..cb39549 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -55,6 +55,7 @@ export const HttpStatusCodes = { Unauthorized: 401, InternalServerError: 500, Forbidden: 403, + TooLarge: 413, }; /** @@ -104,6 +105,9 @@ export const ConstantMessages = { CantCopyToClipBoard: 'Не удалось скопировать текст', WrongTagNameLength: 'Введите имя тега длиной от 1 до 40 символов', + + OfflineMessage: 'Операция не удалась - отсутствует соединение с Интернетом', + TooLargeMessage: 'Файл фложения слишком большой', }; export const BoardStoreConstants = { @@ -123,11 +127,14 @@ export const SettingStoreConstants = { export const ServiceWorker = { CacheUrls: { HTML_URL: '/index.html', + OFFLINE_URL: '/offline', NO_INTERNET_IMG_URL: '/assets/no-internet-icon.webp', }, API_PREFIX: '/api', STATIC_CACHE_NAME: `static-cache-${APP_VERSION}`, API_CACHE_NAME: `api-cache-${APP_VERSION}`, + ATTACHMENT_PREFIX: '/attach', + ATTACH_NAME_PARAM: 'file_name', SW_HEADER: 'X-Is-From-Service-Worker', Messages: { OFFLINE_FROM_CACHE: 'offline-cache', // Приложение работает в offline diff --git a/src/stores/BoardStore/BoardStore.js b/src/stores/BoardStore/BoardStore.js index 39decb5..75cd24a 100644 --- a/src/stores/BoardStore/BoardStore.js +++ b/src/stores/BoardStore/BoardStore.js @@ -19,7 +19,7 @@ import { BoardStoreConstants, CheckLists, ConstantMessages, HTTP, - HttpStatusCodes, + HttpStatusCodes, ServiceWorker, Urls, } from '../../constants/constants.js'; @@ -599,10 +599,11 @@ class BoardStore extends BaseStore { * @private */ async _updateTitleAndDescription(data) { + this._storage.get('setting-popup').errors = null; if (SettingsStore.isOffline()) { + this._storage.get('setting-popup').errors = ConstantMessages.OfflineMessage; return; } - this._storage.get('setting-popup').errors = null; const validator = new Validator(); this._storage.get('setting-popup').errors = validator.validateBoardDescription(data.description); @@ -708,6 +709,7 @@ class BoardStore extends BaseStore { */ async _createCardList(data) { if (SettingsStore.isOffline()) { + this._storage.get('cardlist-popup').errors = ConstantMessages.OfflineMessage; return; } this._storage.get('cardlist-popup').errors = null; @@ -802,6 +804,7 @@ class BoardStore extends BaseStore { */ async _updateCardList(data) { if (SettingsStore.isOffline()) { + this._storage.get('cardlist-popup').errors = ConstantMessages.OfflineMessage; return; } this._storage.get('cardlist-popup').errors = null; @@ -956,6 +959,7 @@ class BoardStore extends BaseStore { */ async _createCard(data) { if (SettingsStore.isOffline()) { + this._storage.get('card-popup').errors = ConstantMessages.OfflineMessage; return; } this._storage.get('card-popup').errors = null; @@ -1136,6 +1140,7 @@ class BoardStore extends BaseStore { */ async _updateCard(data) { if (SettingsStore.isOffline()) { + this._storage.get('card-popup').errors = ConstantMessages.OfflineMessage; return; } this._storage.get('card-popup').errors = null; @@ -1326,10 +1331,11 @@ class BoardStore extends BaseStore { * @private */ async _createCheckList() { + const context = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('card-popup'); context.errors = null; const newCheckList = { @@ -1377,10 +1383,11 @@ class BoardStore extends BaseStore { * @private */ async _saveCheckList(data) { + const context = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('card-popup'); context.errors = null; const checkList = this._getCheckListById(data.chlid); @@ -1454,10 +1461,11 @@ class BoardStore extends BaseStore { * @private */ async _createCheckListItem(data) { + const context = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('card-popup'); context.errors = null; const checkList = this._getCheckListById(data.chlid); @@ -1506,10 +1514,11 @@ class BoardStore extends BaseStore { * @private */ async _saveCheckListItem(data) { + const context = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('card-popup'); context.errors = null; const item = this._getCheckListItemById(data.chlid, data.chliid); @@ -1587,10 +1596,11 @@ class BoardStore extends BaseStore { * @private */ async _toggleCheckListItem(data) { + const context = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('card-popup'); context.errors = null; context.selectInvite = false; let item = this._getCheckListItemById(data.chlid, data.chliid); @@ -1707,10 +1717,11 @@ class BoardStore extends BaseStore { * @private */ async _toggleCardAssigneeInSearchList(data) { + const context = this._storage.get('add-card-member-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('add-card-member-popup'); context.errors = null; context.selectInvite = false; @@ -1806,10 +1817,11 @@ class BoardStore extends BaseStore { * @private */ async _toggleBoardMemberInSearchList(data) { + const context = this._storage.get('add-board-member-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('add-board-member-popup'); context.selectInvite = false; context.errors = null; @@ -1912,10 +1924,11 @@ class BoardStore extends BaseStore { * @private */ async _createCardComment(data) { + const context = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('card-popup'); const comment = { cid: context.cid, @@ -1980,8 +1993,11 @@ class BoardStore extends BaseStore { */ async _updateCardComment(data) { if (SettingsStore.isOffline()) { + this._storage.get('card-popup').errors = ConstantMessages.OfflineMessage; return; } + this._storage.get('card-popup').errors = null; + let payload; try { @@ -2074,10 +2090,11 @@ class BoardStore extends BaseStore { * @private */ async _uploadAttachment(data) { + const cardContext = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + cardContext.errors = ConstantMessages.OfflineMessage; return; } - const cardContext = this._storage.get('card-popup'); cardContext.errors = null; if (data.file.size > BoardStoreConstants.MaxAttachmentSize) { cardContext.errors = ConstantMessages.AttachmentSizeTooBig; @@ -2102,6 +2119,10 @@ class BoardStore extends BaseStore { card.attachments.push(payload.data); return; + case HttpStatusCodes.TooLarge: + cardContext.errors = ConstantMessages.TooLargeMessage; + return; + default: cardContext.errors = ConstantMessages.UnsuccessfulRequest; return; @@ -2114,10 +2135,11 @@ class BoardStore extends BaseStore { * @private */ async _deleteAttachment(data) { + const cardContext = this._storage.get('card-popup'); if (SettingsStore.isOffline()) { + cardContext.errors = ConstantMessages.OfflineMessage; return; } - const cardContext = this._storage.get('card-popup'); let payload; @@ -2152,7 +2174,10 @@ class BoardStore extends BaseStore { const attachment = cardContext.attachments.find((attach) => { return attach.atid === data.atid; }); - window.open(attachment.file_tech_name, `Download: ${attachment.file_pub_name}`); + console.log('attachment.file_tech_name: ' + attachment.file_tech_name); + window.open(ServiceWorker.ATTACHMENT_PREFIX + attachment.file_tech_name + + `?${ServiceWorker.ATTACH_NAME_PARAM}=${attachment.file_pub_name}`, + `Download: ${attachment.file_pub_name}`); } /** @@ -2385,12 +2410,13 @@ class BoardStore extends BaseStore { * @param {Object} data данные c названием тега */ async _createTag(data) { - if (SettingsStore.isOffline()) { - return; - } const contextTagPopUp = this._storage.get('tag-popup'); const contextTagListPopUp = this._storage.get('tags-list-popup'); + if (SettingsStore.isOffline()) { + contextTagPopUp.errors = ConstantMessages.OfflineMessage; + return; + } contextTagPopUp.errors = null; const validator = new Validator(); contextTagPopUp.errors = validator.validateTagTitle(contextTagPopUp.tag_name); @@ -2486,10 +2512,11 @@ class BoardStore extends BaseStore { * Обновляет тег */ async _updateTag() { + const context = this._storage.get('tag-popup'); if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; return; } - const context = this._storage.get('tag-popup'); context.errors = null; const validator = new Validator(); @@ -2541,12 +2568,13 @@ class BoardStore extends BaseStore { * @param {Object} data данные */ async _toggleTag(data) { - if (SettingsStore.isOffline()) { - return; - } const context = this._storage.get('tags-list-popup'); const currentCard = this._getCardById(this._storage.get('card-popup').clid, this._storage.get('card-popup').cid); + if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; + return; + } let payload; diff --git a/src/stores/BoardsStore/BoardsStore.js b/src/stores/BoardsStore/BoardsStore.js index c7b0691..520ab1b 100644 --- a/src/stores/BoardsStore/BoardsStore.js +++ b/src/stores/BoardsStore/BoardsStore.js @@ -184,6 +184,7 @@ class BoardsStore extends BaseStore { */ async _create(data) { if (SettingsStore.isOffline()) { + this._storage.get('create-popup').errors = ConstantMessages.OfflineMessage; return; } const validator = new Validator(); @@ -294,6 +295,10 @@ class BoardsStore extends BaseStore { */ async _refreshTeamMemberSearchList(data) { const context = this._storage.get('add-team-member-popup'); + if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; + return; + } context.errors = null; const {searchString} = data; context.searchString = searchString; @@ -340,6 +345,10 @@ class BoardsStore extends BaseStore { */ async _toggleTeamMemberInSearchList(data) { const context = this._storage.get('add-team-member-popup'); + if (SettingsStore.isOffline()) { + context.errors = ConstantMessages.OfflineMessage; + return; + } context.errors = null; const teams = this._storage.get('teams'); @@ -433,6 +442,7 @@ class BoardsStore extends BaseStore { */ async _submitAddTeamPopUp(data) { if (SettingsStore.isOffline()) { + this._storage.get('team-popup').errors = ConstantMessages.OfflineMessage; return; } const validator = new Validator(); @@ -504,7 +514,10 @@ class BoardsStore extends BaseStore { * @private */ async _submitEditTeamPopUp(data) { - console.log('submit'); + if (SettingsStore.isOffline()) { + this._storage.get('team-popup').errors = ConstantMessages.OfflineMessage; + return; + } const context = this._storage.get('team-popup'); const validator = new Validator(); const validatorStatus = validator.validateTeamTitle(data.team_name); @@ -515,7 +528,6 @@ class BoardsStore extends BaseStore { this._hideTeamPopUp(); let payload; - console.log(context); try { payload = await Network.updateTeam(context.tid, { team_name: data.team_name, @@ -547,6 +559,11 @@ class BoardsStore extends BaseStore { * @private */ async _deleteTeam(data) { + if (SettingsStore.isOffline()) { + this._storage.get('delete-dialog').errors = ConstantMessages.OfflineMessage; + return; + } + this._storage.get('delete-dialog').errors = null; this._hideDeleteTeamPopUp(); if (!data.confirm) { return; @@ -565,6 +582,7 @@ class BoardsStore extends BaseStore { case HttpStatusCodes.Ok: this._storage.get('teams').splice( this._getTeamById(this._storage.get('delete-dialog').tid), 1); + break; default: this._showDeleteTeamPopUp({tid: this._storage.get('delete-dialog').tid}); @@ -583,6 +601,7 @@ class BoardsStore extends BaseStore { visible: true, tid: data.tid, name: this._getTeamById(data.tid).team_name, + errors: null, }); } diff --git a/src/stores/SettingsStore/SettingsStore.js b/src/stores/SettingsStore/SettingsStore.js index d8ba075..bd65389 100644 --- a/src/stores/SettingsStore/SettingsStore.js +++ b/src/stores/SettingsStore/SettingsStore.js @@ -132,6 +132,7 @@ class SettingsStore extends BaseStore { * @param {Object} data данные запроса. */ async _get(data) { + this._storage.set('errors', null); if (!data.userName) { return; } @@ -168,8 +169,10 @@ class SettingsStore extends BaseStore { */ async _put(data) { if (this.isOffline()) { + this._storage.set('errors', ConstantMessages.OfflineMessage); return; } + this._storage.set('errors', null); const formdata = data; this._storage.set('login', data.login); @@ -236,8 +239,10 @@ class SettingsStore extends BaseStore { */ async _uploadAvatar(data) { if (this.isOffline()) { + this._storage.set('errors', ConstantMessages.OfflineMessage); return; } + this._storage.set('errors', null); const validator = new Validator(); if (data.avatar instanceof File) { diff --git a/src/stores/UserStore/UserStore.js b/src/stores/UserStore/UserStore.js index 8f7393d..aced2e3 100644 --- a/src/stores/UserStore/UserStore.js +++ b/src/stores/UserStore/UserStore.js @@ -79,6 +79,7 @@ class UserStore extends BaseStore { * Метод, реализующий реакцию на инициализацию. */ async _fetchUser() { + this._storage.set('errors', null); let response; try { @@ -112,8 +113,10 @@ class UserStore extends BaseStore { */ async _register(data) { if (SettingsStore.isOffline()) { + this._storage.set('errors', ConstantMessages.OfflineMessage); return; } + this._storage.set('errors', null); this._storage.set('userRegisterData', data); this._validate(data, 'userRegisterData'); @@ -160,6 +163,11 @@ class UserStore extends BaseStore { * @param {Object} data данные для входа */ async _login(data) { + if (SettingsStore.isOffline()) { + this._storage.set('errors', ConstantMessages.OfflineMessage); + return; + } + this._storage.set('errors', null); this._storage.set('userLoginData', data); this._validate(data, 'userLoginData'); @@ -207,8 +215,10 @@ class UserStore extends BaseStore { */ async _logout() { if (SettingsStore.isOffline()) { + this._storage.set('errors', ConstantMessages.OfflineMessage); return; } + this._storage.set('errors', null); let response; try { diff --git a/src/sw.js b/src/sw.js index 02df156..60a3be3 100644 --- a/src/sw.js +++ b/src/sw.js @@ -26,9 +26,14 @@ self.addEventListener('fetch', (event) => { const url = new URL(request.url); if (url.pathname.startsWith('/api')) { // Запрос на API - event.respondWith(networkFirst(request, event.clientId)); - } else if (event.request.mode === 'navigate') { // Переход по URL в адресной строке - event.respondWith(cacheFirst(ServiceWorker.CacheUrls.HTML_URL)); + event.respondWith(networkFirst(request, event.clientId, ServiceWorker.API_CACHE_NAME)); + } else if (request.mode === 'navigate') { // Переход по URL в адресной строке + if (url.pathname.startsWith(ServiceWorker.ATTACHMENT_PREFIX)) { + event.respondWith(fetchAttachment(request)); + return; + } + /* Всегда пытаемся получить свежую страницу с новыми бандлами */ + event.respondWith(networkFirst(request, event.clientId, ServiceWorker.STATIC_CACHE_NAME)); } else { // Запрос за статикой event.respondWith(cacheFirst(request)); } @@ -60,24 +65,28 @@ async function cacheFirst(request) { * NetworkFirst - кэширование запросов на API * @param {Request | String} request объект запроса или URL строка * @param {Number} clientId id клиента + * @param {String} cacheName имя кэша * @return {Promise} */ -async function networkFirst(request, clientId) { +async function networkFirst(request, clientId, cacheName) { if (request.method !== 'GET') { try { return await fetch(request); } catch (error) { + await sendMessage(clientId, + ServiceWorker.Messages.OFFLINE_NO_CACHE, + request?.url); return undefined; } } - const cache = await caches.open(ServiceWorker.API_CACHE_NAME); + const cache = await caches.open(cacheName); try { const response = await fetch(request); const responseCopy = response.clone(); await sendMessage(clientId, ServiceWorker.Messages.ONLINE, - request.url); + request?.url); /* Добавим служебный заголовок, позволяющий определить что запрос был кэширован в SW*/ const headers = new Headers(responseCopy.headers); @@ -97,16 +106,49 @@ async function networkFirst(request, clientId) { if (!cachedResponse) { await sendMessage(clientId, ServiceWorker.Messages.OFFLINE_NO_CACHE, - request.url); + request?.url); return undefined; } await sendMessage(clientId, ServiceWorker.Messages.OFFLINE_FROM_CACHE, - request.url); + request?.url); return cachedResponse; } } +/** + * Извлекает аттач, заменяет URL при запросе, добавляет хедер Content-Disposition в ответе + * @param {Request} request - request + * @return {Promise} + */ +async function fetchAttachment(request) { + const url = new URL(request.url); + url.pathname = url.pathname.replace(ServiceWorker.ATTACHMENT_PREFIX, ''); + const fileName = url.searchParams.get(ServiceWorker.ATTACH_NAME_PARAM); + url.searchParams.delete(ServiceWorker.ATTACH_NAME_PARAM); + try { + console.log('url to fetch attach: ' + url.toString()); + const response = await fetch(url.toString()); + + /* Добавим служебный заголовок, указывающий что контент нужно скачать */ + const headers = new Headers(response.headers); + headers.set('Content-Disposition', `attachment; filename="${fileName}"`); + + const responseBytes = await response.blob(); + const responseCopy = new Response(responseBytes, { + status: response.status, + statusText: response.statusText, + headers: headers, + }); + + console.log('возвращаю attchment'); + + return responseCopy; + } catch (error) { + console.log('не удалость загрузить вложение: ' + url + ' ' + error); + } +} + /** * Отправляет сообщение в приложение * @param {Number} clientId id клиента diff --git a/src/views/LoginView/LoginView.hbs b/src/views/LoginView/LoginView.hbs index 026313a..1d13038 100644 --- a/src/views/LoginView/LoginView.hbs +++ b/src/views/LoginView/LoginView.hbs @@ -25,6 +25,9 @@ {{#if validation.userLoginData.password}}
{{validation.userLoginData.password}}
{{/if}} + {{#if errors}} +
{{errors}}
+ {{/if}} diff --git a/src/views/RegisterView/RegisterView.hbs b/src/views/RegisterView/RegisterView.hbs index 2772b30..4562dd9 100644 --- a/src/views/RegisterView/RegisterView.hbs +++ b/src/views/RegisterView/RegisterView.hbs @@ -43,7 +43,9 @@ {{/if}} {{!--

Создавая учетную запись, вы соглашаетесь с нашими
Условиями пользования и
Политикой конфиденциальности
.

--}} - + {{#if errors}} +
{{errors}}
+ {{/if}} diff --git a/webpack.config.js b/webpack.config.js index 658ad33..1b9a3a4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,6 +6,7 @@ const {InjectManifest} = require('workbox-webpack-plugin'); const {CleanWebpackPlugin} = require('clean-webpack-plugin'); const {DefinePlugin} = require('webpack'); const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); const packageJSON = require('./package.json'); const crypto = require('crypto'); @@ -143,4 +144,8 @@ const config = { devServer: confConst.DEBUG ? devServer : devServer, }; +if (!confConst.DEBUG) { + config.optimization.minimizer.push(new TerserPlugin()); +} + module.exports = config;