@jsenv/plugin-minification 1.7.9 → 1.7.10
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/package.json +2 -1
- package/src/js/js_minification.js +8 -5
- package/src/js/js_strip_comments.js +79 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/plugin-minification",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@jsenv/ast": "6.9.2",
|
|
25
|
+
"@jsenv/sourcemap": "1.4.2",
|
|
25
26
|
"@jsenv/urls": "2.9.10",
|
|
26
27
|
"html-minifier": "4.0.0",
|
|
27
28
|
"lightningcss": "1.33.0",
|
|
@@ -12,11 +12,14 @@ export const minifyJs = async (jsUrlInfo, options) => {
|
|
|
12
12
|
[url]: content,
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
// a map costs terser ~20% of its time, only when the kitchen keeps it
|
|
16
|
+
sourceMap: jsUrlInfo.context.sourcemapsEnabled
|
|
17
|
+
? {
|
|
18
|
+
...(sourcemap ? { content: JSON.stringify(sourcemap) } : {}),
|
|
19
|
+
asObject: true,
|
|
20
|
+
includeSources: true,
|
|
21
|
+
}
|
|
22
|
+
: false,
|
|
20
23
|
module: isJsModule,
|
|
21
24
|
// We need to preserve "new __InlineContent__()" calls to be able to recognize them
|
|
22
25
|
// after minification in order to version urls inside inline content text
|
|
@@ -1,28 +1,81 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createMagicSource } from "@jsenv/sourcemap";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
3
|
+
// Comments are taken out in place, leaving every line where it is: the line
|
|
4
|
+
// numbers a stack trace shows stay those of the source. A comment sharing its
|
|
5
|
+
// line with code is replaced by spaces, so the code keeps its columns too.
|
|
6
|
+
// A license notice stays (@license, @preserve): the code it covers is
|
|
7
|
+
// shipped, the notice must be too.
|
|
8
|
+
export const stripJsComments = (urlInfo) => {
|
|
9
|
+
const { content } = urlInfo;
|
|
10
|
+
const allComments = urlInfo.contentAst.comments || [];
|
|
11
|
+
const comments = allComments.filter((comment) => !mustKeepComment(comment));
|
|
12
|
+
const magicSource = createMagicSource(content);
|
|
13
|
+
// Whatever trails the last code (comments, blank lines) goes: the file
|
|
14
|
+
// ends right after its last token, the way a generated file does.
|
|
15
|
+
let tailStart = content.length;
|
|
16
|
+
const allCommentsFromEnd = allComments.slice().sort((a, b) => b.end - a.end);
|
|
17
|
+
let tailCommentIndex = 0;
|
|
18
|
+
while (true) {
|
|
19
|
+
while (tailStart > 0 && /\s/.test(content[tailStart - 1])) {
|
|
20
|
+
tailStart--;
|
|
21
|
+
}
|
|
22
|
+
const comment = allCommentsFromEnd[tailCommentIndex];
|
|
23
|
+
if (comment && comment.end === tailStart && !mustKeepComment(comment)) {
|
|
24
|
+
tailStart = comment.start;
|
|
25
|
+
tailCommentIndex++;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
if (tailStart === content.length && comments.length === 0) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (tailStart < content.length) {
|
|
34
|
+
magicSource.remove({ start: tailStart, end: content.length });
|
|
35
|
+
}
|
|
36
|
+
for (const comment of comments) {
|
|
37
|
+
const { start, end } = comment;
|
|
38
|
+
if (start >= tailStart) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const lineStart = content.lastIndexOf("\n", start - 1) + 1;
|
|
42
|
+
let lineEnd = content.indexOf("\n", end);
|
|
43
|
+
if (lineEnd === -1) {
|
|
44
|
+
lineEnd = content.length;
|
|
45
|
+
}
|
|
46
|
+
const before = content.slice(lineStart, start);
|
|
47
|
+
const after = content.slice(end, lineEnd);
|
|
48
|
+
const commentText = content.slice(start, end);
|
|
49
|
+
const lineBreaks = "\n".repeat(commentText.split("\n").length - 1);
|
|
50
|
+
if (before.trim() === "" && after.trim() === "") {
|
|
51
|
+
// alone on its line(s): they become empty lines
|
|
52
|
+
magicSource.replace({
|
|
53
|
+
start: lineStart,
|
|
54
|
+
end: lineEnd,
|
|
55
|
+
replacement: lineBreaks,
|
|
56
|
+
});
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (after.trim() === "") {
|
|
60
|
+
// ends the line: goes away with the spaces separating it from the code
|
|
61
|
+
const spacesBefore = before.length - before.trimEnd().length;
|
|
62
|
+
magicSource.replace({
|
|
63
|
+
start: start - spacesBefore,
|
|
64
|
+
end: lineEnd,
|
|
65
|
+
replacement: lineBreaks,
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// code follows on the same line
|
|
70
|
+
magicSource.replace({
|
|
71
|
+
start,
|
|
72
|
+
end,
|
|
73
|
+
replacement: commentText.replace(/[^\n]/g, " "),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return magicSource.toContentAndSourcemap();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const mustKeepComment = ({ text }) => {
|
|
80
|
+
return text.includes("@license") || text.includes("@preserve");
|
|
28
81
|
};
|