@divriots/jampack 0.32.0 → 0.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -0
- package/README.md +0 -0
- package/dist/cache.js +7 -1
- package/dist/compress.js +5 -1
- package/dist/index.js +0 -0
- package/dist/optimize.js +129 -22
- package/dist/optimizers/img-external.js +3 -3
- package/dist/optimizers/process-iframe.js +2 -3
- package/dist/state.d.ts +2 -0
- package/dist/utils/install-dep.js +9 -2
- package/dist/utils/resource.d.ts +4 -3
- package/dist/utils/resource.js +12 -9
- package/package.json +9 -10
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/dist/cache.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { hashSync as hasha } from 'hasha';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import * as
|
|
3
|
+
import * as fsp from 'fs/promises';
|
|
4
4
|
import { CACHE_VERSIONS } from './packagejson.js';
|
|
5
5
|
const listOfCategories = ['img', 'img-ext'];
|
|
6
6
|
function getCacheFolder(state) {
|
|
7
7
|
return state.args.cache_folder || '.jampack/cache';
|
|
8
8
|
}
|
|
9
9
|
async function cleanCache(state, full) {
|
|
10
|
+
var _a;
|
|
10
11
|
const CACHE_FOLDER = getCacheFolder(state);
|
|
12
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
11
13
|
if (full) {
|
|
12
14
|
try {
|
|
13
15
|
await fs.rm(CACHE_FOLDER, { recursive: true });
|
|
@@ -66,9 +68,11 @@ function getLocation(state, hash, category) {
|
|
|
66
68
|
return path.join(CACHE_FOLDER, category, getVersionOfCategory(category), hash);
|
|
67
69
|
}
|
|
68
70
|
async function getFromCache(state, category, hash) {
|
|
71
|
+
var _a;
|
|
69
72
|
if (state.args.nocache) {
|
|
70
73
|
return undefined;
|
|
71
74
|
}
|
|
75
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
72
76
|
const location = getLocation(state, hash, category);
|
|
73
77
|
try {
|
|
74
78
|
const buffer = await fs.readFile(path.join(location, 'data'));
|
|
@@ -81,9 +85,11 @@ async function getFromCache(state, category, hash) {
|
|
|
81
85
|
return undefined;
|
|
82
86
|
}
|
|
83
87
|
async function addToCache(state, category, hash, data) {
|
|
88
|
+
var _a;
|
|
84
89
|
if (state.args.nocache) {
|
|
85
90
|
return;
|
|
86
91
|
}
|
|
92
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
87
93
|
const location = getLocation(state, hash, category);
|
|
88
94
|
await fs.mkdir(location, { recursive: true });
|
|
89
95
|
await fs.writeFile(path.join(location, 'data'), data.buffer);
|
package/dist/compress.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as fsp from 'fs/promises';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { formatBytes } from './utils.js';
|
|
4
4
|
import { globby } from 'globby';
|
|
@@ -8,7 +8,9 @@ import { compressJS } from './compressors/js.js';
|
|
|
8
8
|
import { compressHTML } from './compressors/html.js';
|
|
9
9
|
import { compressImage } from './compressors/images.js';
|
|
10
10
|
const processFile = async (state, file, stats) => {
|
|
11
|
+
var _a;
|
|
11
12
|
let writeData = undefined;
|
|
13
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
12
14
|
try {
|
|
13
15
|
const ext = path.extname(file);
|
|
14
16
|
switch (ext) {
|
|
@@ -69,6 +71,8 @@ const processFile = async (state, file, stats) => {
|
|
|
69
71
|
state.reportSummary(result);
|
|
70
72
|
};
|
|
71
73
|
export async function compressFolder(state, exclude) {
|
|
74
|
+
var _a;
|
|
75
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
72
76
|
const spinner = ora(getProgressText(state)).start();
|
|
73
77
|
const globs = ['**/**', '!_jampack/**']; // Exclude jampack folder because already compressed
|
|
74
78
|
if (exclude)
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/optimize.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { globby } from 'globby';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import * as
|
|
3
|
+
import * as fsp from 'fs/promises';
|
|
4
4
|
import { getCanonicalCdnForUrl, getTransformer } from 'unpic';
|
|
5
5
|
import * as cheerio from '@divriots/cheerio';
|
|
6
6
|
import { isNumeric } from './utils.js';
|
|
@@ -26,9 +26,11 @@ function getIntAttr(img, attr) {
|
|
|
26
26
|
return parsed;
|
|
27
27
|
}
|
|
28
28
|
async function analyse(state, file) {
|
|
29
|
+
var _a;
|
|
29
30
|
console.log('▶ ' + file);
|
|
30
31
|
// For processes to add into
|
|
31
32
|
const appendToBody = {};
|
|
33
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
32
34
|
const html = (await fs.readFile(path.join(state.dir, file))).toString();
|
|
33
35
|
if (!html.includes('<html'))
|
|
34
36
|
return;
|
|
@@ -37,6 +39,7 @@ async function analyse(state, file) {
|
|
|
37
39
|
await processTag(state, file, $, 'img', 'src', processImage, theFold, appendToBody);
|
|
38
40
|
await processTag(state, file, $, 'iframe', 'src', processIframe, theFold, appendToBody);
|
|
39
41
|
await processTag(state, file, $, 'video', 'src', processVideo, theFold, appendToBody);
|
|
42
|
+
await processTag(state, file, $, 'meta[property$=":image"], meta[name$=":image"]', 'content', processMetaImage, theFold, appendToBody);
|
|
40
43
|
// Remove the fold
|
|
41
44
|
//
|
|
42
45
|
if (theFold) {
|
|
@@ -148,7 +151,7 @@ function getTheFold($) {
|
|
|
148
151
|
return 0;
|
|
149
152
|
}
|
|
150
153
|
async function processImage(state, htmlfile, img, isAboveTheFold) {
|
|
151
|
-
var _a, _b;
|
|
154
|
+
var _a, _b, _c;
|
|
152
155
|
/*
|
|
153
156
|
* Attribute 'src'
|
|
154
157
|
*/
|
|
@@ -226,28 +229,21 @@ async function processImage(state, htmlfile, img, isAboveTheFold) {
|
|
|
226
229
|
/*
|
|
227
230
|
* Check for external images
|
|
228
231
|
*/
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
232
|
+
const { external } = state.options.image;
|
|
233
|
+
if (isExternalImage(attrib_src, external)) {
|
|
234
|
+
if (external.process === 'off')
|
|
235
|
+
// Don't process external images
|
|
233
236
|
return;
|
|
234
237
|
try {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
attrib_src =
|
|
238
|
-
}
|
|
239
|
-
else if (typeof config.image.external.process === 'function') {
|
|
240
|
-
// Custom processing for external image
|
|
241
|
-
attrib_src = await config.image.external.process(attrib_src);
|
|
242
|
-
}
|
|
243
|
-
img.attr('src', attrib_src);
|
|
238
|
+
const external_src = await externalImage(attrib_src, state, htmlfile);
|
|
239
|
+
if (external_src)
|
|
240
|
+
img.attr('src', (attrib_src = external_src));
|
|
244
241
|
}
|
|
245
242
|
catch (e) {
|
|
246
|
-
state.reportIssue(htmlfile, {
|
|
243
|
+
return state.reportIssue(htmlfile, {
|
|
247
244
|
type: 'warn',
|
|
248
245
|
msg: `Failed to process external image: ${attrib_src} - ${e.message}`,
|
|
249
|
-
});
|
|
250
|
-
return; // No more processing
|
|
246
|
+
}); // No more processing
|
|
251
247
|
}
|
|
252
248
|
}
|
|
253
249
|
switch (config.image.cdn.process) {
|
|
@@ -299,7 +295,7 @@ async function processImage(state, htmlfile, img, isAboveTheFold) {
|
|
|
299
295
|
/*
|
|
300
296
|
* Loading image
|
|
301
297
|
*/
|
|
302
|
-
const originalImage = await Resource.loadResource(state
|
|
298
|
+
const originalImage = await Resource.loadResource(state, htmlfile, attrib_src);
|
|
303
299
|
// No file -> give up
|
|
304
300
|
if (!originalImage) {
|
|
305
301
|
state.reportIssue(htmlfile, {
|
|
@@ -336,7 +332,7 @@ async function processImage(state, htmlfile, img, isAboveTheFold) {
|
|
|
336
332
|
const newSrc = path.join(path.dirname(attrib_src), path.basename(attrib_src, path.extname(attrib_src)) +
|
|
337
333
|
`.${newImage.format}`);
|
|
338
334
|
if (!state.compressedFiles.has(newFilename) && !state.args.nowrite) {
|
|
339
|
-
|
|
335
|
+
await ((_b = state.vfs) !== null && _b !== void 0 ? _b : fsp).writeFile(newFilename, newImage.data);
|
|
340
336
|
}
|
|
341
337
|
// Mark new file as compressed
|
|
342
338
|
state.compressedFiles.add(newFilename);
|
|
@@ -477,7 +473,7 @@ async function processImage(state, htmlfile, img, isAboveTheFold) {
|
|
|
477
473
|
// https://twitter.com/jonsneyers/status/1346389917816008704?s=19
|
|
478
474
|
const isLossless = mime === 'image/png' ||
|
|
479
475
|
(mime === 'image/webp' &&
|
|
480
|
-
((
|
|
476
|
+
((_c = (await originalImage.getImageMeta())) === null || _c === void 0 ? void 0 : _c.isLossless));
|
|
481
477
|
if (!isLossless) {
|
|
482
478
|
sourcesToGenerate.push({
|
|
483
479
|
mime: 'image/avif',
|
|
@@ -508,6 +504,103 @@ async function processImage(state, htmlfile, img, isAboveTheFold) {
|
|
|
508
504
|
}
|
|
509
505
|
}
|
|
510
506
|
}
|
|
507
|
+
async function processMetaImage(state, htmlfile, meta) {
|
|
508
|
+
var _a, _b, _c;
|
|
509
|
+
const attribute = 'content';
|
|
510
|
+
let content = meta.attr(attribute);
|
|
511
|
+
if (!content)
|
|
512
|
+
return state.reportIssue(htmlfile, {
|
|
513
|
+
type: 'warn',
|
|
514
|
+
msg: `Missing [content] on meta - processing skipped.`,
|
|
515
|
+
});
|
|
516
|
+
// Setup to ignore
|
|
517
|
+
const { src_exclude, src_include, cdn, external } = state.options.image;
|
|
518
|
+
if (!isIncluded(content, src_include, src_exclude))
|
|
519
|
+
return;
|
|
520
|
+
/*
|
|
521
|
+
* Check for external images
|
|
522
|
+
*/
|
|
523
|
+
if (isExternalImage(content, external)) {
|
|
524
|
+
if (external.process === 'off')
|
|
525
|
+
// Don't process external images
|
|
526
|
+
return;
|
|
527
|
+
try {
|
|
528
|
+
const external_content = await externalImage(content, state, htmlfile);
|
|
529
|
+
if (external_content)
|
|
530
|
+
meta.attr(attribute, (content = external_content));
|
|
531
|
+
}
|
|
532
|
+
catch (e) {
|
|
533
|
+
return state.reportIssue(htmlfile, {
|
|
534
|
+
type: 'warn',
|
|
535
|
+
msg: `Failed to process external image: ${attribute} - ${e.message}`,
|
|
536
|
+
}); // No more processing
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const propName = meta.attr('property') ? 'property' : 'name';
|
|
540
|
+
const width = meta.closest(`meta[${propName}:width]`).attr(attribute);
|
|
541
|
+
switch (cdn.process) {
|
|
542
|
+
case 'off':
|
|
543
|
+
break;
|
|
544
|
+
case 'optimize':
|
|
545
|
+
let cdnTransformer = cdn.transformer;
|
|
546
|
+
if (cdnTransformer && !cdn.src_include) {
|
|
547
|
+
throw new Error('config.image.cdn.src_include is required when specifying a config.image.cdn.transformer');
|
|
548
|
+
}
|
|
549
|
+
if (!cdnTransformer) {
|
|
550
|
+
const canonical = getCanonicalCdnForUrl(content);
|
|
551
|
+
if (!canonical)
|
|
552
|
+
break;
|
|
553
|
+
cdnTransformer = getTransformer(canonical.cdn);
|
|
554
|
+
}
|
|
555
|
+
if (!cdnTransformer)
|
|
556
|
+
break;
|
|
557
|
+
if (!isIncluded(content, cdn.src_include || /.*/, cdn.src_exclude))
|
|
558
|
+
break;
|
|
559
|
+
if (!width)
|
|
560
|
+
return state.reportIssue(htmlfile, {
|
|
561
|
+
type: 'warn',
|
|
562
|
+
msg: `Missing or malformed'width' attribute for image ${content}, unable to perform CDN transform`,
|
|
563
|
+
});
|
|
564
|
+
meta.attr(attribute, (_b = (_a = cdnTransformer({ url: content, width: +width })) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.replace(UNPIC_DEFAULT_HOST_REGEX, '/'));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
/*
|
|
568
|
+
* Loading image
|
|
569
|
+
*/
|
|
570
|
+
const originalImage = await Resource.loadResource(state, htmlfile, content);
|
|
571
|
+
if (!originalImage)
|
|
572
|
+
return state.reportIssue(htmlfile, {
|
|
573
|
+
type: 'erro',
|
|
574
|
+
msg: `Can't find img on disk ${attribute}="${content}"`,
|
|
575
|
+
});
|
|
576
|
+
/*
|
|
577
|
+
* Compress image
|
|
578
|
+
*/
|
|
579
|
+
const newImage = await compressImage(state, await originalImage.getData(), {
|
|
580
|
+
resize: width ? { width: +width } : undefined,
|
|
581
|
+
toFormat: meta.closest(`meta[${propName}:type]`).attr(attribute) === 'image/png'
|
|
582
|
+
? 'png'
|
|
583
|
+
: 'jpeg',
|
|
584
|
+
});
|
|
585
|
+
if ((newImage === null || newImage === void 0 ? void 0 : newImage.data) && newImage.data.length < (await originalImage.getLen())) {
|
|
586
|
+
meta.attr(attribute, path.join(path.dirname(content), path.basename(content, path.extname(content)) + `.${newImage.format}`));
|
|
587
|
+
const newFilename = path.join(path.dirname(originalImage.filePathAbsolute), path.basename(originalImage.filePathAbsolute, path.extname(originalImage.filePathAbsolute)) + `.${newImage.format}`);
|
|
588
|
+
if (!state.compressedFiles.has(newFilename)) {
|
|
589
|
+
if (!state.args.nowrite)
|
|
590
|
+
await ((_c = state.vfs) !== null && _c !== void 0 ? _c : fsp).writeFile(newFilename, newImage.data);
|
|
591
|
+
// Mark new file as compressed
|
|
592
|
+
state.compressedFiles.add(newFilename);
|
|
593
|
+
// Report compression result
|
|
594
|
+
state.reportSummary({
|
|
595
|
+
action: newFilename !== originalImage.filePathAbsolute
|
|
596
|
+
? `${await originalImage.getExt()}->${newImage.format}`
|
|
597
|
+
: path.extname(originalImage.filePathAbsolute),
|
|
598
|
+
originalSize: await originalImage.getLen(),
|
|
599
|
+
compressedSize: newImage.data.length,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
511
604
|
const isIncluded = (src, includeConf, excludeConf) => !!src.match(includeConf) && (!excludeConf || !src.match(excludeConf));
|
|
512
605
|
async function _generateSrcSet({ options }, startSrc, imageWidth, imageHeight, transformSrc) {
|
|
513
606
|
// Start from original image
|
|
@@ -549,6 +642,7 @@ async function generateSrcSet(state, htmlfile, originalImage, startSrc, startSrc
|
|
|
549
642
|
const imageHeight = (meta === null || meta === void 0 ? void 0 : meta.height) || 0;
|
|
550
643
|
let previousImageSize = startSrcLength || Number.MAX_VALUE;
|
|
551
644
|
return _generateSrcSet(state, startSrc, imageWidth, imageHeight, async (valueW) => {
|
|
645
|
+
var _a;
|
|
552
646
|
const src = imageSrc(`@${valueW}w`);
|
|
553
647
|
const absoluteFilename = translateSrc(state.dir, path.dirname(htmlfile), src);
|
|
554
648
|
// Don't generate srcset file twice
|
|
@@ -563,7 +657,7 @@ async function generateSrcSet(state, htmlfile, originalImage, startSrc, startSrc
|
|
|
563
657
|
else {
|
|
564
658
|
// Write file
|
|
565
659
|
if (!state.args.nowrite) {
|
|
566
|
-
|
|
660
|
+
await ((_a = state.vfs) !== null && _a !== void 0 ? _a : fsp).writeFile(absoluteFilename, compressedImage.data);
|
|
567
661
|
}
|
|
568
662
|
// Set new previous size to beat
|
|
569
663
|
previousImageSize = compressedImage.data.length;
|
|
@@ -707,6 +801,7 @@ async function setImageSize(state, htmlfile, img, image) {
|
|
|
707
801
|
throw new Error(`Unexpected issue when resolving image size "${image.src}"`);
|
|
708
802
|
}
|
|
709
803
|
export async function optimize(state, include, exclude) {
|
|
804
|
+
var _a;
|
|
710
805
|
const glob = include ? [include] : ['**/*.{htm,html}'];
|
|
711
806
|
if (exclude)
|
|
712
807
|
glob.push('!' + exclude);
|
|
@@ -714,6 +809,7 @@ export async function optimize(state, include, exclude) {
|
|
|
714
809
|
// Sequential async
|
|
715
810
|
for (const file of paths) {
|
|
716
811
|
await analyse(state, file);
|
|
812
|
+
(_a = state.onAnalysedFile) === null || _a === void 0 ? void 0 : _a.call(state, file);
|
|
717
813
|
}
|
|
718
814
|
}
|
|
719
815
|
async function processTag(state, file, $, tag, attribute_to_log, processor, theFold, appendToBody) {
|
|
@@ -754,3 +850,14 @@ async function processTag(state, file, $, tag, attribute_to_log, processor, theF
|
|
|
754
850
|
spinnerImg.succeed();
|
|
755
851
|
}
|
|
756
852
|
}
|
|
853
|
+
const isExternalImage = (content, external) => !isLocal(content) &&
|
|
854
|
+
isIncluded(content, external.src_include, external.src_exclude);
|
|
855
|
+
async function externalImage(content, state, htmlfile) {
|
|
856
|
+
const { process } = state.options.image.external;
|
|
857
|
+
if (process === 'download')
|
|
858
|
+
// Download external image for local processing
|
|
859
|
+
return await downloadExternalImage(state, htmlfile, content);
|
|
860
|
+
if (typeof process === 'function')
|
|
861
|
+
// Custom processing for external image
|
|
862
|
+
return await process(content);
|
|
863
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import * as
|
|
2
|
+
import * as fsp from 'fs/promises';
|
|
3
3
|
import { hashSync as hasha } from 'hasha';
|
|
4
4
|
import { fileTypeFromBuffer } from 'file-type';
|
|
5
5
|
import { addToCache, getFromCache } from '../cache.js';
|
|
6
6
|
import { parse } from '../utils/cache-control-parser.js';
|
|
7
7
|
import '../utils/polyfill-fetch.js';
|
|
8
8
|
export async function downloadExternalImage(state, htmlfile, href) {
|
|
9
|
-
var _a, _b, _c, _d, _e;
|
|
9
|
+
var _a, _b, _c, _d, _e, _f;
|
|
10
10
|
const hash = hasha(href, {
|
|
11
11
|
algorithm: 'md5',
|
|
12
12
|
});
|
|
@@ -97,6 +97,6 @@ export async function downloadExternalImage(state, htmlfile, href) {
|
|
|
97
97
|
throw new Error('Unknown image format');
|
|
98
98
|
const htmlFolder = path.dirname(htmlfile);
|
|
99
99
|
const filename = path.relative(path.join(state.dir, htmlFolder), path.join(state.dir, `_jampack/${contentHash}.${ext}`));
|
|
100
|
-
await
|
|
100
|
+
await ((_f = state.vfs) !== null && _f !== void 0 ? _f : fsp).writeFile(path.join(state.dir, htmlFolder, filename), buffer);
|
|
101
101
|
return filename;
|
|
102
102
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { install_lozad } from '../utils/install-dep.js';
|
|
2
2
|
export async function processIframe(state, htmlfile, iframe, isAboveTheFold, appendToBody) {
|
|
3
|
-
// Reset loading attribute
|
|
4
|
-
iframe.removeAttr('loading');
|
|
5
3
|
const lazyloadOptions = state.options.iframe.lazyload;
|
|
6
|
-
if (lazyloadOptions.when === 'never') {
|
|
4
|
+
if (lazyloadOptions.when === 'never' || iframe.attr('loading') === 'eager') {
|
|
5
|
+
// If lazy loading is set to 'never' or 'eager', do not modify the iframe
|
|
7
6
|
return;
|
|
8
7
|
}
|
|
9
8
|
if (lazyloadOptions.when === 'always' ||
|
package/dist/state.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export declare class GlobalState {
|
|
|
29
29
|
installed_dependencies: Set<string>;
|
|
30
30
|
summary: Summary;
|
|
31
31
|
summaryByExtension: Record<string, Summary>;
|
|
32
|
+
vfs?: typeof import('fs/promises');
|
|
33
|
+
onAnalysedFile?: (file: string) => void;
|
|
32
34
|
reportIssue(sourceFile: string, issue: Issue): void;
|
|
33
35
|
reportSummary(r: ReportItem): void;
|
|
34
36
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as fsp from 'fs/promises';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
const require = createRequire(import.meta.url);
|
|
5
5
|
export async function install_dependency(state, html_file, options, appendToBody) {
|
|
6
|
+
var _a;
|
|
6
7
|
const path_html = path.dirname('/' + html_file);
|
|
7
8
|
const folder = `/_jampack/${options.destination.folder_name}`;
|
|
8
9
|
const src_filename = options.source.filename;
|
|
9
10
|
const url_loader = `${folder}/loader.js`;
|
|
11
|
+
const fs = (_a = state.vfs) !== null && _a !== void 0 ? _a : fsp;
|
|
10
12
|
// Install dependency in /_jampack if not done yet
|
|
11
13
|
if (!state.installed_dependencies.has(options.source.npm_package_name)) {
|
|
12
14
|
const quickLinkDestination = path.join(state.dir, folder, src_filename);
|
|
@@ -17,7 +19,12 @@ export async function install_dependency(state, html_file, options, appendToBody
|
|
|
17
19
|
await fs.writeFile(path_loader, code_loader);
|
|
18
20
|
// Write quicklink code
|
|
19
21
|
const source = require.resolve(`${options.source.npm_package_name}${options.source.absolute_path_to_file}/${src_filename}`);
|
|
20
|
-
|
|
22
|
+
if (state.vfs) {
|
|
23
|
+
await state.vfs.writeFile(quickLinkDestination, await fsp.readFile(source));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
await fs.copyFile(source, quickLinkDestination);
|
|
27
|
+
}
|
|
21
28
|
state.installed_dependencies.add(options.source.npm_package_name);
|
|
22
29
|
}
|
|
23
30
|
// Add custom code to the end of body if not done yet
|
package/dist/utils/resource.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FileExtension, MimeType } from 'file-type';
|
|
2
2
|
import { ImageFormat } from '../compressors/images.js';
|
|
3
|
+
import { GlobalState } from '../state.js';
|
|
3
4
|
type ImageMeta = {
|
|
4
5
|
width: number | undefined;
|
|
5
6
|
height: number | undefined;
|
|
@@ -11,13 +12,14 @@ type ImageMeta = {
|
|
|
11
12
|
* File extension, mime and data are loaded only on demand, then cached.
|
|
12
13
|
*/
|
|
13
14
|
export declare class Resource {
|
|
15
|
+
private state;
|
|
14
16
|
readonly src: string;
|
|
15
17
|
readonly filePathAbsolute: string;
|
|
16
18
|
private ext;
|
|
17
19
|
private mime;
|
|
18
20
|
private data;
|
|
19
21
|
private image_meta;
|
|
20
|
-
constructor(src: string, filePathAbsolute: string);
|
|
22
|
+
constructor(state: GlobalState, src: string, filePathAbsolute: string);
|
|
21
23
|
getData(): Promise<Buffer>;
|
|
22
24
|
getImageMeta(): Promise<ImageMeta | null | undefined>;
|
|
23
25
|
getLen(): Promise<number>;
|
|
@@ -25,9 +27,8 @@ export declare class Resource {
|
|
|
25
27
|
getImageFormat(): Promise<ImageFormat | undefined>;
|
|
26
28
|
getMime(): Promise<MimeType | 'image/svg+xml'>;
|
|
27
29
|
private loadFileType;
|
|
28
|
-
static loadResource(
|
|
30
|
+
static loadResource(state: GlobalState, relativeFile: string, src: string): Promise<Resource | undefined>;
|
|
29
31
|
}
|
|
30
32
|
export declare function isLocal(src: string): boolean;
|
|
31
|
-
export declare function fileExists(path: string): Promise<boolean>;
|
|
32
33
|
export declare function translateSrc(projectRoot: string, htmlRelativePath: string, src: string): string;
|
|
33
34
|
export {};
|
package/dist/utils/resource.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as url from 'url';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import * as
|
|
3
|
+
import * as fsp from 'fs/promises';
|
|
4
4
|
import { fileTypeFromBuffer } from 'file-type';
|
|
5
5
|
import sharp from 'sharp';
|
|
6
6
|
import { AllImageFormat } from '../compressors/images.js';
|
|
@@ -8,13 +8,15 @@ import { AllImageFormat } from '../compressors/images.js';
|
|
|
8
8
|
* File extension, mime and data are loaded only on demand, then cached.
|
|
9
9
|
*/
|
|
10
10
|
export class Resource {
|
|
11
|
-
constructor(src, filePathAbsolute) {
|
|
11
|
+
constructor(state, src, filePathAbsolute) {
|
|
12
|
+
this.state = state;
|
|
12
13
|
this.src = src;
|
|
13
14
|
this.filePathAbsolute = filePathAbsolute;
|
|
14
15
|
}
|
|
15
16
|
async getData() {
|
|
17
|
+
var _a;
|
|
16
18
|
if (this.data === undefined) {
|
|
17
|
-
this.data = await
|
|
19
|
+
this.data = await ((_a = this.state.vfs) !== null && _a !== void 0 ? _a : fsp).readFile(this.filePathAbsolute);
|
|
18
20
|
}
|
|
19
21
|
return this.data;
|
|
20
22
|
}
|
|
@@ -98,7 +100,7 @@ export class Resource {
|
|
|
98
100
|
throw new Error(`Unknown file type "${this.src}"`);
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
|
-
static async loadResource(
|
|
103
|
+
static async loadResource(state, relativeFile, src) {
|
|
102
104
|
if (!isLocal(src)) {
|
|
103
105
|
throw new Error('src should be local');
|
|
104
106
|
}
|
|
@@ -106,10 +108,10 @@ export class Resource {
|
|
|
106
108
|
if (!u.pathname) {
|
|
107
109
|
throw new Error(`Invalid src format "${src}"`);
|
|
108
110
|
}
|
|
109
|
-
const relativePath = path.join(
|
|
111
|
+
const relativePath = path.join(state.dir, src.startsWith('/') ? '' : path.dirname(relativeFile), u.pathname);
|
|
110
112
|
let absolutePath = path.resolve(relativePath);
|
|
111
|
-
if (await fileExists(absolutePath)) {
|
|
112
|
-
return new Resource(src, absolutePath);
|
|
113
|
+
if (await fileExists(state, absolutePath)) {
|
|
114
|
+
return new Resource(state, src, absolutePath);
|
|
113
115
|
}
|
|
114
116
|
return undefined;
|
|
115
117
|
}
|
|
@@ -118,9 +120,10 @@ export function isLocal(src) {
|
|
|
118
120
|
const u = url.parse(src);
|
|
119
121
|
return !u.host;
|
|
120
122
|
}
|
|
121
|
-
|
|
123
|
+
async function fileExists(state, path) {
|
|
124
|
+
var _a;
|
|
122
125
|
try {
|
|
123
|
-
await
|
|
126
|
+
await ((_a = state.vfs) !== null && _a !== void 0 ? _a : fsp).stat(path);
|
|
124
127
|
}
|
|
125
128
|
catch (e) {
|
|
126
129
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@divriots/jampack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.1",
|
|
4
4
|
"cache-version": {
|
|
5
5
|
"img": "v1",
|
|
6
6
|
"img-ext": "v1"
|
|
@@ -60,18 +60,17 @@
|
|
|
60
60
|
"tslib": "^2.6.2",
|
|
61
61
|
"typescript": "^5.4.5"
|
|
62
62
|
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=14.0.0"
|
|
65
|
+
},
|
|
66
|
+
"bugs": "https://github.com/divriots/jampack/issues",
|
|
67
|
+
"keywords": [],
|
|
68
|
+
"types": "dist/index.d.ts",
|
|
63
69
|
"scripts": {
|
|
64
70
|
"watch": "pnpm build --watch",
|
|
65
71
|
"try": "shx rm -fr demo && cp -R demo_drc demo && node ./dist/index.js ./demo --nocache",
|
|
66
72
|
"build": "shx rm -rf dist && tsc -b",
|
|
67
73
|
"lint": "eslint . --ext .ts --config .eslintrc",
|
|
68
|
-
"prepublishOnly": "pnpm build",
|
|
69
74
|
"cleanAllDotJampack": "find -s . | grep '.jampack$' | xargs rm -fr"
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
"node": ">=14.0.0"
|
|
73
|
-
},
|
|
74
|
-
"bugs": "https://github.com/divriots/jampack/issues",
|
|
75
|
-
"keywords": [],
|
|
76
|
-
"types": "dist/index.d.ts"
|
|
77
|
-
}
|
|
75
|
+
}
|
|
76
|
+
}
|