@divriots/jampack 0.24.4 → 0.25.0

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 CHANGED
File without changes
package/README.md CHANGED
File without changes
package/dist/cache.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
+ import { GlobalState } from './state.js';
2
3
  declare const listOfCategories: readonly ["img", "img-ext"];
3
4
  export type Category = (typeof listOfCategories)[number];
4
5
  export type CacheData = {
5
6
  buffer: Buffer;
6
7
  meta: any;
7
8
  };
8
- declare function cleanCache(full: boolean): Promise<void>;
9
- declare function computeCacheHash(buffer: Buffer, options?: any): string;
10
- declare function getFromCache(category: Category, hash: string): Promise<CacheData | undefined>;
11
- declare function addToCache(category: Category, hash: string, data: CacheData): Promise<void>;
9
+ declare function cleanCache(state: GlobalState, full?: boolean): Promise<void>;
10
+ declare function computeCacheHash(state: GlobalState, buffer: Buffer, options?: any): string;
11
+ declare function getFromCache(state: GlobalState, category: Category, hash: string): Promise<CacheData | undefined>;
12
+ declare function addToCache(state: GlobalState, category: Category, hash: string, data: CacheData): Promise<void>;
12
13
  export { cleanCache, computeCacheHash, getFromCache, addToCache };
package/dist/cache.js CHANGED
@@ -1,14 +1,13 @@
1
1
  import { hashSync as hasha } from 'hasha';
2
2
  import path from 'path';
3
3
  import * as fs from 'fs/promises';
4
- import $state from './state.js';
5
4
  import { CACHE_VERSIONS } from './packagejson.js';
6
5
  const listOfCategories = ['img', 'img-ext'];
