umberto 8.3.5 → 8.4.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/CHANGELOG.md +15 -11
- package/package.json +5 -3
- package/src/tasks/build-documentation.js +20 -12
- package/src/tasks/get-project-config.js +1 -0
- package/src/tasks/minify-html.js +54 -0
- package/src/tasks/minify-worker.js +27 -0
- package/src/tasks/validate-links.js +5 -1
- package/themes/umberto/src/gloria/js/components/hash-link.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
+
## [8.4.0](https://github.com/cksource/umberto/compare/v8.3.5...v8.4.0) (October 30, 2025)
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Minify output HTML to reduce file size and improve load performance.
|
|
9
|
+
|
|
10
|
+
The output is automatically minified during production builds to remove unnecessary whitespace and comments.
|
|
11
|
+
|
|
12
|
+
Minification is **disabled when using the `--dev` modifier**, ensuring the generated HTML remains readable for easier debugging and inspection.
|
|
13
|
+
|
|
14
|
+
### Other changes
|
|
15
|
+
|
|
16
|
+
* Umberto reads a project configuration once and passes it through the pipeline. Thanks to that, hooks can modify it, which affects a project's build.
|
|
17
|
+
|
|
18
|
+
|
|
4
19
|
## [8.3.5](https://github.com/cksource/umberto/compare/v8.3.4...v8.3.5) (October 29, 2025)
|
|
5
20
|
|
|
6
21
|
### Other changes
|
|
@@ -30,17 +45,6 @@ Changelog
|
|
|
30
45
|
|
|
31
46
|
* Update to TypeScript 5.3.
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
## [8.3.1](https://github.com/cksource/umberto/compare/v8.3.0...v8.3.1) (September 4, 2025)
|
|
35
|
-
|
|
36
|
-
### Bug fixes
|
|
37
|
-
|
|
38
|
-
* Fixed link styles not being applied to followup questions in `Kapa.ai` integration.
|
|
39
|
-
|
|
40
|
-
### Other changes
|
|
41
|
-
|
|
42
|
-
* Increased size of the modal in `Kapa.ai` integration.
|
|
43
|
-
|
|
44
48
|
---
|
|
45
49
|
|
|
46
50
|
To see all releases, visit the [release page](https://github.com/cksource/umberto/releases).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "umberto",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.0",
|
|
4
4
|
"description": "CKSource Documentation builder",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"@babel/core": "^7.18.10",
|
|
18
18
|
"@babel/preset-env": "^7.18.10",
|
|
19
19
|
"@ckeditor/jsdoc-plugins": "^43.0.0",
|
|
20
|
+
"@minify-html/node": "^0.17.1",
|
|
20
21
|
"babel-loader": "^10.0.0",
|
|
21
22
|
"cheerio": "^1.0.0",
|
|
22
23
|
"escape-string-regexp": "^4.0.0",
|
|
@@ -28,8 +29,8 @@
|
|
|
28
29
|
"hexo-generator-category": "^2.0.0",
|
|
29
30
|
"hexo-generator-index": "^4.0.0",
|
|
30
31
|
"hexo-generator-tag": "^2.0.0",
|
|
31
|
-
"hexo-renderer-pug": "^3.0.0",
|
|
32
32
|
"hexo-renderer-markdown-it-plus": "^1.0.5",
|
|
33
|
+
"hexo-renderer-pug": "^3.0.0",
|
|
33
34
|
"htmlparser2": "^10.0.0",
|
|
34
35
|
"javascript-stringify": "^2.1.0",
|
|
35
36
|
"jquery": "~3.7.1",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"sass": "^1.54.0",
|
|
47
48
|
"shiki": "^3.4.0",
|
|
48
49
|
"sitemap": "^8.0.0",
|
|
50
|
+
"tinypool": "^2.0.0",
|
|
49
51
|
"tippy.js": "^6.3.7",
|
|
50
52
|
"tree-model": "^1.0.7",
|
|
51
53
|
"upath": "^2.0.1",
|
|
@@ -71,6 +73,6 @@
|
|
|
71
73
|
]
|
|
72
74
|
},
|
|
73
75
|
"hexo": {
|
|
74
|
-
"version": "
|
|
76
|
+
"version": "8.0.0"
|
|
75
77
|
}
|
|
76
78
|
}
|
|
@@ -26,6 +26,7 @@ const createSitemapStep = require( './create-sitemap-step' );
|
|
|
26
26
|
const buildSnippets = require( './build-snippets' );
|
|
27
27
|
const copyProjectIcons = require( './copy-project-icons' );
|
|
28
28
|
const executeHooks = require( './execute-hooks' );
|
|
29
|
+
const minifyHtml = require( './minify-html' );
|
|
29
30
|
const umbertoVersion = require( '../../package.json' ).version;
|
|
30
31
|
|
|
31
32
|
const { parseLinks } = require( '../../scripts/utils/parselinks' );
|
|
@@ -49,6 +50,7 @@ const getFilePatternsToProcess = require( '../helpers/get-file-patterns-to-proce
|
|
|
49
50
|
* clean option can be used to clear the build directory or not.
|
|
50
51
|
* @param {Boolean} options.dev If true, it indicates a local build, skips minification, reuses already built files, allows to skip webpack.
|
|
51
52
|
* @param {Boolean} options.skipApi Skip rendering API docs.
|
|
53
|
+
* @param {Boolean} options.skipSdk Skip building SDK docs.
|
|
52
54
|
* @param {Boolean} options.skipLiveSnippets Skip building live code snippets.
|
|
53
55
|
* @param {Array.<String>|String} options.extraStyles Path/s to extra css.
|
|
54
56
|
* @param {Array.<String>|String} options.extraScripts Path/s to extra js.
|
|
@@ -69,6 +71,7 @@ module.exports = options => {
|
|
|
69
71
|
clean = !options.dev,
|
|
70
72
|
dev = false,
|
|
71
73
|
skipApi = false,
|
|
74
|
+
skipSdk = false,
|
|
72
75
|
skipLiveSnippets = false,
|
|
73
76
|
extraStyles = [],
|
|
74
77
|
extraScripts = [],
|
|
@@ -127,13 +130,14 @@ module.exports = options => {
|
|
|
127
130
|
} );
|
|
128
131
|
} )
|
|
129
132
|
.then( async () => {
|
|
130
|
-
const configs = await getProjectConfigs( rootPath, projectPaths );
|
|
133
|
+
const configs = await getProjectConfigs( rootPath, projectPaths, { skipLiveSnippets } );
|
|
131
134
|
|
|
132
135
|
return executeHooks( configs, 'beforeHexo' );
|
|
133
136
|
} )
|
|
134
137
|
.then( () => {
|
|
135
138
|
return buildProjects( rootPath, projectPaths, {
|
|
136
139
|
skipApi,
|
|
140
|
+
skipSdk,
|
|
137
141
|
skipLiveSnippets,
|
|
138
142
|
dev,
|
|
139
143
|
docSearch: mainConfig.docsearch,
|
|
@@ -205,6 +209,16 @@ module.exports = options => {
|
|
|
205
209
|
|
|
206
210
|
return Promise.resolve();
|
|
207
211
|
} )
|
|
212
|
+
// Minify HTML files.
|
|
213
|
+
.then( async () => {
|
|
214
|
+
if ( options.dev ) {
|
|
215
|
+
return Promise.resolve();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const outputDir = upath.relative( process.cwd(), hexoManager.getPublicDir() );
|
|
219
|
+
|
|
220
|
+
return minifyHtml( outputDir );
|
|
221
|
+
} )
|
|
208
222
|
// Links validation.
|
|
209
223
|
.then( async () => {
|
|
210
224
|
const projectConfigs = await getProjectConfigs( rootPath, projectPaths, {
|
|
@@ -233,12 +247,12 @@ module.exports = options => {
|
|
|
233
247
|
} );
|
|
234
248
|
} )
|
|
235
249
|
.then( async () => {
|
|
236
|
-
const projectConfigs = await getProjectConfigs( rootPath, projectPaths );
|
|
250
|
+
const projectConfigs = await getProjectConfigs( rootPath, projectPaths, { skipLiveSnippets } );
|
|
237
251
|
|
|
238
252
|
return createSitemapStep( { projectConfigs, verbose, mainConfig } );
|
|
239
253
|
} )
|
|
240
254
|
.then( async () => {
|
|
241
|
-
const configs = await getProjectConfigs( rootPath, projectPaths );
|
|
255
|
+
const configs = await getProjectConfigs( rootPath, projectPaths, { skipLiveSnippets } );
|
|
242
256
|
|
|
243
257
|
return executeHooks( configs, 'afterHexo' );
|
|
244
258
|
} )
|
|
@@ -396,15 +410,9 @@ async function getProjectConfigs( rootPath, projectPaths, options = {} ) {
|
|
|
396
410
|
const promises = projectPaths.map( async pPath => {
|
|
397
411
|
const projectRootPath = upath.join( rootPath, pPath );
|
|
398
412
|
|
|
399
|
-
return
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
...await getProjectConfig( projectRootPath, {
|
|
403
|
-
skipLiveSnippets: options.skipLiveSnippets
|
|
404
|
-
} ),
|
|
405
|
-
projectRootPath
|
|
406
|
-
}
|
|
407
|
-
);
|
|
413
|
+
return getProjectConfig( projectRootPath, {
|
|
414
|
+
skipLiveSnippets: options.skipLiveSnippets
|
|
415
|
+
} );
|
|
408
416
|
} );
|
|
409
417
|
|
|
410
418
|
return Promise.all( promises );
|
|
@@ -32,6 +32,7 @@ module.exports = async ( rootPath, options = {} ) => {
|
|
|
32
32
|
|
|
33
33
|
const config = getConfigurationFile( configPath );
|
|
34
34
|
|
|
35
|
+
config.projectRootPath = rootPath;
|
|
35
36
|
config.__configPath = configPath;
|
|
36
37
|
|
|
37
38
|
// Get the `realImportPath()` function. It displays an import path of a class below the class title.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const { join } = require( 'path' );
|
|
9
|
+
const { globSync } = require( 'fs' );
|
|
10
|
+
const { styleText } = require( 'util' );
|
|
11
|
+
const { default: TinyPool } = require( 'tinypool' );
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Minifies all HTML files under outputDir in parallel using tinypool.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} outputDir - base directory to search for *.html files
|
|
17
|
+
*/
|
|
18
|
+
module.exports = async function minifyHtml( outputDir ) {
|
|
19
|
+
const files = globSync( join( outputDir, '**', 'api', '**', '*.html' ) );
|
|
20
|
+
|
|
21
|
+
const pool = new TinyPool( {
|
|
22
|
+
runtime: 'child_process',
|
|
23
|
+
filename: require.resolve( './minify-worker.js' )
|
|
24
|
+
} );
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
console.log( 'Started HTML minification.' );
|
|
28
|
+
|
|
29
|
+
const results = await Promise.allSettled(
|
|
30
|
+
files.map( async file => {
|
|
31
|
+
try {
|
|
32
|
+
return await pool.run( file );
|
|
33
|
+
} catch ( err ) {
|
|
34
|
+
err.file = file;
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
} )
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const failed = results.filter( r => r.status === 'rejected' );
|
|
41
|
+
|
|
42
|
+
if ( failed.length > 0 ) {
|
|
43
|
+
failed.forEach( ( { reason } ) => {
|
|
44
|
+
console.error( styleText( 'redBright', `Minification failed for "${ reason.file }": ${ reason.message }` ) );
|
|
45
|
+
} );
|
|
46
|
+
|
|
47
|
+
throw new Error( `Minification failed for ${ failed.length } file(s).` );
|
|
48
|
+
}
|
|
49
|
+
} finally {
|
|
50
|
+
await pool.destroy();
|
|
51
|
+
|
|
52
|
+
console.log( 'Finished HTML minification.' );
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2017-2025, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const { readFileSync, writeFileSync } = require( 'fs' );
|
|
9
|
+
const minifier = require( '@minify-html/node' );
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Minifies HTML content.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} file - Path to the HTML file to minify.
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
module.exports = function( file ) {
|
|
18
|
+
const html = readFileSync( file );
|
|
19
|
+
|
|
20
|
+
const minified = minifier.minify( html, {
|
|
21
|
+
keep_comments: true,
|
|
22
|
+
minify_css: true,
|
|
23
|
+
minify_js: true
|
|
24
|
+
} );
|
|
25
|
+
|
|
26
|
+
writeFileSync( file, minified );
|
|
27
|
+
};
|
|
@@ -55,7 +55,11 @@ function collectLinks( pathsToFiles, options ) {
|
|
|
55
55
|
links.add( upath.resolve( filePath + '#' ) );
|
|
56
56
|
|
|
57
57
|
const content = fs.readFileSync( filePath, 'utf-8' );
|
|
58
|
-
|
|
58
|
+
// Extract both quoted and unquoted "id" attributes.
|
|
59
|
+
const ids = [
|
|
60
|
+
...Array.from( content.matchAll( /id="([^"]+)"/g ), m => m[ 1 ] ),
|
|
61
|
+
...Array.from( content.matchAll( /id=([^\s"'/>]+)/g ), m => m[ 1 ] )
|
|
62
|
+
];
|
|
59
63
|
|
|
60
64
|
for ( const id of ids ) {
|
|
61
65
|
if ( !isMaskedID( id ) && !ids.includes( 'icons-' ) ) {
|