-
Notifications
You must be signed in to change notification settings - Fork 3
/
web.js
134 lines (120 loc) · 4.76 KB
/
web.js
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* Minified Web Version Creation Tool
*
* Creates a minified version of the P4 Assembler and Simulator ready for use in a web server.
*
* To create the minified version: node web.js
*
* As folder named 'web' will be created with all the contents that should be put in the web server.
*
* @author Dinis Madeira (dinismadeira@tecnico.ulisboa.pt)
* @version 2018
*/
'use strict';
const initTime = Date.now();
const fs = require('fs-extra');
const CleanCSS = require('clean-css');
const minifyHTML = require('html-minifier').minify;
const UglifyJS = require("uglify-es");
const minifyHTMLLiterals = require('minify-html-literals').minifyHTMLLiterals
const parseElement = element => {
const attrs = {};
const attrMatches = element.match(/<\w+ (.+?)(?:><\/\w+>|>)/i);
const attrString = attrMatches[1];
const attrPairs = attrString.match(/\w+(=("[^"]+"|[^ ]))?/g);
for (const attrPair of attrPairs) {
const attrMatches = attrPair.match(/(\w+)(?:=("[^"]+"|[^ ]))?/);
const attrName = attrMatches[1];
const attrValue = (attrMatches[2] || "").replace(/^"(.+)"$/, '$1');
attrs[attrName] = attrValue;
}
return attrs;
};
const process = async () => {
const contents = (await fs.readFile('index.html')).toString();
const filesPromise = [];
const files = [];
const minified = {script: [], defer: [], css: [], index: contents};
const scriptMatches = contents.match(/<script .+?><\/script>/gi);
for (const element of scriptMatches) {
const attrs = parseElement(element);
if (attrs.src) {
minified.index = minified.index.replace(element, '');
filesPromise.push(fs.readFile(attrs.src));
files.push({type: 'script', attrs: attrs});
}
}
const linkMatches = contents.match(/<link .+?\/?>/gi);
for (const element of linkMatches) {
const attrs = parseElement(element);
if (attrs.rel == 'stylesheet' && attrs.href) {
minified.index = minified.index.replace(element, '');
filesPromise.push(fs.readFile(attrs.href));
files.push({type: 'css', attrs: attrs});
}
}
const filesContent = await Promise.all(filesPromise);
for (let i = 0; i < files.length; i++) {
const file = files[i];
const content = filesContent[i].toString();
if (file.type == 'css') minified.css.push(content);
else if ('defer' in file.attrs) minified.defer.push(content);
else minified.script.push(content);
}
const scriptSrc = `script-${initTime}.js`;
const deferSrc = `script-defer-${initTime}.js`;
const cssSrc = `styles-${initTime}.css`;
const rootDir = `web/`
const scriptFile = rootDir + `script.js`;
const deferFile = rootDir + `script-defer.js`;
const cssFile = rootDir + `styles.css`;
const htmFile = rootDir + `index.html`;
const UglifyJSOptions = {
compress: {
ecma: 6
}
};
const minifyScript = (file, content) => {
const minifiedLiterals = minifyHTMLLiterals(content, {fileName: ''});
const minified = UglifyJS.minify(minifiedLiterals ? minifiedLiterals.code : content, UglifyJSOptions);
return fs.writeFile(file, minified.code);
};
minified.index = minified.index.
replace(/<script>([^]+?)<\/script>/ig, (match, p1) => '<script>' + UglifyJS.minify(p1, UglifyJSOptions).code + '</script>').
replace(/<\/head>/, `
<link rel="stylesheet" href="${cssSrc}">
<script src="${scriptSrc}"></script>
<script src="${deferSrc}" defer></script>
</head>`);
const minifyHTMLOptions = {
collapseBooleanAttributes: true,
collapseInlineTagWhitespace: true,
collapseWhitespace: true,
conservativeCollapse: true,
decodeEntities: true,
removeAttributeQuotes: true,
removeComments: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortAttributes: true,
sortClassName: true,
useShortDoctype: true
};
// Create 'web' folder
if (!fs.existsSync(rootDir)){
fs.mkdirSync(rootDir);
}
// Write minified files and copy necessary folders
await Promise.all([
fs.copy('fonts', rootDir + 'fonts'),
fs.copy('demos', rootDir + 'demos'),
fs.writeFile(cssFile, new CleanCSS({}).minify(minified.css.join("\n")).styles),
minifyScript(scriptFile, minified.script.join("\n")),
minifyScript(deferFile, minified.defer.join("\n")),
fs.writeFile(htmFile, minifyHTML(minified.index, minifyHTMLOptions))
]);
console.log(`Completed in ${(Date.now() - initTime) / 1000} seconds.`);
};
process();