7
- function getCacheFolder() {
8
- return $state.args.cache_folder || '.jampack/cache';
6
+ function getCacheFolder(state) {
7
+ return state.args.cache_folder || '.jampack/cache';
9
8
  }
10
- async function cleanCache(full) {
11
- const CACHE_FOLDER = getCacheFolder();
9
+ async function cleanCache(state, full) {
10
+ const CACHE_FOLDER = getCacheFolder(state);
12
11
  if (full) {
13
12
  try {
14
13
  await fs.rm(CACHE_FOLDER, { recursive: true });
@@ -49,8 +48,8 @@ async function cleanCache(full) {
49
48
  }
50
49
  }
51
50
  }
52
- function computeCacheHash(buffer, options) {
53
- if ($state.args.nocache) {
51
+ function computeCacheHash(state, buffer, options) {
52
+ if (state.args.nocache) {
54
53
  return '';
55
54
  }
56
55
  let hash = `${hasha(buffer, { algorithm: 'sha256' })}`;
@@ -62,15 +61,15 @@ function computeCacheHash(buffer, options) {
62
61
  function getVersionOfCategory(category) {
63
62
  return CACHE_VERSIONS[category];
64
63
  }
65
- function getLocation(hash, category) {
66
- const CACHE_FOLDER = getCacheFolder();
64
+ function getLocation(state, hash, category) {
65
+ const CACHE_FOLDER = getCacheFolder(state);
67
66
  return path.join(CACHE_FOLDER, category, getVersionOfCategory(category), hash);
68
67
  }
69
- async function getFromCache(category, hash) {
70
- if ($state.args.nocache) {
68
+ async function getFromCache(state, category, hash) {
69
+ if (state.args.nocache) {
71
70
  return undefined;
72
71
  }
73
- const location = getLocation(hash, category);
72
+ const location = getLocation(state, hash, category);
74
73
  try {
75
74
  const buffer = await fs.readFile(path.join(location, 'data'));
76
75
  const meta = JSON.parse((await fs.readFile(path.join(location, 'meta'))).toString());
@@ -81,11 +80,11 @@ async function getFromCache(category, hash) {
81
80
  }
82
81
  return undefined;
83
82
  }
84
- async function addToCache(category, hash, data) {
85
- if ($state.args.nocache) {
83
+ async function addToCache(state, category, hash, data) {
84
+ if (state.args.nocache) {
86
85
  return;
87
86
  }
88
- const location = getLocation(hash, category);
87
+ const location = getLocation(state, hash, category);
89
88
  await fs.mkdir(location, { recursive: true });
90
89
  await fs.writeFile(path.join(location, 'data'), data.buffer);
91
90
  await fs.writeFile(path.join(location, 'meta'), JSON.stringify(data.meta));
@@ -1 +1,2 @@
1
- export declare function compressFolder(exclude: string): Promise<void>;
1
+ import { GlobalState } from './state.js';
2
+ export declare function compressFolder(state: GlobalState, exclude?: string): Promise<void>;
package/dist/compress.js CHANGED
@@ -1,15 +1,13 @@
1
1
  import * as fs from 'fs/promises';
2
2
  import * as path from 'path';
3
3
  import { formatBytes } from './utils.js';
4
- import config from './config.js';
5
- import $state from './state.js';
6
4
  import { globby } from 'globby';
7
5
  import ora from 'ora';
8
6
  import { compressCSS } from './compressors/css.js';
9
7
  import { compressJS } from './compressors/js.js';
10
8
  import { compressHTML } from './compressors/html.js';
11
9
  import { compressImage } from './compressors/images.js';
12
- const processFile = async (file, stats) => {
10
+ const processFile = async (state, file, stats) => {
13
11
  let writeData = undefined;
14
12
  try {
15
13
  const ext = path.extname(file);
@@ -20,9 +18,9 @@ const processFile = async (file, stats) => {
20
18
  case '.svg':
21
19
  case '.webp':
22
20
  case '.avif':
23
- if (config.image.compress) {
21
+ if (state.options.image.compress) {
24
22
  const imgData = await fs.readFile(file);
25
- const newImage = await compressImage(imgData, {});
23
+ const newImage = await compressImage(state, imgData, {});
26
24
  if ((newImage === null || newImage === void 0 ? void 0 : newImage.data) && newImage.data.length < stats.size) {
27
25
  writeData = newImage.data;
28
26
  }
@@ -31,19 +29,19 @@ const processFile = async (file, stats) => {
31
29
  case '.html':
32
30
  case '.htm':
33
31
  const htmldata = await fs.readFile(file);
34
- const newhtmlData = await compressHTML(htmldata);
32
+ const newhtmlData = await compressHTML(state, htmldata);
35
33
  writeData = newhtmlData;
36
34
  break;
37
35
  case '.css':
38
36
  const cssdata = await fs.readFile(file);
39
- const newCSS = await compressCSS(cssdata);
37
+ const newCSS = await compressCSS(state, cssdata);
40
38
  if (newCSS && newCSS.length < cssdata.length) {
41
39
  writeData = newCSS;
42
40
  }
43
41
  break;
44
42
  case '.js':
45
43
  const jsdata = await fs.readFile(file);
46
- const newJS = await compressJS(jsdata.toString());
44
+ const newJS = await compressJS(state, jsdata.toString());
47
45
  if (newJS && newJS.length < jsdata.length) {
48
46
  writeData = newJS;
49
47
  }
@@ -63,30 +61,30 @@ const processFile = async (file, stats) => {
63
61
  // Writedata
64
62
  if (writeData && writeData.length < result.originalSize) {
65
63
  result.compressedSize = writeData.length;
66
- if (!$state.args.nowrite) {
64
+ if (!state.args.nowrite) {
67
65
  await fs.writeFile(file, writeData);
68
66
  }
69
67
  }
70
- $state.compressedFiles.add(file);
71
- $state.reportSummary(result);
68
+ state.compressedFiles.add(file);
69
+ state.reportSummary(result);
72
70
  };
73
- export async function compressFolder(exclude) {
74
- const spinner = ora(getProgressText()).start();
71
+ export async function compressFolder(state, exclude) {
72
+ const spinner = ora(getProgressText(state)).start();
75
73
  const globs = ['**/**', '!_jampack/**']; // Exclude jampack folder because already compressed
76
74
  if (exclude)
77
75
  globs.push('!' + exclude);
78
- const paths = await globby(globs, { cwd: $state.dir, absolute: true });
76
+ const paths = await globby(globs, { cwd: state.dir, absolute: true });
79
77
  // "Parallel" processing
80
78
  await Promise.all(paths.map(async (file) => {
81
- if (!$state.compressedFiles.has(file)) {
82
- await processFile(file, await fs.stat(file));
83
- spinner.text = getProgressText();
79
+ if (!state.compressedFiles.has(file)) {
80
+ await processFile(state, file, await fs.stat(file));
81
+ spinner.text = getProgressText(state);
84
82
  }
85
83
  }));
86
- spinner.text = getProgressText();
84
+ spinner.text = getProgressText(state);
87
85
  spinner.succeed();
88
86
  }
89
- const getProgressText = () => {
90
- const gain = $state.summary.dataLenUncompressed - $state.summary.dataLenCompressed;
91
- return `${$state.summary.nbFiles} files | ${formatBytes($state.summary.dataLenUncompressed)} → ${formatBytes($state.summary.dataLenCompressed)} | -${formatBytes(gain)} `;
87
+ const getProgressText = (state) => {
88
+ const gain = state.summary.dataLenUncompressed - state.summary.dataLenCompressed;
89
+ return `${state.summary.nbFiles} files | ${formatBytes(state.summary.dataLenUncompressed)} → ${formatBytes(state.summary.dataLenCompressed)} | -${formatBytes(gain)} `;
92
90
  };
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- import { Options } from '../config-types.js';
3
- export declare function compressCSS(originalCode: Buffer, type?: 'inline' | undefined): Promise<Buffer>;
4
- export declare function loadConfig(config: Options): void;
2
+ import { GlobalState } from '../state.js';
3
+ export declare const defaultTargets: () => import("lightningcss").Targets;
4
+ export declare function compressCSS({ targets }: GlobalState, originalCode: Buffer, type?: 'inline' | undefined): Promise<Buffer>;
5
+ export declare function loadConfigCSS(state: GlobalState): void;
@@ -1,7 +1,7 @@
1
1
  import browserslist from 'browserslist';
2
2
  import { browserslistToTargets, transform as lightcss, transformStyleAttribute as lightcssStyleAttribute, } from 'lightningcss';
3
- let targets = browserslistToTargets(browserslist('defaults'));
4
- export async function compressCSS(originalCode, type) {
3
+ export const defaultTargets = () => browserslistToTargets(browserslist('defaults'));
4
+ export async function compressCSS({ targets }, originalCode, type) {
5
5
  // Compress with lightningcss
6
6
  let lightCSSData = undefined;
7
7
  try {
@@ -28,10 +28,10 @@ export async function compressCSS(originalCode, type) {
28
28
  }
29
29
  let resultBuffer = undefined;
30
30
  if (lightCSSData && lightCSSData.length < originalCode.length) {
31
- resultBuffer = lightCSSData;
31
+ resultBuffer = Buffer.from(lightCSSData);
32
32
  }
33
33
  return resultBuffer || originalCode;
34
34
  }
35
- export function loadConfig(config) {
36
- targets = browserslistToTargets(browserslist(config.css.browserslist || config.general.browserslist));
35
+ export function loadConfigCSS(state) {
36
+ const { options } = state;
37
37
  }
@@ -1,2 +1,3 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- export declare function compressHTML(originalCode: Buffer): Promise<Buffer>;
2
+ import { GlobalState } from '../state.js';
3
+ export declare function compressHTML(state: GlobalState, originalCode: Buffer): Promise<Buffer>;
@@ -1,29 +1,28 @@
1
1
  import { minify } from 'html-minifier-terser';
2
2
  import { compressCSS } from './css.js';
3
3
  import { compressJS } from './js.js';
4
- import config from '../config.js';
5
- async function minifyJSinHTML(originalCode) {
6
- const newCode = await compressJS(originalCode);
4
+ async function minifyJSinHTML(state, originalCode) {
5
+ const newCode = await compressJS(state, originalCode);
7
6
  if (newCode && newCode.length < originalCode.length)
8
7
  return newCode;
9
8
  return originalCode;
10
9
  }
11
- async function minifyCSSinHTML(originalCode, type) {
10
+ async function minifyCSSinHTML(state, originalCode, type) {
12
11
  // Don't compress media
13
- if (type === 'media')
12
+ if (type !== undefined && type !== 'inline')
14
13
  return originalCode;
15
14
  const originalBuffer = Buffer.from(originalCode);
16
- const newCSS = await compressCSS(originalBuffer, type);
15
+ const newCSS = await compressCSS(state, originalBuffer, type);
17
16
  if (newCSS && newCSS.length > 0 && newCSS.length < originalBuffer.length)
18
17
  return newCSS.toString();
19
18
  return originalCode;
20
19
  }
21
- export async function compressHTML(originalCode) {
20
+ export async function compressHTML(state, originalCode) {
22
21
  const newhtmlData = await minify(originalCode.toString(), {
23
- minifyCSS: minifyCSSinHTML,
24
- minifyJS: minifyJSinHTML,
22
+ minifyCSS: (text, type) => minifyCSSinHTML(state, text, type),
23
+ minifyJS: (text) => minifyJSinHTML(state, text),
25
24
  sortClassName: true,
26
- sortAttributes: config.html.sort_attributes,
25
+ sortAttributes: state.options.html.sort_attributes,
27
26
  });
28
27
  if (newhtmlData)
29
28
  return Buffer.from(newhtmlData, 'utf-8');
@@ -1,6 +1,7 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  import sharp from 'sharp';
3
3
  import { MimeType } from 'file-type';
4
+ import { GlobalState } from '../state.js';
4
5
  export type ImageMimeType = MimeType | 'image/svg+xml';
5
6
  export declare const AllImageFormat: string[];
6
7
  export type ImageFormat = (typeof AllImageFormat)[number] | undefined;
@@ -12,4 +13,4 @@ export type ImageOutputOptions = {
12
13
  resize?: sharp.ResizeOptions;
13
14
  toFormat?: 'webp' | 'avif' | 'png' | 'jpeg' | 'unchanged';
14
15
  };
15
- export declare function compressImage(data: Buffer, options: ImageOutputOptions): Promise<Image | undefined>;
16
+ export declare function compressImage(state: GlobalState, data: Buffer, options: ImageOutputOptions): Promise<Image | undefined>;
@@ -1,7 +1,6 @@
1
1
  import sharp from 'sharp';
2
2
  import { optimize as svgo } from 'svgo';
3
3
  import { getFromCache, addToCache, computeCacheHash } from '../cache.js';
4
- import config from '../config.js';
5
4
  export const AllImageFormat = ['webp', 'svg', 'jpg', 'png', 'avif'];
6
5
  function createWebpOptions(opt) {
7
6
  return {
@@ -10,10 +9,10 @@ function createWebpOptions(opt) {
10
9
  effort: opt.effort,
11
10
  };
12
11
  }
13
- export async function compressImage(data, options) {
12
+ export async function compressImage(state, data, options) {
14
13
  var _a, _b;
15
- const cacheHash = computeCacheHash(data, options);
16
- const imageFromCache = await getFromCache('img', cacheHash);
14
+ const cacheHash = computeCacheHash(state, data, options);
15
+ const imageFromCache = await getFromCache(state, 'img', cacheHash);
17
16
  if (imageFromCache) {
18
17
  return { data: imageFromCache.buffer, format: imageFromCache.meta };
19
18
  }
@@ -27,9 +26,10 @@ export async function compressImage(data, options) {
27
26
  return undefined;
28
27
  }
29
28
  let outputFormat;
29
+ const imageOptions = state.options.image;
30
30
  // Special case for svg
31
31
  if (meta.format === 'svg') {
32
- if (!config.image.svg.optimization)
32
+ if (!imageOptions.svg.optimization)
33
33
  return undefined;
34
34
  try {
35
35
  const output = svgo(data.toString(), {
@@ -60,16 +60,16 @@ export async function compressImage(data, options) {
60
60
  if (toFormat === 'unchanged') {
61
61
  switch (meta.format) {
62
62
  case 'png':
63
- sharpFile = sharpFile.png(config.image.png.options || {});
63
+ sharpFile = sharpFile.png(imageOptions.png.options || {});
64
64
  outputFormat = 'png';
65
65
  break;
66
66
  case 'jpeg':
67
67
  case 'jpg':
68
- sharpFile = sharpFile.jpeg(config.image.jpeg.options || {});
68
+ sharpFile = sharpFile.jpeg(imageOptions.jpeg.options || {});
69
69
  outputFormat = 'jpg';
70
70
  break;
71
71
  case 'webp':
72
- sharpFile = sharpFile.webp(createWebpOptions(config.image.webp.options_lossly) || {});
72
+ sharpFile = sharpFile.webp(createWebpOptions(imageOptions.webp.options_lossly) || {});
73
73
  outputFormat = 'webp';
74
74
  break;
75
75
  case 'heif':
@@ -83,17 +83,17 @@ export async function compressImage(data, options) {
83
83
  // To format
84
84
  switch (toFormat) {
85
85
  case 'jpeg':
86
- sharpFile = sharpFile.jpeg({ ...config.image.jpeg.options } || {});
86
+ sharpFile = sharpFile.jpeg({ ...imageOptions.jpeg.options } || {});
87
87
  outputFormat = 'jpg';
88
88
  break;
89
89
  case 'png':
90
- sharpFile = sharpFile.png({ ...config.image.png.options } || {});
90
+ sharpFile = sharpFile.png({ ...imageOptions.png.options } || {});
91
91
  outputFormat = 'png';
92
92
  break;
93
93
  case 'webp':
94
94
  sharpFile = sharpFile.webp(createWebpOptions(meta.format === 'png'
95
- ? config.image.webp.options_lossless
96
- : config.image.webp.options_lossly));
95
+ ? imageOptions.webp.options_lossless
96
+ : imageOptions.webp.options_lossly));
97
97
  outputFormat = 'webp';
98
98
  break;
99
99
  case 'avif':
@@ -125,7 +125,7 @@ export async function compressImage(data, options) {
125
125
  format: outputFormat,
126
126
  data: await sharpFile.toBuffer(),
127
127
  };
128
- await addToCache('img', cacheHash, {
128
+ await addToCache(state, 'img', cacheHash, {
129
129
  buffer: outputImage.data,
130
130
  meta: outputImage.format,
131
131
  });
@@ -1 +1,2 @@
1
- export declare function compressJS(originalCode: string): Promise<string>;
1
+ import { GlobalState } from '../state.js';
2
+ export declare function compressJS({ options }: GlobalState, originalCode: string): Promise<string>;
@@ -1,9 +1,8 @@
1
1
  import swc from '@swc/core';
2
2
  import * as esbuild from 'esbuild';
3
- import config from '../config.js';
4
- export async function compressJS(originalCode) {
3
+ export async function compressJS({ options }, originalCode) {
5
4
  let resultCode = originalCode;
6
- switch (config.js.compressor) {
5
+ switch (options.js.compressor) {
7
6
  case 'esbuild':
8
7
  resultCode = (await esbuild.transform(originalCode, {
9
8
  minify: true,
package/dist/config.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- declare const options: import("./config-types.js").Options;
2
- export declare function fast(): void;
3
- export declare function loadConfig(): Promise<void>;
4
- export default options;
1
+ import { GlobalState } from './state.js';
2
+ export declare function fast(state: GlobalState): void;
3
+ export declare function loadConfig(state: GlobalState): Promise<void>;
package/dist/config.js CHANGED
@@ -3,16 +3,18 @@ import load from '@proload/core';
3
3
  import deepmerge from 'deepmerge';
4
4
  import default_options from './config-default.js';
5
5
  import fast_options_override from './config-fast.js';
6
- const options = default_options;
7
- export function fast() {
8
- Object.assign(options, deepmerge(options, fast_options_override));
6
+ import { loadConfigCSS } from './compressors/css.js';
7
+ export function fast(state) {
8
+ const options = default_options;
9
+ Object.assign(state.options, deepmerge(options, fast_options_override));
9
10
  }
10
- export async function loadConfig() {
11
+ export async function loadConfig(state) {
12
+ const options = default_options;
11
13
  const proload = await load('jampack', { mustExist: false });
12
14
  if (proload) {
13
15
  console.log('Merging default config with:');
14
16
  console.log(JSON.stringify(proload.value, null, 2));
15
- Object.assign(options, deepmerge(options, proload.value));
17
+ Object.assign(state.options, deepmerge(options, proload.value));
16
18
  }
19
+ loadConfigCSS(state);
17
20
  }
18
- export default options;
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from 'commander';
2
+ import { Command } from '@commander-js/extra-typings';
3
3
  import { compressFolder } from './compress.js';
4
4
  import { optimize } from './optimize.js';
5
- import $state from './state.js';
5
+ import { GlobalState } from './state.js';
6
6
  import { table } from 'table';
7
7
  import { formatBytes } from './utils.js';
8
- import config, { fast, loadConfig } from './config.js';
8
+ import { fast, loadConfig } from './config.js';
9
9
  import { printTitle } from './logger.js';
10
10
  import { exit } from 'process';
11
11
  import kleur from 'kleur';
@@ -13,7 +13,6 @@ import { cleanCache } from './cache.js';
13
13
  import { VERSION } from './packagejson.js';
14
14
  import { mkdirSync } from 'fs';
15
15
  import { join } from 'path';
16
- import { loadConfig as loadConfigCSS } from './compressors/css.js';
17
16
  const logo = ` __ __
18
17
  |__|____ _____ ___________ ____ | | __
19
18
  | \\__ \\ / \\\\____ \\__ \\ _/ ___\\| |/ /
@@ -43,9 +42,10 @@ program
43
42
  .option('--cleancache', 'Clean cache before running')
44
43
  .option('--nocache', 'Run with no use of cache')
45
44
  .action(async (dir, options) => {
45
+ const state = new GlobalState();
46
46
  // Arguments
47
- $state.dir = dir;
48
- $state.args = options;
47
+ state.dir = dir;
48
+ state.args = options;
49
49
  // Print options
50
50
  if (options) {
51
51
  console.log('Options:');
@@ -53,13 +53,13 @@ program
53
53
  console.log('');
54
54
  }
55
55
  // Override default config with config file
56
- await loadConfig();
56
+ await loadConfig(state);
57
57
  // Override config with fast options if set
58
58
  if (options.fast) {
59
- fast();
59
+ fast(state);
60
60
  }
61
61
  // Clean cache
62
- await cleanCache(options.cleancache);
62
+ await cleanCache(state, options.cleancache);
63
63
  // Make _jampack folder
64
64
  try {
65
65
  mkdirSync(join(dir, '_jampack'));
@@ -68,28 +68,26 @@ program
68
68
  console.error('Folder `_jampack` is present in target folder. This means that jampack has already processed this folder. You should always run jampack on clean build of the static website.');
69
69
  exit(1);
70
70
  }
71
- // Inject config into modules
72
- loadConfigCSS(config);
73
71
  if (!options.onlycomp) {
74
72
  printTitle('PASS 1 - Optimizing');
75
73
  console.time('Done');
76
- await optimize(options.include, options.exclude);
74
+ await optimize(state, options.include, options.exclude);
77
75
  console.timeEnd('Done');
78
76
  }
79
77
  if (!options.onlyoptim && !options.fast) {
80
78
  printTitle('PASS 2 - Compressing the rest');
81
79
  console.time('Done');
82
- await compressFolder(options.exclude);
80
+ await compressFolder(state, options.exclude);
83
81
  console.timeEnd('Done');
84
82
  }
85
- printSummary();
86
- printIssues();
87
- if (options.fail && $state.issues.size > 0) {
83
+ printSummary(state);
84
+ printIssues(state);
85
+ if (options.fail && state.issues.size > 0) {
88
86
  exit(1);
89
87
  }
90
88
  });
91
89
  program.parse();
92
- function printSummary() {
90
+ function printSummary($state) {
93
91
  if ($state.summary.nbFiles > 0) {
94
92
  printTitle('Summary');
95
93
  const dataTable = [
@@ -141,22 +139,22 @@ function printSummary() {
141
139
  console.log(table(dataTable, config));
142
140
  }
143
141
  }
144
- function printIssues() {
142
+ function printIssues(state) {
145
143
  let issueCount = 0;
146
- if ($state.issues.size === 0) {
144
+ if (state.issues.size === 0) {
147
145
  printTitle('✔ No issues');
148
146
  }
149
147
  else {
150
148
  printTitle('Issues', kleur.bgRed);
151
149
  console.log('');
152
- for (let [file, list] of $state.issues) {
150
+ for (let [file, list] of state.issues) {
153
151
  console.log('▶ ' + file + '\n');
154
152
  list.forEach((issue) => {
155
153
  issueCount++;
156
154
  console.log(`${kleur.bgYellow(` ${issue.type} `)} ${issue.msg}\n`);
157
155
  });
158
156
  }
159
- printTitle(`${issueCount} issue(s) over ${$state.issues.size} files`, kleur.bgYellow);
157
+ printTitle(`${issueCount} issue(s) over ${state.issues.size} files`, kleur.bgYellow);
160
158
  console.log('');
161
159
  }
162
160
  }
@@ -1 +1,2 @@
1
- export declare function optimize(include?: string, exclude?: string): Promise<void>;
1
+ import { GlobalState } from './state.js';
2
+ export declare function optimize(state: GlobalState, include?: string, exclude?: string): Promise<void>;
package/dist/optimize.js CHANGED
@@ -4,10 +4,8 @@ import * as fs 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';
7
- import config from './config.js';
8
7
  import { compressImage, } from './compressors/images.js';
9
8
  import svgToMiniDataURI from 'mini-svg-data-uri';
10
- import $state from './state.js';
11
9
  import kleur from 'kleur';
12
10
  import ora from 'ora';
13
11
  import { isLocal, Resource, translateSrc } from './utils/resource.js';
@@ -25,9 +23,9 @@ function getIntAttr(img, attr) {
25
23
  return;
26
24
  return parsed;
27
25
  }
28
- async function analyse(file) {
26
+ async function analyse(state, file) {
29
27
  console.log('▶ ' + file);
30
- const html = (await fs.readFile(path.join($state.dir, file))).toString();
28
+ const html = (await fs.readFile(path.join(state.dir, file))).toString();
31
29
  if (!html.includes('<html'))
32
30
  return;
33
31
  const $ = cheerio.load(html, { sourceCodeLocationInfo: true });
@@ -46,10 +44,10 @@ async function analyse(file) {
46
44
  const isAboveTheFold = isImgAboveTheFold(img, imgElement, theFold);
47
45
  img.removeAttr(ABOVE_FOLD_DATA_ATTR);
48
46
  try {
49
- await processImage(file, img, isAboveTheFold);
47
+ await processImage(state, file, img, isAboveTheFold);
50
48
  }
51
49
  catch (e) {
52
- $state.reportIssue(file, {
50
+ state.reportIssue(file, {
53
51
  type: 'erro',
54
52
  msg: e.message ||
55
53
  `Unexpected error while processing image: ${JSON.stringify(e)}`,
@@ -59,7 +57,7 @@ async function analyse(file) {
59
57
  // Reset spinner
60
58
  spinnerImg.text = kleur.dim(`<img> [${imgsArray.length}/${imgsArray.length}]`);
61
59
  // Notify issues
62
- const issues = $state.issues.get(file);
60
+ const issues = state.issues.get(file);
63
61
  if (issues) {
64
62
  spinnerImg.fail();
65
63
  console.log(kleur.red(` ${issues.length} issue${issues.length > 1 ? 's' : ''}`));
@@ -82,7 +80,7 @@ async function analyse(file) {
82
80
  await processIframe(file, $, ifElement, isAboveTheFold);
83
81
  }
84
82
  catch (e) {
85
- $state.reportIssue(file, {
83
+ state.reportIssue(file, {
86
84
  type: 'erro',
87
85
  msg: e.message ||
88
86
  `Unexpected error while processing image: ${JSON.stringify(e)}`,
@@ -104,7 +102,8 @@ async function analyse(file) {
104
102
  const heads = $('head'); // always exists because doc loaded with isDocument=true (default)
105
103
  const charsetElements$ = heads.find('meta[charset]');
106
104
  const wasCharsetFirst = !charsetElements$.prev().length;
107
- if (config.html.add_css_reset_as === 'inline') {
105
+ const { options } = state;
106
+ if (options.html.add_css_reset_as === 'inline') {
108
107
  prependToHead += `<style>:where(img){height:auto;}</style>`;
109
108
  }
110
109
  if (prependToHead || appendToHead) {
@@ -115,7 +114,7 @@ async function analyse(file) {
115
114
  }
116
115
  switch (charsetElements$.length) {
117
116
  case 0:
118
- $state.reportIssue(file, {
117
+ state.reportIssue(file, {
119
118
  type: 'fix',
120
119
  msg: 'Adding missing <meta charset="utf-8"> to the top of the <head>',
121
120
  });
@@ -123,7 +122,7 @@ async function analyse(file) {
123
122
  break;
124
123
  case 1:
125
124
  if (!wasCharsetFirst) {
126
- $state.reportIssue(file, {
125
+ state.reportIssue(file, {
127
126
  type: 'perf',
128
127
  msg: 'Moving <meta charset> to the top of the <head>',
129
128
  });
@@ -132,7 +131,7 @@ async function analyse(file) {
132
131
  heads.prepend(charsetElements$);
133
132
  break;
134
133
  default:
135
- $state.reportIssue(file, {
134
+ state.reportIssue(file, {
136
135
  type: 'fix',
137
136
  msg: 'Multiple <meta charset> found in the <head>: taking only the first one and deleting the others',
138
137
  });
@@ -142,8 +141,8 @@ async function analyse(file) {
142
141
  // Add to <body>
143
142
  //
144
143
  let appendToBody = '';
145
- if (config.misc.prefetch_links === 'in-viewport') {
146
- appendToBody += await prefetch_links_in_viewport(file);
144
+ if (options.misc.prefetch_links === 'in-viewport') {
145
+ appendToBody += await prefetch_links_in_viewport(state, file);
147
146
  }
148
147
  if (appendToBody) {
149
148
  const body = $('body');
@@ -156,16 +155,16 @@ async function analyse(file) {
156
155
  let htmlResult = $.html();
157
156
  // Inline critical css
158
157
  //
159
- if (config.css.inline_critical_css) {
158
+ if (options.css.inline_critical_css) {
160
159
  try {
161
- htmlResult = await inlineCriticalCss($state.dir, htmlResult);
160
+ htmlResult = await inlineCriticalCss(state.dir, htmlResult);
162
161
  }
163
162
  catch (e) {
164
163
  console.warn('Fail to inline critical CSS', e);
165
164
  }
166
165
  }
167
- if (!$state.args.nowrite) {
168
- await fs.writeFile(path.join($state.dir, file), htmlResult);
166
+ if (!state.args.nowrite) {
167
+ await fs.writeFile(path.join(state.dir, file), htmlResult);
169
168
  }
170
169
  }
171
170
  function isImgAboveTheFold(img, imgElement, theFold) {
@@ -200,7 +199,7 @@ function getTheFold($) {
200
199
  }
201
200
  return 0;
202
201
  }
203
- async function processImage(htmlfile, img, isAboveTheFold) {
202
+ async function processImage(state, htmlfile, img, isAboveTheFold) {
204
203
  var _a, _b;
205
204
  /*
206
205
  * Attribute 'src'
@@ -214,12 +213,13 @@ async function processImage(htmlfile, img, isAboveTheFold) {
214
213
  // Let's not mess with it and hope it's well done
215
214
  return; // No warnings
216
215
  }
217
- $state.reportIssue(htmlfile, {
216
+ state.reportIssue(htmlfile, {
218
217
  type: 'warn',
219
218
  msg: `Missing [src] on img - processing skipped.`,
220
219
  });
221
220
  return;
222
221
  }
222
+ const config = state.options;
223
223
  if (!isIncluded(attrib_src, config.image.src_include, config.image.src_exclude)) {
224
224
  // Setup to ignore
225
225
  return;
@@ -229,7 +229,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
229
229
  */
230
230
  const attrib_alt = img.attr('alt');
231
231
  if (attrib_alt === undefined) {
232
- $state.reportIssue(htmlfile, {
232
+ state.reportIssue(htmlfile, {
233
233
  type: 'a11y',
234
234
  msg: `Missing [alt] on img src="${attrib_src}" - Adding alt="" meanwhile.`,
235
235
  });
@@ -261,7 +261,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
261
261
  // Don't touch it
262
262
  break;
263
263
  default:
264
- $state.reportIssue(htmlfile, {
264
+ state.reportIssue(htmlfile, {
265
265
  type: 'invalid',
266
266
  msg: `Invalid [loading]="${attr_loading}" on img src="${attrib_src}"`,
267
267
  });
@@ -294,7 +294,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
294
294
  break;
295
295
  let attrib_width = getIntAttr(img, 'width');
296
296
  if (!attrib_width) {
297
- $state.reportIssue(htmlfile, {
297
+ state.reportIssue(htmlfile, {
298
298
  type: 'warn',
299
299
  msg: `Missing or malformed'width' attribute for image ${attrib_src}, unable to perform CDN transform`,
300
300
  });
@@ -302,13 +302,13 @@ async function processImage(htmlfile, img, isAboveTheFold) {
302
302
  }
303
303
  let attrib_height = getIntAttr(img, 'height');
304
304
  if (!attrib_height) {
305
- $state.reportIssue(htmlfile, {
305
+ state.reportIssue(htmlfile, {
306
306
  type: 'warn',
307
307
  msg: `Missing or malformed 'height' attribute for image ${attrib_src}, unable to perform CDN transform`,
308
308
  });
309
309
  return;
310
310
  }
311
- const new_srcset = await generateSrcSetForCdn(attrib_src, cdnTransformer, attrib_width, attrib_height);
311
+ const new_srcset = await generateSrcSetForCdn(state, attrib_src, cdnTransformer, attrib_width, attrib_height);
312
312
  if (new_srcset !== null) {
313
313
  img.attr('srcset', new_srcset);
314
314
  }
@@ -326,11 +326,11 @@ async function processImage(htmlfile, img, isAboveTheFold) {
326
326
  if (!isIncluded(attrib_src, config.image.external.src_include, config.image.external.src_exclude))
327
327
  break;
328
328
  try {
329
- attrib_src = await downloadExternalImage(htmlfile, attrib_src);
329
+ attrib_src = await downloadExternalImage(state, htmlfile, attrib_src);
330
330
  img.attr('src', attrib_src);
331
331
  }
332
332
  catch (e) {
333
- $state.reportIssue(htmlfile, {
333
+ state.reportIssue(htmlfile, {
334
334
  type: 'warn',
335
335
  msg: `Failed to download image: ${attrib_src} - ${e.message}`,
336
336
  });
@@ -342,10 +342,10 @@ async function processImage(htmlfile, img, isAboveTheFold) {
342
342
  /*
343
343
  * Loading image
344
344
  */
345
- const originalImage = await Resource.loadResource($state.dir, htmlfile, attrib_src);
345
+ const originalImage = await Resource.loadResource(state.dir, htmlfile, attrib_src);
346
346
  // No file -> give up
347
347
  if (!originalImage) {
348
- $state.reportIssue(htmlfile, {
348
+ state.reportIssue(htmlfile, {
349
349
  type: 'erro',
350
350
  msg: `Can't find img on disk src="${attrib_src}"`,
351
351
  });
@@ -369,7 +369,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
369
369
  : 'webp';
370
370
  }
371
371
  if (config.image.compress) {
372
- newImage = await compressImage(await originalImage.getData(), {
372
+ newImage = await compressImage(state, await originalImage.getData(), {
373
373
  toFormat: srcToFormat,
374
374
  resize: { width: config.image.srcset_max_width },
375
375
  });
@@ -378,13 +378,13 @@ async function processImage(htmlfile, img, isAboveTheFold) {
378
378
  const newFilename = path.join(path.dirname(originalImage.filePathAbsolute), path.basename(originalImage.filePathAbsolute, path.extname(originalImage.filePathAbsolute)) + `.${newImage.format}`);
379
379
  const newSrc = path.join(path.dirname(attrib_src), path.basename(attrib_src, path.extname(attrib_src)) +
380
380
  `.${newImage.format}`);
381
- if (!$state.compressedFiles.has(newFilename) && !$state.args.nowrite) {
381
+ if (!state.compressedFiles.has(newFilename) && !state.args.nowrite) {
382
382
  fs.writeFile(newFilename, newImage.data);
383
383
  }
384
384
  // Mark new file as compressed
385
- $state.compressedFiles.add(newFilename);
385
+ state.compressedFiles.add(newFilename);
386
386
  // Report compression result
387
- $state.reportSummary({
387
+ state.reportSummary({
388
388
  action: newFilename !== originalImage.filePathAbsolute
389
389
  ? `${await originalImage.getExt()}->${newImage.format}`
390
390
  : path.extname(originalImage.filePathAbsolute),
@@ -397,7 +397,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
397
397
  // Drop new Image
398
398
  newImage = undefined;
399
399
  // Report non-compression
400
- $state.reportSummary({
400
+ state.reportSummary({
401
401
  action: path.extname(originalImage.filePathAbsolute),
402
402
  originalSize: await originalImage.getLen(),
403
403
  compressedSize: await originalImage.getLen(),
@@ -437,7 +437,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
437
437
  img.attr('src', datauri);
438
438
  img.removeAttr('loading');
439
439
  img.removeAttr('decoding');
440
- $state.reportSummary({
440
+ state.reportSummary({
441
441
  action: `${imageToEmbed.format}->embed`,
442
442
  originalSize: await originalImage.getLen(),
443
443
  compressedSize: imageToEmbed.data.length,
@@ -454,7 +454,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
454
454
  /*
455
455
  * Attribute 'width' & 'height'
456
456
  */
457
- const [w, h] = await setImageSize(htmlfile, img, originalImage);
457
+ const [w, h] = await setImageSize(state, htmlfile, img, originalImage);
458
458
  if (isEmbed) {
459
459
  // Image is embed, no need for more processing
460
460
  return;
@@ -479,7 +479,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
479
479
  // of the srcset
480
480
  }
481
481
  else {
482
- const new_srcset = await generateSrcSet(htmlfile, originalImage, img.attr('src'), imageLengthToBeatInSrcSet, { toFormat: srcToFormat });
482
+ const new_srcset = await generateSrcSet(state, htmlfile, originalImage, img.attr('src'), imageLengthToBeatInSrcSet, { toFormat: srcToFormat });
483
483
  if (new_srcset !== null) {
484
484
  img.attr('srcset', new_srcset);
485
485
  }
@@ -533,7 +533,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
533
533
  // Ignore the creation of sources that already exist
534
534
  continue;
535
535
  }
536
- const srcset = await generateSrcSet(htmlfile, originalImage, undefined, undefined, {
536
+ const srcset = await generateSrcSet(state, htmlfile, originalImage, undefined, undefined, {
537
537
  toFormat: s.format,
538
538
  });
539
539
  if (!srcset) {
@@ -547,7 +547,7 @@ async function processImage(htmlfile, img, isAboveTheFold) {
547
547
  }
548
548
  }
549
549
  const isIncluded = (src, includeConf, excludeConf) => !!src.match(includeConf) && (!excludeConf || !src.match(excludeConf));
550
- async function _generateSrcSet(startSrc, imageWidth, imageHeight, transformSrc) {
550
+ async function _generateSrcSet({ options }, startSrc, imageWidth, imageHeight, transformSrc) {
551
551
  // Start from original image
552
552
  let new_srcset = '';
553
553
  if (!imageWidth || !imageHeight) {
@@ -557,8 +557,8 @@ async function _generateSrcSet(startSrc, imageWidth, imageHeight, transformSrc)
557
557
  // Start reduction
558
558
  const step = 300; //px
559
559
  let valueW = !startSrc ? imageWidth : imageWidth - step;
560
- valueW = Math.min(valueW, config.image.srcset_max_width);
561
- while (valueW >= config.image.srcset_min_width) {
560
+ valueW = Math.min(valueW, options.image.srcset_max_width);
561
+ while (valueW >= options.image.srcset_min_width) {
562
562
  let src = await transformSrc(valueW);
563
563
  if (src) {
564
564
  new_srcset += `, ${src} ${valueW}w`;
@@ -573,7 +573,7 @@ async function _generateSrcSet(startSrc, imageWidth, imageHeight, transformSrc)
573
573
  }
574
574
  return null;
575
575
  }
576
- async function generateSrcSet(htmlfile, originalImage, startSrc, startSrcLength, options) {
576
+ async function generateSrcSet(state, htmlfile, originalImage, startSrc, startSrcLength, options) {
577
577
  const ext = path.extname(originalImage.src);
578
578
  const fullbasename = originalImage.src.slice(0, -ext.length);
579
579
  const imageSrc = (addition) => {
@@ -586,12 +586,12 @@ async function generateSrcSet(htmlfile, originalImage, startSrc, startSrcLength,
586
586
  const imageWidth = (meta === null || meta === void 0 ? void 0 : meta.width) || 0;
587
587
  const imageHeight = (meta === null || meta === void 0 ? void 0 : meta.height) || 0;
588
588
  let previousImageSize = startSrcLength || Number.MAX_VALUE;
589
- return _generateSrcSet(startSrc, imageWidth, imageHeight, async (valueW) => {
589
+ return _generateSrcSet(state, startSrc, imageWidth, imageHeight, async (valueW) => {
590
590
  const src = imageSrc(`@${valueW}w`);
591
- const absoluteFilename = translateSrc($state.dir, path.dirname(htmlfile), src);
591
+ const absoluteFilename = translateSrc(state.dir, path.dirname(htmlfile), src);
592
592
  // Don't generate srcset file twice
593
- if (!$state.compressedFiles.has(absoluteFilename)) {
594
- const compressedImage = await compressImage(await originalImage.getData(), { ...options, resize: { width: valueW } });
593
+ if (!state.compressedFiles.has(absoluteFilename)) {
594
+ const compressedImage = await compressImage(state, await originalImage.getData(), { ...options, resize: { width: valueW } });
595
595
  if (!(compressedImage === null || compressedImage === void 0 ? void 0 : compressedImage.data) ||
596
596
  compressedImage.data.length >= previousImageSize) {
597
597
  // New image is not compressed or bigger than previous image in srcset
@@ -600,20 +600,20 @@ async function generateSrcSet(htmlfile, originalImage, startSrc, startSrcLength,
600
600
  }
601
601
  else {
602
602
  // Write file
603
- if (!$state.args.nowrite) {
603
+ if (!state.args.nowrite) {
604
604
  fs.writeFile(absoluteFilename, compressedImage.data);
605
605
  }
606
606
  // Set new previous size to beat
607
607
  previousImageSize = compressedImage.data.length;
608
608
  // Add file to list avoid recompression
609
- $state.compressedFiles.add(absoluteFilename);
609
+ state.compressedFiles.add(absoluteFilename);
610
610
  }
611
611
  }
612
612
  return src;
613
613
  });
614
614
  }
615
- async function generateSrcSetForCdn(startSrc, cdnTransformer, imageWidth, imageHeight) {
616
- return _generateSrcSet('', imageWidth, imageHeight, (valueW) => {
615
+ async function generateSrcSetForCdn(state, startSrc, cdnTransformer, imageWidth, imageHeight) {
616
+ return _generateSrcSet(state, '', imageWidth, imageHeight, (valueW) => {
617
617
  var _a, _b;
618
618
  return (_b = (_a = cdnTransformer({
619
619
  url: startSrc,
@@ -621,19 +621,19 @@ async function generateSrcSetForCdn(startSrc, cdnTransformer, imageWidth, imageH
621
621
  })) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.replace(UNPIC_DEFAULT_HOST_REGEX, '/');
622
622
  });
623
623
  }
624
- async function setImageSize(htmlfile, img, image) {
624
+ async function setImageSize(state, htmlfile, img, image) {
625
625
  let width = img.attr('width');
626
626
  let height = img.attr('height');
627
627
  let width_new = undefined;
628
628
  let height_new = undefined;
629
629
  const img_fmt = await image.getExt();
630
- if (img_fmt === 'svg' && !config.image.svg.add_width_and_height) {
630
+ if (img_fmt === 'svg' && !state.options.image.svg.add_width_and_height) {
631
631
  return [];
632
632
  }
633
633
  // Check valid values
634
634
  if (width !== undefined) {
635
635
  if (!isNumeric(width)) {
636
- $state.reportIssue(htmlfile, {
636
+ state.reportIssue(htmlfile, {
637
637
  type: 'fix',
638
638
  msg: `Invalid width attribute format: "${width}" - overriding for ${image.src}`,
639
639
  });
@@ -642,7 +642,7 @@ async function setImageSize(htmlfile, img, image) {
642
642
  }
643
643
  if (height !== undefined) {
644
644
  if (!isNumeric(height)) {
645
- $state.reportIssue(htmlfile, {
645
+ state.reportIssue(htmlfile, {
646
646
  type: 'fix',
647
647
  msg: `Invalid height attribute format: "${height}" - overriding for ${image.src}`,
648
648
  });
@@ -750,13 +750,13 @@ async function processIframe(htmlfile, $, imgElement, isAboveTheFold) {
750
750
  iframe.attr('loading', 'lazy');
751
751
  }
752
752
  }
753
- export async function optimize(include, exclude) {
753
+ export async function optimize(state, include, exclude) {
754
754
  const glob = include ? [include] : ['**/*.{htm,html}'];
755
755
  if (exclude)
756
756
  glob.push('!' + exclude);
757
- const paths = await globby(glob, { cwd: $state.dir });
757
+ const paths = await globby(glob, { cwd: state.dir });
758
758
  // Sequential async
759
759
  for (const file of paths) {
760
- await analyse(file);
760
+ await analyse(state, file);
761
761
  }
762
762
  }
@@ -1,2 +1,3 @@
1
+ import { GlobalState } from '../state.js';
1
2
  import '../utils/polyfill-fetch.js';
2
- export declare function downloadExternalImage(htmlfile: string, href: string): Promise<string>;
3
+ export declare function downloadExternalImage(state: GlobalState, htmlfile: string, href: string): Promise<string>;
@@ -1,12 +1,11 @@
1
1
  import * as path from 'path';
2
2
  import * as fs from 'fs/promises';
3
- import $state from '../state.js';
4
3
  import { hashSync as hasha } from 'hasha';
5
4
  import { fileTypeFromBuffer } from 'file-type';
6
5
  import { addToCache, getFromCache } from '../cache.js';
7
6
  import { parse } from '../utils/cache-control-parser.js';
8
7
  import '../utils/polyfill-fetch.js';
9
- export async function downloadExternalImage(htmlfile, href) {
8
+ export async function downloadExternalImage(state, htmlfile, href) {
10
9
  var _a, _b, _c, _d, _e;
11
10
  const hash = hasha(href, {
12
11
  algorithm: 'md5',
@@ -15,7 +14,7 @@ export async function downloadExternalImage(htmlfile, href) {
15
14
  let buffer;
16
15
  let ext;
17
16
  // Image is in cache?
18
- const dataFromCache = await getFromCache('img-ext', hash);
17
+ const dataFromCache = await getFromCache(state, 'img-ext', hash);
19
18
  const cacheControl = (_a = dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.meta) === null || _a === void 0 ? void 0 : _a.CacheControl;
20
19
  if (dataFromCache && cacheControl) {
21
20
  const date = (_b = dataFromCache === null || dataFromCache === void 0 ? void 0 : dataFromCache.meta) === null || _b === void 0 ? void 0 : _b.Date;
@@ -64,7 +63,7 @@ export async function downloadExternalImage(htmlfile, href) {
64
63
  }
65
64
  else {
66
65
  // Add downloaded image to cache
67
- await addToCache('img-ext', hash, {
66
+ await addToCache(state, 'img-ext', hash, {
68
67
  buffer,
69
68
  meta: {
70
69
  Date: resp.headers.get('Date'),
@@ -97,7 +96,7 @@ export async function downloadExternalImage(htmlfile, href) {
97
96
  if (!ext)
98
97
  throw new Error('Unknown image format');
99
98
  const htmlFolder = path.dirname(htmlfile);
100
- const filename = path.relative(path.join($state.dir, htmlFolder), path.join($state.dir, `_jampack/${contentHash}.${ext}`));
101
- await fs.writeFile(path.join($state.dir, htmlFolder, filename), buffer);
99
+ const filename = path.relative(path.join(state.dir, htmlFolder), path.join(state.dir, `_jampack/${contentHash}.${ext}`));
100
+ await fs.writeFile(path.join(state.dir, htmlFolder, filename), buffer);
102
101
  return filename;
103
102
  }
@@ -1 +1,2 @@
1
- export declare function prefetch_links_in_viewport(html_file: string): Promise<string>;
1
+ import { GlobalState } from '../state.js';
2
+ export declare function prefetch_links_in_viewport(state: GlobalState, html_file: string): Promise<string>;
@@ -1,4 +1,3 @@
1
- import $state from '../state.js';
2
1
  import * as fs from 'fs/promises';
3
2
  import * as path from 'path';
4
3
  import { createRequire } from 'node:module';
@@ -6,13 +5,15 @@ const require = createRequire(import.meta.url);
6
5
  const src_filename = 'quicklink.mjs';
7
6
  const folder = `/_jampack/quicklink-2.3.0`;
8
7
  const url_loader = `${folder}/loader.js`;
9
- export async function prefetch_links_in_viewport(html_file) {
8
+ export async function prefetch_links_in_viewport(state, html_file) {
10
9
  const path_html = path.dirname('/' + html_file);
11
- const quickLinkDestination = path.join($state.dir, folder, src_filename);
12
- const payloadStored = await fs.access(quickLinkDestination).catch(() => false);
10
+ const quickLinkDestination = path.join(state.dir, folder, src_filename);
11
+ const payloadStored = await fs
12
+ .access(quickLinkDestination)
13
+ .catch(() => false);
13
14
  if (!payloadStored) {
14
- const path_loader = path.join($state.dir, url_loader);
15
- await fs.mkdir(path.join($state.dir, folder), { recursive: true });
15
+ const path_loader = path.join(state.dir, url_loader);
16
+ await fs.mkdir(path.join(state.dir, folder), { recursive: true });
16
17
  // Write loader
17
18
  const code_loader = `import { listen } from "./${src_filename}";
18
19
  listen();`;
package/dist/state.d.ts CHANGED
@@ -21,6 +21,8 @@ type Issue = {
21
21
  export declare class GlobalState {
22
22
  dir: string;
23
23
  args: Args;
24
+ options: import("./config-types.js").Options;
25
+ targets: import("lightningcss").Targets;
24
26
  compressedFiles: Set<string>;
25
27
  issues: Map<string, Issue[]>;
26
28
  summary: Summary;
@@ -28,5 +30,4 @@ export declare class GlobalState {
28
30
  reportIssue(sourceFile: string, issue: Issue): void;
29
31
  reportSummary(r: ReportItem): void;
30
32
  }
31
- declare const state: GlobalState;
32
- export default state;
33
+ export {};
package/dist/state.js CHANGED
@@ -1,7 +1,11 @@
1
+ import { defaultTargets } from './compressors/css.js';
2
+ import default_options from './config-default.js';
1
3
  export class GlobalState {
2
4
  constructor() {
3
5
  this.dir = 'dist';
4
6
  this.args = {};
7
+ this.options = default_options;
8
+ this.targets = defaultTargets();
5
9
  this.compressedFiles = new Set();
6
10
  this.issues = new Map();
7
11
  this.summary = {
@@ -23,9 +27,9 @@ export class GlobalState {
23
27
  reportSummary(r) {
24
28
  const isCompressed = r.compressedSize < r.originalSize ? 1 : 0;
25
29
  this.summary.nbFiles++;
26
- state.summary.nbFilesCompressed += isCompressed;
27
- state.summary.dataLenUncompressed += r.originalSize;
28
- state.summary.dataLenCompressed += r.compressedSize;
30
+ this.summary.nbFilesCompressed += isCompressed;
31
+ this.summary.dataLenUncompressed += r.originalSize;
32
+ this.summary.dataLenCompressed += r.compressedSize;
29
33
  if (r.action) {
30
34
  let summary = this.summaryByExtension[r.action];
31
35
  if (!summary) {
@@ -44,5 +48,3 @@ export class GlobalState {
44
48
  }
45
49
  }
46
50
  }
47
- const state = new GlobalState();
48
- export default state;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@divriots/jampack",
3
- "version": "0.24.4",
3
+ "version": "0.25.0",
4
4
  "cache-version": {
5
5
  "img": "v1",
6
6
  "img-ext": "v1"
@@ -26,6 +26,7 @@
26
26
  "./state": "./dist/state.js"
27
27
  },
28
28
  "dependencies": {
29
+ "@commander-js/extra-typings": "^12.0.0",
29
30
  "@divriots/cheerio": "1.0.0-rc.12",
30
31
  "@proload/core": "^0.3.3",
31
32
  "@swc/core": "^1.4.16",
@@ -40,7 +41,7 @@
40
41
  "hasha": "^6.0.0",
41
42
  "html-minifier-terser": "^7.2.0",
42
43
  "kleur": "^4.1.5",
43
- "lightningcss": "^1.24.1",
44
+ "lightningcss": "^1.25.1",
44
45
  "mini-svg-data-uri": "^1.4.4",
45
46
  "ora": "^8.0.1",
46
47
  "quicklink": "^2.3.0",
@@ -58,18 +59,17 @@
58
59
  "tslib": "^2.6.2",
59
60
  "typescript": "^5.4.5"
60
61
  },
62
+ "engines": {
63
+ "node": ">=14.0.0"
64
+ },
65
+ "bugs": "https://github.com/divriots/jampack/issues",
66
+ "keywords": [],
67
+ "types": "dist/index.d.ts",
61
68
  "scripts": {
62
69
  "watch": "pnpm build --watch",
63
70
  "try": "shx rm -fr demo && cp -R demo_drc demo && node ./dist/index.js ./demo --nocache",
64
71
  "build": "shx rm -rf dist && tsc -b",
65
72
  "lint": "eslint . --ext .ts --config .eslintrc",
66
- "prepublishOnly": "pnpm build",
67
73
  "cleanAllDotJampack": "find -s . | grep '.jampack$' | xargs rm -fr"
68
- },
69
- "engines": {
70
- "node": ">=14.0.0"
71
- },
72
- "bugs": "https://github.com/divriots/jampack/issues",
73
- "keywords": [],
74
- "types": "dist/index.d.ts"
74
+ }
75
75
  }