-
Notifications
You must be signed in to change notification settings - Fork 14
/
index.js
96 lines (86 loc) · 2.82 KB
/
index.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
import { statSync, readFileSync, writeFileSync, readdirSync, unlinkSync } from 'fs';
import { relative, basename, sep as pathSeperator } from 'path';
import hasha from 'hasha';
// import cheerio from 'cheerio';
const cheerio = require('cheerio');
function traverse(dir, list) {
const dirList = readdirSync(dir);
dirList.forEach(node => {
const file = `${dir}/${node}`;
if (statSync(file).isDirectory()) {
traverse(file, list);
} else {
if (/\.js$/.test(file)) {
list.push({ type: 'js', file });
} else if (/\.css$/.test(file)) {
list.push({ type: 'css', file });
}
}
});
}
function isURL(url){
return /^(((https|http|ftp|rtsp|mms):)?\/\/)+[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/.test(url);
}
export default (opt = {}) => {
const { template, filename, externals, inject, defaultmode } = opt;
return {
name: 'html',
onwrite(config, data) {
const $ = cheerio.load(readFileSync(template).toString());
const head = $('head');
const body = $('body');
const { file } = config;
const fileList = [];
// relative('./', dest) will not be equal to dest when dest is a absolute path
const destPath = relative('./', file);
const firstDir = destPath.slice(0, destPath.indexOf(pathSeperator));
const destFile = `${firstDir}/${filename || basename(template)}`;
traverse(firstDir, fileList);
if (Array.isArray(externals)) {
let firstBundle = 0;
externals.forEach(function(node) {
if (node.pos === 'before') {
fileList.splice(firstBundle++, 0, node);
} else {
fileList.splice(fileList.length, 0, node);
}
})
}
fileList.forEach(node => {
let { type, file } = node;
let hash = '';
let code = '';
if (/\[hash\]/.test(file)) {
if (file === destPath) {
// data.code will remove the last line of the source code(//# sourceMappingURL=xxx), so it's needed to add this
code = data.code + `//# sourceMappingURL=${basename(file)}.map`;
} else {
code = readFileSync(file).toString();
}
hash = hasha(code, { algorithm: 'md5' });
// remove the file without hash
unlinkSync(file);
file = file.replace('[hash]', hash)
writeFileSync(file, code);
}
const src = isURL(file) ? file : relative(firstDir, file);
if (type === 'js') {
let attrs = {src: src};
let mode = node.mode || defaultmode;
if (mode) attrs.type = mode;
attrs = Object.entries(([key, val]) => `${key}="${val}"`).join(' ');
const script = `<script ${attrs}></script>\n`;
// node.inject will cover the inject
if (node.inject === 'head' || inject === 'head') {
head.append(script);
} else {
body.append(script);
}
} else if (type === 'css') {
head.append(`<link rel="stylesheet" href="${src}">\n`);
}
});
writeFileSync(destFile, $.html());
}
};
}