WebP new converter
This commit is contained in:
parent
617acdbb13
commit
c33748eb5c
23
package-lock.json
generated
23
package-lock.json
generated
@ -3171,6 +3171,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.4.tgz",
|
||||||
"integrity": "sha512-k3NqigXWRzQZVBDS5D1U70A5E8Qk4Kh+Ha/x4M8Bt9pF0X05eggfnC9+63Usc9Q928hRUIpIhTQaXsZwZBl4Ew=="
|
"integrity": "sha512-k3NqigXWRzQZVBDS5D1U70A5E8Qk4Kh+Ha/x4M8Bt9pF0X05eggfnC9+63Usc9Q928hRUIpIhTQaXsZwZBl4Ew=="
|
||||||
},
|
},
|
||||||
|
"@types/pako": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-GdZbRSJ3Cv5fiwT6I0SQ3ckeN2PWNqxd26W9Z2fCK1tGrrasGy4puvNFtnddqH9UJFMQYXxEuuB7B8UK+LLwSg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/puppeteer": {
|
"@types/puppeteer": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-3.0.1.tgz",
|
||||||
@ -6444,6 +6450,17 @@
|
|||||||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"fast-png": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-png/-/fast-png-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-75j60BAZP5R3eTHslW5o8apfuAtxRONfY3gGt3yQlsm46Xz+uRCjguBFFr5SMNGPJ7MjYFBsE1dlwPLnTA4t6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/pako": "^1.0.1",
|
||||||
|
"iobuffer": "^5.0.2",
|
||||||
|
"pako": "^1.0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fastdom": {
|
"fastdom": {
|
||||||
"version": "1.0.9",
|
"version": "1.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.9.tgz",
|
||||||
@ -8082,6 +8099,12 @@
|
|||||||
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
|
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"iobuffer": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-FwwzAUZkapfHq76amLGSaEigB2nRSZR+ADc+zRcIRm2MsofDJAiIEPGbw+is/lI+kW32fM5jezmJ8dVQnd1UbA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ip": {
|
"ip": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
"compression-webpack-plugin": "^3.1.0",
|
"compression-webpack-plugin": "^3.1.0",
|
||||||
"css-loader": "^3.5.3",
|
"css-loader": "^3.5.3",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"fast-png": "^5.0.2",
|
||||||
"fastdom": "^1.0.9",
|
"fastdom": "^1.0.9",
|
||||||
"file-loader": "^4.3.0",
|
"file-loader": "^4.3.0",
|
||||||
"handlebars": "^4.7.6",
|
"handlebars": "^4.7.6",
|
||||||
|
@ -15,6 +15,6 @@ app.get('/', (req, res) => {
|
|||||||
https.createServer({
|
https.createServer({
|
||||||
key: fs.readFileSync(__dirname + '/certs/server-key.pem'),
|
key: fs.readFileSync(__dirname + '/certs/server-key.pem'),
|
||||||
cert: fs.readFileSync(__dirname + '/certs/server-cert.pem')
|
cert: fs.readFileSync(__dirname + '/certs/server-cert.pem')
|
||||||
}, app).listen(9001, () => {
|
}, app).listen(443/* 9001 */, () => {
|
||||||
console.log('Listening...');
|
console.log('Listening...');
|
||||||
});
|
});
|
@ -1,5 +1,5 @@
|
|||||||
import { logger, LogLevels } from "../lib/logger";
|
import { logger, LogLevels } from "../lib/logger";
|
||||||
import smoothscroll from '../lib/smoothscroll';
|
import smoothscroll from '../vendor/smoothscroll';
|
||||||
import { touchSupport, isSafari } from "../lib/config";
|
import { touchSupport, isSafari } from "../lib/config";
|
||||||
//import { isInDOM } from "../lib/utils";
|
//import { isInDOM } from "../lib/utils";
|
||||||
(window as any).__forceSmoothScrollPolyfill__ = true;
|
(window as any).__forceSmoothScrollPolyfill__ = true;
|
||||||
|
@ -9,17 +9,16 @@ import ProgressivePreloaderNew from './preloader_new';
|
|||||||
import LazyLoadQueue from './lazyLoadQueue';
|
import LazyLoadQueue from './lazyLoadQueue';
|
||||||
import VideoPlayer from '../lib/mediaPlayer';
|
import VideoPlayer from '../lib/mediaPlayer';
|
||||||
import { RichTextProcessor } from '../lib/richtextprocessor';
|
import { RichTextProcessor } from '../lib/richtextprocessor';
|
||||||
import { CancellablePromise } from '../lib/polyfill';
|
|
||||||
import { renderImageFromUrl } from './misc';
|
import { renderImageFromUrl } from './misc';
|
||||||
import appMessagesManager from '../lib/appManagers/appMessagesManager';
|
import appMessagesManager from '../lib/appManagers/appMessagesManager';
|
||||||
import { Layouter, RectPart } from './groupedLayout';
|
import { Layouter, RectPart } from './groupedLayout';
|
||||||
import PollElement from './poll';
|
import PollElement from './poll';
|
||||||
import appWebpManager from '../lib/appManagers/appWebpManager';
|
import { mediaSizes, isSafari } from '../lib/config';
|
||||||
import { mediaSizes } from '../lib/config';
|
|
||||||
import { MTDocument, MTPhotoSize } from '../types';
|
import { MTDocument, MTPhotoSize } from '../types';
|
||||||
import animationIntersector from './animationIntersector';
|
import animationIntersector from './animationIntersector';
|
||||||
import AudioElement from './audio';
|
import AudioElement from './audio';
|
||||||
import { Download } from '../lib/appManagers/appDownloadManager';
|
import { Download } from '../lib/appManagers/appDownloadManager';
|
||||||
|
import { webpWorkerController } from '../lib/webp/webpWorkerController';
|
||||||
|
|
||||||
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue}: {
|
export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue}: {
|
||||||
doc: MTDocument,
|
doc: MTDocument,
|
||||||
@ -420,12 +419,12 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
|
|||||||
if(thumb.bytes) {
|
if(thumb.bytes) {
|
||||||
let img = new Image();
|
let img = new Image();
|
||||||
|
|
||||||
if((appWebpManager.isSupported() || doc.stickerThumbConverted)/* && false */) {
|
if((!isSafari || doc.stickerThumbConverted)/* && false */) {
|
||||||
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true));
|
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true));
|
||||||
|
|
||||||
div.append(img);
|
div.append(img);
|
||||||
} else {
|
} else {
|
||||||
appWebpManager.convertToPng(thumb.bytes).then(bytes => {
|
webpWorkerController.convert(doc.id, thumb.bytes).then(bytes => {
|
||||||
if(middleware && !middleware()) return;
|
if(middleware && !middleware()) return;
|
||||||
|
|
||||||
thumb.bytes = bytes;
|
thumb.bytes = bytes;
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
MTProto.apiManager.invokeApi('messages.getPeerDialogs', {
|
|
||||||
peers: [
|
|
||||||
{
|
|
||||||
_: 'inputDialogPeer',
|
|
||||||
peer: {_: 'inputPeerUser', user_id: 296814355, access_hash: '7461657386624868366'}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}).then(dialogs => console.log(dialogs));
|
|
||||||
|
|
||||||
MTProto.apiManager.invokeApi('messages.getPinnedDialogs', {
|
|
||||||
folder_id: 0
|
|
||||||
}).then(dialogs => console.log(dialogs));
|
|
||||||
|
|
||||||
// read_outbox_max_id && read_inbox_max_id are 0!
|
|
||||||
MTProto.apiManager.invokeApi('messages.getDialogs', {
|
|
||||||
flags: 0 | 1,
|
|
||||||
exclude_pinned: true,
|
|
||||||
folder_id: 0,
|
|
||||||
offset_date: 0,
|
|
||||||
offset_id: 0,
|
|
||||||
offset_peer: {_: 'inputPeerEmpty'},
|
|
||||||
limit: 6,
|
|
||||||
hash: Date.now() * 5
|
|
||||||
}).then(dialogs => console.log(dialogs));
|
|
||||||
|
|
||||||
// [109, 188, 177, 157, 19, 7, 177, 17, 49, 155, 9, 0, 44, 155, 9, 0, 237, 154, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 157, 80, 175] - works
|
|
||||||
// [109, 188, 177, 157, 19, 7, 177, 17, 49, 155, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 157, 80, 175] - pinned
|
|
||||||
|
|
7
src/global.d.ts
vendored
Normal file
7
src/global.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
declare module 'worker-loader!*' {
|
||||||
|
class WebpackWorker extends Worker {
|
||||||
|
constructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WebpackWorker;
|
||||||
|
}
|
15
src/helpers/userAgent.ts
Normal file
15
src/helpers/userAgent.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export const userAgent = navigator ? navigator.userAgent : null;
|
||||||
|
export const isApple = navigator.userAgent.search(/OS X|iPhone|iPad|iOS/i) != -1;
|
||||||
|
export const isAndroid = navigator.userAgent.toLowerCase().indexOf('android') != -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true when run in WebKit derived browsers.
|
||||||
|
* This is used as a workaround for a memory leak in Safari caused by using Transferable objects to
|
||||||
|
* transfer data between WebWorkers and the main thread.
|
||||||
|
* https://github.com/mapbox/mapbox-gl-js/issues/8771
|
||||||
|
*
|
||||||
|
* This should be removed once the underlying Safari issue is fixed.
|
||||||
|
*/
|
||||||
|
const ctx = typeof(window) !== 'undefined' ? window : self;
|
||||||
|
|
||||||
|
export const isSafari = !!('safari' in ctx) || !!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || (!!userAgent.match('Safari') && !userAgent.match('Chrome'))));
|
@ -1,103 +0,0 @@
|
|||||||
class AppWebpManager {
|
|
||||||
private webpMachine: any = null;
|
|
||||||
private loaded: Promise<void>;
|
|
||||||
private busyPromise: Promise<Uint8Array | void>;
|
|
||||||
private queue: {bytes: Uint8Array, callback: (res: Uint8Array) => void}[] = [];
|
|
||||||
|
|
||||||
private testPromise: Promise<boolean> = null;
|
|
||||||
public webpSupport = false;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.testWebpSupport();
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadWebpHero() {
|
|
||||||
if(this.loaded) return this.loaded;
|
|
||||||
|
|
||||||
this.loaded = new Promise(async(resolve, reject) => {
|
|
||||||
let res = await this.testWebpSupport();
|
|
||||||
|
|
||||||
if(!res) {
|
|
||||||
(window as any).webpLoaded = () => {
|
|
||||||
//console.log('webpHero loaded');
|
|
||||||
this.webpMachine = new (window as any).WebpMachine();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
|
|
||||||
let sc = document.createElement('script');
|
|
||||||
sc.src = 'npm.webp-hero.chunk.js';
|
|
||||||
sc.async = true;
|
|
||||||
sc.onload = (window as any).webpLoaded;
|
|
||||||
|
|
||||||
document.body.appendChild(sc);
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private convert(bytes: Uint8Array): AppWebpManager['busyPromise'] {
|
|
||||||
return this.webpMachine.decode(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async processQueue() {
|
|
||||||
if(this.busyPromise) return;
|
|
||||||
|
|
||||||
this.busyPromise = Promise.resolve();
|
|
||||||
|
|
||||||
let {bytes, callback} = this.queue.pop();
|
|
||||||
|
|
||||||
if(!this.loaded) {
|
|
||||||
this.loadWebpHero();
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.loaded;
|
|
||||||
|
|
||||||
this.busyPromise = this.convert(bytes);
|
|
||||||
let res = await this.busyPromise;
|
|
||||||
|
|
||||||
//console.log('converted webp', res);
|
|
||||||
|
|
||||||
callback(res as Uint8Array);
|
|
||||||
|
|
||||||
this.busyPromise = null;
|
|
||||||
|
|
||||||
if(this.queue.length) {
|
|
||||||
this.processQueue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public testWebpSupport() {
|
|
||||||
if(this.testPromise) return this.testPromise;
|
|
||||||
|
|
||||||
return this.testPromise = new Promise((resolve, reject) => {
|
|
||||||
return resolve(this.webpSupport = true);
|
|
||||||
let webP = new Image();
|
|
||||||
webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
|
|
||||||
'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
|
|
||||||
webP.onload = webP.onerror = () => {
|
|
||||||
resolve(this.webpSupport = webP.height === 2/* && false */);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public isSupported() {
|
|
||||||
return this.webpSupport;
|
|
||||||
}
|
|
||||||
|
|
||||||
public convertToPng(bytes: Uint8Array) {
|
|
||||||
//console.warn('convertToPng!');
|
|
||||||
return new Promise<Uint8Array>((resolve, reject) => {
|
|
||||||
// @ts-ignore
|
|
||||||
this.queue.push({bytes, callback: resolve});
|
|
||||||
this.processQueue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const appWebpManager = new AppWebpManager();
|
|
||||||
/* // @ts-ignore
|
|
||||||
if(process.env.NODE_ENV != 'production') {
|
|
||||||
(window as any).appWebpManager = appWebpManager;
|
|
||||||
} */
|
|
||||||
export default appWebpManager;
|
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
import {blobConstruct} from './bin_utils';
|
import {blobConstruct} from './bin_utils';
|
||||||
|
|
||||||
class FileManager {
|
export class FileManager {
|
||||||
public blobSupported = true;
|
public blobSupported = true;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -14,22 +14,6 @@ class FileManager {
|
|||||||
public isAvailable() {
|
public isAvailable() {
|
||||||
return this.blobSupported;
|
return this.blobSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
public copy(fromFileEntry: any, toFileEntry: any) {
|
|
||||||
return this.write(toFileEntry, fromFileEntry).then(() => {
|
|
||||||
console.log('copy success');
|
|
||||||
return toFileEntry;
|
|
||||||
}, (error: any) => {
|
|
||||||
console.error('copy error 1:', error);
|
|
||||||
try {
|
|
||||||
toFileEntry.truncate(0);
|
|
||||||
} catch(e) {
|
|
||||||
console.error('copy error', e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public write(fileWriter: ReturnType<FileManager['getFakeFileWriter']>, bytes: Uint8Array | Blob | {file: any}): Promise<void> {
|
public write(fileWriter: ReturnType<FileManager['getFakeFileWriter']>, bytes: Uint8Array | Blob | {file: any}): Promise<void> {
|
||||||
if('file' in bytes) {
|
if('file' in bytes) {
|
||||||
|
@ -4,9 +4,9 @@ import cacheStorage from "../cacheStorage";
|
|||||||
import FileManager from "../filemanager";
|
import FileManager from "../filemanager";
|
||||||
import apiManager from "./apiManager";
|
import apiManager from "./apiManager";
|
||||||
import { deferredPromise, CancellablePromise } from "../polyfill";
|
import { deferredPromise, CancellablePromise } from "../polyfill";
|
||||||
import appWebpManager from "../appManagers/appWebpManager";
|
|
||||||
import { logger } from "../logger";
|
import { logger } from "../logger";
|
||||||
import { InputFileLocation, FileLocation, UploadFile } from "../../types";
|
import { InputFileLocation, FileLocation, UploadFile } from "../../types";
|
||||||
|
import { isSafari } from "../../helpers/userAgent";
|
||||||
|
|
||||||
type Delayed = {
|
type Delayed = {
|
||||||
offset: number,
|
offset: number,
|
||||||
@ -21,7 +21,6 @@ export type DownloadOptions = {
|
|||||||
fileName?: string,
|
fileName?: string,
|
||||||
mimeType?: string,
|
mimeType?: string,
|
||||||
limitPart?: number,
|
limitPart?: number,
|
||||||
stickerType?: number,
|
|
||||||
processPart?: (bytes: Uint8Array, offset?: number, queue?: Delayed[]) => Promise<any>
|
processPart?: (bytes: Uint8Array, offset?: number, queue?: Delayed[]) => Promise<any>
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,6 +41,8 @@ export class ApiFileManager {
|
|||||||
} = {};
|
} = {};
|
||||||
public downloadActives: {[dcID: string]: number} = {};
|
public downloadActives: {[dcID: string]: number} = {};
|
||||||
|
|
||||||
|
public webpConvertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};
|
||||||
|
|
||||||
private log: ReturnType<typeof logger> = logger('AFM');
|
private log: ReturnType<typeof logger> = logger('AFM');
|
||||||
|
|
||||||
public downloadRequest(dcID: 'upload', cb: () => Promise<void>, activeDelta: number): Promise<void>;
|
public downloadRequest(dcID: 'upload', cb: () => Promise<void>, activeDelta: number): Promise<void>;
|
||||||
@ -151,14 +152,10 @@ export class ApiFileManager {
|
|||||||
let size = options.size ?? 0;
|
let size = options.size ?? 0;
|
||||||
let {dcID, location} = options;
|
let {dcID, location} = options;
|
||||||
|
|
||||||
let processSticker = false;
|
let processWebp = false;
|
||||||
if(options.stickerType == 1 && !appWebpManager.isSupported()) {
|
if(options.mimeType == 'image/webp' && isSafari) {
|
||||||
if(size > 524288) {
|
processWebp = true;
|
||||||
delete options.stickerType;
|
options.mimeType = 'image/png';
|
||||||
} else {
|
|
||||||
processSticker = true;
|
|
||||||
options.mimeType = 'image/png';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.log('Dload file', dcID, location, size)
|
// this.log('Dload file', dcID, location, size)
|
||||||
@ -172,7 +169,7 @@ export class ApiFileManager {
|
|||||||
if(options.processPart) {
|
if(options.processPart) {
|
||||||
return cachedPromise.then((blob) => {
|
return cachedPromise.then((blob) => {
|
||||||
return this.convertBlobToBytes(blob).then(bytes => {
|
return this.convertBlobToBytes(blob).then(bytes => {
|
||||||
options.processPart(bytes)
|
options.processPart(bytes);
|
||||||
return blob;
|
return blob;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -204,13 +201,13 @@ export class ApiFileManager {
|
|||||||
|
|
||||||
let canceled = false;
|
let canceled = false;
|
||||||
let resolved = false;
|
let resolved = false;
|
||||||
let cacheFileWriter: any;
|
let cacheFileWriter: ReturnType<typeof FileManager['getFakeFileWriter']>;
|
||||||
let errorHandler = (error: any) => {
|
let errorHandler = (error: any) => {
|
||||||
deferred.reject(error);
|
deferred.reject(error);
|
||||||
errorHandler = () => {};
|
errorHandler = () => {};
|
||||||
|
|
||||||
if(cacheFileWriter && (!error || error.type != 'DOWNLOAD_CANCELED')) {
|
if(cacheFileWriter && (!error || error.type != 'DOWNLOAD_CANCELED')) {
|
||||||
cacheFileWriter.truncate(0);
|
cacheFileWriter.truncate();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -269,8 +266,22 @@ export class ApiFileManager {
|
|||||||
await options.processPart(bytes, offset, delayed);
|
await options.processPart(bytes, offset, delayed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(processSticker) {
|
if(processWebp) {
|
||||||
return appWebpManager.convertToPng(bytes);
|
const convertPromise = deferredPromise<Uint8Array>();
|
||||||
|
|
||||||
|
(self as any as ServiceWorkerGlobalScope)
|
||||||
|
.clients
|
||||||
|
.matchAll({includeUncontrolled: false, type: 'window'})
|
||||||
|
.then((listeners) => {
|
||||||
|
if(!listeners.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners[0].postMessage({type: 'convertWebp', payload: {fileName, bytes}});
|
||||||
|
});
|
||||||
|
|
||||||
|
return await (this.webpConvertPromises[fileName] = convertPromise);
|
||||||
|
//return appWebpManager.convertToPng(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
|
@ -9,6 +9,7 @@ import networkerFactory from "./networkerFactory";
|
|||||||
import apiFileManager, { DownloadOptions } from './apiFileManager';
|
import apiFileManager, { DownloadOptions } from './apiFileManager';
|
||||||
import { getFileNameByLocation } from '../bin_utils';
|
import { getFileNameByLocation } from '../bin_utils';
|
||||||
import { logger, LogLevels } from '../logger';
|
import { logger, LogLevels } from '../logger';
|
||||||
|
import { isSafari } from '../../helpers/userAgent';
|
||||||
|
|
||||||
const log = logger('SW'/* , LogLevels.error */);
|
const log = logger('SW'/* , LogLevels.error */);
|
||||||
|
|
||||||
@ -16,34 +17,11 @@ const ctx = self as any as ServiceWorkerGlobalScope;
|
|||||||
|
|
||||||
//console.error('INCLUDE !!!', new Error().stack);
|
//console.error('INCLUDE !!!', new Error().stack);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true when run in WebKit derived browsers.
|
|
||||||
* This is used as a workaround for a memory leak in Safari caused by using Transferable objects to
|
|
||||||
* transfer data between WebWorkers and the main thread.
|
|
||||||
* https://github.com/mapbox/mapbox-gl-js/issues/8771
|
|
||||||
*
|
|
||||||
* This should be removed once the underlying Safari issue is fixed.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param scope {WindowOrWorkerGlobalScope} Since this function is used both on the main thread and WebWorker context,
|
|
||||||
* let the calling scope pass in the global scope object.
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
var _isSafari: boolean = null;
|
|
||||||
function isSafari(scope: any) {
|
|
||||||
if(_isSafari == null) {
|
|
||||||
var userAgent = scope.navigator ? scope.navigator.userAgent : null;
|
|
||||||
_isSafari = !!scope.safari ||
|
|
||||||
!!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || (!!userAgent.match('Safari') && !userAgent.match('Chrome'))));
|
|
||||||
}
|
|
||||||
return _isSafari;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isObject(object: any) {
|
function isObject(object: any) {
|
||||||
return typeof(object) === 'object' && object !== null;
|
return typeof(object) === 'object' && object !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillTransfer(transfer: any, obj: any) {
|
/* function fillTransfer(transfer: any, obj: any) {
|
||||||
if(!obj) return;
|
if(!obj) return;
|
||||||
|
|
||||||
if(obj instanceof ArrayBuffer) {
|
if(obj instanceof ArrayBuffer) {
|
||||||
@ -59,7 +37,7 @@ function fillTransfer(transfer: any, obj: any) {
|
|||||||
fillTransfer(transfer, value);
|
fillTransfer(transfer, value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Respond to request
|
* Respond to request
|
||||||
@ -83,7 +61,7 @@ function respond(client: Client | ServiceWorker | MessagePort, ...args: any[]) {
|
|||||||
* Broadcast Notification
|
* Broadcast Notification
|
||||||
*/
|
*/
|
||||||
function notify(...args: any[]) {
|
function notify(...args: any[]) {
|
||||||
ctx.clients.matchAll({ includeUncontrolled: false, type: 'window' }).then((listeners) => {
|
ctx.clients.matchAll({includeUncontrolled: false, type: 'window'}).then((listeners) => {
|
||||||
if(!listeners.length) {
|
if(!listeners.length) {
|
||||||
//console.trace('no listeners?', self, listeners);
|
//console.trace('no listeners?', self, listeners);
|
||||||
return;
|
return;
|
||||||
@ -108,6 +86,13 @@ ctx.addEventListener('message', async(e) => {
|
|||||||
if(e.data.useLs) {
|
if(e.data.useLs) {
|
||||||
AppStorage.finishTask(e.data.taskID, e.data.args);
|
AppStorage.finishTask(e.data.taskID, e.data.args);
|
||||||
return;
|
return;
|
||||||
|
} else if(e.data.type == 'convertWebp') {
|
||||||
|
const {fileName, bytes} = e.data.payload;
|
||||||
|
const deferred = apiFileManager.webpConvertPromises[fileName];
|
||||||
|
if(deferred) {
|
||||||
|
deferred.resolve(bytes);
|
||||||
|
delete apiFileManager.webpConvertPromises[fileName];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(e.data.task) {
|
switch(e.data.task) {
|
||||||
@ -288,7 +273,7 @@ ctx.addEventListener('fetch', (event: FetchEvent): void => {
|
|||||||
|
|
||||||
if(info.mimeType) headers['Content-Type'] = info.mimeType;
|
if(info.mimeType) headers['Content-Type'] = info.mimeType;
|
||||||
|
|
||||||
if(isSafari(ctx)) {
|
if(isSafari) {
|
||||||
ab = ab.slice(offset - alignedOffset, end - alignedOffset + 1);
|
ab = ab.slice(offset - alignedOffset, end - alignedOffset + 1);
|
||||||
headers['Content-Range'] = `bytes ${offset}-${offset + ab.byteLength - 1}/${info.size || '*'}`;
|
headers['Content-Range'] = `bytes ${offset}-${offset + ab.byteLength - 1}/${info.size || '*'}`;
|
||||||
headers['Content-Length'] = `${ab.byteLength}`;
|
headers['Content-Length'] = `${ab.byteLength}`;
|
||||||
|
@ -2,8 +2,8 @@ import {isObject, $rootScope} from '../utils';
|
|||||||
import AppStorage from '../storage';
|
import AppStorage from '../storage';
|
||||||
import CryptoWorkerMethods from '../crypto/crypto_methods';
|
import CryptoWorkerMethods from '../crypto/crypto_methods';
|
||||||
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
||||||
import { InputFileLocation, FileLocation } from '../../types';
|
|
||||||
import { logger } from '../logger';
|
import { logger } from '../logger';
|
||||||
|
import { webpWorkerController } from '../webp/webpWorkerController';
|
||||||
|
|
||||||
type Task = {
|
type Task = {
|
||||||
taskID: number,
|
taskID: number,
|
||||||
@ -74,6 +74,8 @@ class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
}
|
}
|
||||||
} else if(e.data.progress) {
|
} else if(e.data.progress) {
|
||||||
$rootScope.$broadcast('download_progress', e.data.progress);
|
$rootScope.$broadcast('download_progress', e.data.progress);
|
||||||
|
} else if(e.data.type == 'convertWebp') {
|
||||||
|
webpWorkerController.postMessage(e.data);
|
||||||
} else {
|
} else {
|
||||||
this.finalizeTask(e.data.taskID, e.data.result, e.data.error);
|
this.finalizeTask(e.data.taskID, e.data.result, e.data.error);
|
||||||
}
|
}
|
||||||
@ -162,15 +164,6 @@ class ApiManagerProxy extends CryptoWorkerMethods {
|
|||||||
return this.performTaskWorker('logOut');
|
return this.performTaskWorker('logOut');
|
||||||
}
|
}
|
||||||
|
|
||||||
public downloadFile(dcID: number, location: InputFileLocation | FileLocation, size: number = 0, options: Partial<{
|
|
||||||
mimeType: string,
|
|
||||||
toFileEntry: any,
|
|
||||||
limitPart: number,
|
|
||||||
stickerType: number
|
|
||||||
}> = {}): Promise<Blob> {
|
|
||||||
return this.performTaskWorker('downloadFile', dcID, location, size, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public cancelDownload(fileName: string) {
|
public cancelDownload(fileName: string) {
|
||||||
return this.performTaskWorker('cancelDownload', fileName);
|
return this.performTaskWorker('cancelDownload', fileName);
|
||||||
}
|
}
|
||||||
|
@ -136,15 +136,15 @@ class ConfigStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const configStorage = new ConfigStorage();
|
|
||||||
|
|
||||||
class AppStorage {
|
class AppStorage {
|
||||||
private isWebWorker: boolean;
|
private isWorker: boolean;
|
||||||
private taskID = 0;
|
private taskID = 0;
|
||||||
private tasks: {[taskID: number]: (result: any) => void} = {};
|
private tasks: {[taskID: number]: (result: any) => void} = {};
|
||||||
//private log = (...args: any[]) => console.log('[SW LS]', ...args);
|
//private log = (...args: any[]) => console.log('[SW LS]', ...args);
|
||||||
private log = (...args: any[]) => {};
|
private log = (...args: any[]) => {};
|
||||||
|
|
||||||
|
private configStorage: ConfigStorage;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
if(Modes.test) {
|
if(Modes.test) {
|
||||||
this.setPrefix('t_');
|
this.setPrefix('t_');
|
||||||
@ -152,15 +152,23 @@ class AppStorage {
|
|||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
//this.isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
|
//this.isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
|
||||||
this.isWebWorker = typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope;
|
this.isWorker = typeof ServiceWorkerGlobalScope !== 'undefined' && self instanceof ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
|
if(!this.isWorker) {
|
||||||
|
this.configStorage = new ConfigStorage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setPrefix(newPrefix: string) {
|
public setPrefix(newPrefix: string) {
|
||||||
configStorage.keyPrefix = newPrefix;
|
if(this.configStorage) {
|
||||||
|
this.configStorage.keyPrefix = newPrefix;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public noPrefix() {
|
public noPrefix() {
|
||||||
configStorage.noPrefix = true;
|
if(this.configStorage) {
|
||||||
|
this.configStorage.noPrefix = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public finishTask(taskID: number, result: any) {
|
public finishTask(taskID: number, result: any) {
|
||||||
@ -175,9 +183,9 @@ class AppStorage {
|
|||||||
delete this.tasks[taskID];
|
delete this.tasks[taskID];
|
||||||
}
|
}
|
||||||
|
|
||||||
private proxy<T>(methodName: string, ..._args: any[]) {
|
private proxy<T>(methodName: 'set' | 'get' | 'remove' | 'clear', ..._args: any[]) {
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
if(this.isWebWorker) {
|
if(this.isWorker) {
|
||||||
const taskID = this.taskID++;
|
const taskID = this.taskID++;
|
||||||
|
|
||||||
this.tasks[taskID] = resolve;
|
this.tasks[taskID] = resolve;
|
||||||
@ -203,8 +211,7 @@ class AppStorage {
|
|||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
// @ts-ignore
|
this.configStorage[methodName].apply(this.configStorage, args as any);
|
||||||
configStorage[methodName].apply(configStorage, args);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
import {Webp} from "webp-hero/libwebp/dist/webp.js"
|
|
||||||
|
|
||||||
const relax = () => new Promise(resolve => requestAnimationFrame(resolve));
|
|
||||||
|
|
||||||
export class WebpMachineError extends Error {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Webp Machine
|
|
||||||
* - decode and polyfill webp images
|
|
||||||
* - can only decode images one-at-a-time (otherwise will throw busy error)
|
|
||||||
*/
|
|
||||||
export class WebpMachine {
|
|
||||||
private readonly webp: Webp;
|
|
||||||
private busy = false;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.webp = new Webp();
|
|
||||||
this.webp.Module.doNotCaptureKeyboard = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode raw webp data into a png data url
|
|
||||||
*/
|
|
||||||
decode(webpData: Uint8Array): Promise<Uint8Array> {
|
|
||||||
if(this.busy) throw new WebpMachineError("cannot decode when already busy");
|
|
||||||
this.busy = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
return relax().then(() => {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
this.webp.setCanvas(canvas);
|
|
||||||
this.webp.webpToSdl(webpData, webpData.length);
|
|
||||||
this.busy = false;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
canvas.toBlob(blob => {
|
|
||||||
let reader = new FileReader();
|
|
||||||
reader.onload = (event) => {
|
|
||||||
resolve(new Uint8Array(event.target.result as ArrayBuffer));
|
|
||||||
};
|
|
||||||
reader.onerror = reject;
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
}, 'image/png', 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch(error) {
|
|
||||||
this.busy = false;
|
|
||||||
error.name = WebpMachineError.name;
|
|
||||||
error.message = `failed to decode webp image: ${error.message}`;
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(window as any).WebpMachine = WebpMachine;
|
|
42
src/lib/webp/webp.ts
Normal file
42
src/lib/webp/webp.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { WebPDecoder } from '../../vendor/libwebp-0.2.0';
|
||||||
|
import { encode } from 'fast-png';
|
||||||
|
|
||||||
|
export function webp2png(data: Uint8Array) {
|
||||||
|
const decoder = new WebPDecoder();
|
||||||
|
const config: any = decoder.WebPDecoderConfig;
|
||||||
|
const buffer = config.j || config.output;
|
||||||
|
const bitstream = config.input;
|
||||||
|
|
||||||
|
decoder.WebPInitDecoderConfig(config);
|
||||||
|
decoder.WebPGetFeatures(data, data.length, bitstream);
|
||||||
|
|
||||||
|
/** MODE_RGBA = 1 MODE_ARGB = 4, */
|
||||||
|
buffer.J = 1;
|
||||||
|
|
||||||
|
let status;
|
||||||
|
try {
|
||||||
|
status = decoder.WebPDecode(data, data.length, config);
|
||||||
|
} catch(e) {
|
||||||
|
status = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status === 0) {
|
||||||
|
const rgbaData = buffer.Jb;
|
||||||
|
const pngData = encode({
|
||||||
|
data: rgbaData,
|
||||||
|
width: buffer.width,
|
||||||
|
height: buffer.height,
|
||||||
|
channels: 4,
|
||||||
|
depth: 8,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {status, bytes: pngData};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {status, bytes: data};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function webp2pngAsBlob(data: Uint8Array) {
|
||||||
|
const {status, bytes} = webp2png(data);
|
||||||
|
return new Blob([bytes], {type: status === 0 ? 'image/png' : 'image/webp'});
|
||||||
|
}
|
50
src/lib/webp/webp.worker.ts
Normal file
50
src/lib/webp/webp.worker.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { webp2png } from './webp';
|
||||||
|
import type { WebpConvertTask } from './webpWorkerController';
|
||||||
|
|
||||||
|
const ctx = self as any as DedicatedWorkerGlobalScope;
|
||||||
|
const tasks: WebpConvertTask[] = [];
|
||||||
|
let isProcessing = false;
|
||||||
|
|
||||||
|
function finishTask() {
|
||||||
|
isProcessing = false;
|
||||||
|
processTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
function processTasks() {
|
||||||
|
if(isProcessing) return;
|
||||||
|
|
||||||
|
const task = tasks.shift();
|
||||||
|
if(!task) return;
|
||||||
|
|
||||||
|
isProcessing = true;
|
||||||
|
|
||||||
|
switch(task.type) {
|
||||||
|
case 'convertWebp': {
|
||||||
|
const {fileName, bytes} = task.payload;
|
||||||
|
|
||||||
|
ctx.postMessage({
|
||||||
|
type: 'convertWebp',
|
||||||
|
payload: {
|
||||||
|
fileName,
|
||||||
|
bytes: webp2png(bytes).bytes
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
finishTask();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
finishTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleTask(task: WebpConvertTask) {
|
||||||
|
tasks.push(task);
|
||||||
|
processTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.addEventListener('message', (event) => {
|
||||||
|
scheduleTask(event.data);
|
||||||
|
});
|
53
src/lib/webp/webpWorkerController.ts
Normal file
53
src/lib/webp/webpWorkerController.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import WebpWorker from 'worker-loader!./webp.worker';
|
||||||
|
import { CancellablePromise, deferredPromise } from '../polyfill';
|
||||||
|
|
||||||
|
export type WebpConvertTask = {
|
||||||
|
type: 'convertWebp',
|
||||||
|
payload: {
|
||||||
|
fileName: string,
|
||||||
|
bytes: Uint8Array
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export class WebpWorkerController {
|
||||||
|
private worker: Worker;
|
||||||
|
private convertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.worker = new WebpWorker();
|
||||||
|
this.worker.addEventListener('message', (e) => {
|
||||||
|
const payload = (e.data as WebpConvertTask).payload;
|
||||||
|
|
||||||
|
if(payload.fileName.indexOf('main-') === 0) {
|
||||||
|
const promise = this.convertPromises[payload.fileName];
|
||||||
|
if(promise) {
|
||||||
|
promise.resolve(payload.bytes);
|
||||||
|
delete this.convertPromises[payload.fileName];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigator.serviceWorker.controller.postMessage(e.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage(data: WebpConvertTask) {
|
||||||
|
if(this.init) {
|
||||||
|
this.init();
|
||||||
|
this.init = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.worker.postMessage(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
convert(fileName: string, bytes: Uint8Array) {
|
||||||
|
const convertPromise = deferredPromise<Uint8Array>();
|
||||||
|
|
||||||
|
fileName = 'main-' + fileName;
|
||||||
|
|
||||||
|
this.postMessage({type: 'convertWebp', payload: {fileName, bytes}});
|
||||||
|
|
||||||
|
return this.convertPromises[fileName] = convertPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const webpWorkerController = new WebpWorkerController();
|
4082
src/vendor/libwebp-0.2.0.js
vendored
Normal file
4082
src/vendor/libwebp-0.2.0.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -65,10 +65,8 @@
|
|||||||
"node_modules",
|
"node_modules",
|
||||||
"public",
|
"public",
|
||||||
"coverage",
|
"coverage",
|
||||||
"./src/lib/ckin.js",
|
|
||||||
"./src/lib/crypto/crypto.worker.js",
|
"./src/lib/crypto/crypto.worker.js",
|
||||||
"src/lib/config.ts",
|
"src/vendor/StackBlur.js",
|
||||||
"./src/lib/StackBlur.js",
|
|
||||||
"./src/lib/*.js",
|
"./src/lib/*.js",
|
||||||
"./src/*.js",
|
"./src/*.js",
|
||||||
"*.js",
|
"*.js",
|
||||||
|
@ -51,29 +51,6 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
].filter(l => !!l)
|
].filter(l => !!l)
|
||||||
},
|
},
|
||||||
/* {
|
|
||||||
test: /\.s[ac]ss$/i,
|
|
||||||
use: [
|
|
||||||
// Creates `style` nodes from JS strings
|
|
||||||
'style-loader',
|
|
||||||
// Translates CSS into CommonJS
|
|
||||||
'css-loader',
|
|
||||||
// Compiles Sass to CSS
|
|
||||||
{
|
|
||||||
loader: 'resolve-url-loader'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'sass-loader',
|
|
||||||
options: {
|
|
||||||
sourceMap: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.css$/i,
|
|
||||||
use: ['style-loader', 'css-loader'],
|
|
||||||
}, */
|
|
||||||
{
|
{
|
||||||
test: /\.ts?$/,
|
test: /\.ts?$/,
|
||||||
use: [
|
use: [
|
||||||
@ -82,21 +59,6 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
/* {
|
|
||||||
test: /\.(woff2?|ttf|otf|eot|svg|jpg)$/,
|
|
||||||
exclude: /node_modules/,
|
|
||||||
loader: 'file-loader',
|
|
||||||
options: {
|
|
||||||
outputPath: 'assets/',
|
|
||||||
publicPath: 'assets/',
|
|
||||||
name: '[folder]/[name].[ext]'
|
|
||||||
}
|
|
||||||
}, */
|
|
||||||
{
|
|
||||||
test: /\.worker\.(js|ts)$/,
|
|
||||||
use: { loader: 'worker-loader' }
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
test: /\.hbs$/,
|
test: /\.hbs$/,
|
||||||
use: [
|
use: [
|
||||||
@ -105,28 +67,23 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [ '.ts', '.js' ],
|
extensions: ['.ts', '.js'],
|
||||||
},
|
|
||||||
//entry: './src/index.ts',
|
|
||||||
entry: {
|
|
||||||
index: './src/index.ts',
|
|
||||||
//mp4: './src/lib/MP4Source.ts',
|
|
||||||
webp: './src/lib/webp.ts'/* ,
|
|
||||||
lottie: './src/lib/lottie.ts' */
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
entry: './src/index.ts',
|
||||||
/* entry: {
|
/* entry: {
|
||||||
index: './src/index.ts',
|
index: './src/index.ts'
|
||||||
'lottie-web': ['lottie-web']
|
|
||||||
//lottieLoader: './src/lib/lottieLoader.ts'
|
|
||||||
}, */
|
}, */
|
||||||
//devtool: 'inline-source-map',
|
//devtool: 'inline-source-map',
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'public'),
|
path: path.resolve(__dirname, 'public'),
|
||||||
//filename: 'bundle.js',
|
|
||||||
filename: "[name].bundle.js",
|
filename: "[name].bundle.js",
|
||||||
chunkFilename: "[name].chunk.js"
|
chunkFilename: "[name].chunk.js"
|
||||||
},
|
},
|
||||||
|
|
||||||
devServer: {
|
devServer: {
|
||||||
contentBase: path.join(__dirname, 'public'),
|
contentBase: path.join(__dirname, 'public'),
|
||||||
watchContentBase: true,
|
watchContentBase: true,
|
||||||
@ -165,19 +122,19 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
sockHost: useLocal ? undefined : 'tweb.enko.club',
|
sockHost: useLocal ? undefined : 'tweb.enko.club',
|
||||||
},
|
},
|
||||||
|
|
||||||
plugins: [
|
plugins: [
|
||||||
new ServiceWorkerWebpackPlugin({
|
new ServiceWorkerWebpackPlugin({
|
||||||
entry: path.join(__dirname, 'src/lib/mtproto/mtproto.service.ts'),
|
entry: path.join(__dirname, 'src/lib/mtproto/mtproto.service.ts'),
|
||||||
filename: 'sw.js',
|
filename: 'sw.js',
|
||||||
excludes: ['**/*'],
|
excludes: ['**/*'],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: `index.html`,
|
filename: `index.html`,
|
||||||
//template: 'public/index_template.html',
|
//template: 'public/index_template.html',
|
||||||
template: 'src/index.hbs',
|
template: 'src/index.hbs',
|
||||||
//inject: true,
|
inject: false, // true, 'head'
|
||||||
inject: false,
|
|
||||||
//inject: 'head',
|
|
||||||
minify: {
|
minify: {
|
||||||
removeComments: true,
|
removeComments: true,
|
||||||
collapseWhitespace: true,
|
collapseWhitespace: true,
|
||||||
@ -191,7 +148,7 @@ module.exports = {
|
|||||||
minifyURLs: true
|
minifyURLs: true
|
||||||
},
|
},
|
||||||
chunks: "all",
|
chunks: "all",
|
||||||
excludeChunks: ['npm.webp-hero'/* , 'mp4' *//* , 'npm.lottie-web' */]
|
excludeChunks: []
|
||||||
}),
|
}),
|
||||||
|
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user