This repository has been archived by the owner on Aug 5, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
/
index.js
126 lines (114 loc) · 3.81 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
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
import {createFilter} from "rollup-pluginutils"
import mime from "mime"
import crypto from "crypto"
import path from "path"
import fs from "fs"
const defaultInclude = [
"**/*.svg",
"**/*.png",
"**/*.jpg",
"**/*.gif",
]
export default function url(options = {}) {
const {
limit = 14 * 1024,
include = defaultInclude,
exclude,
publicPath = "",
emitFiles = true,
fileName = "[hash][extname]"
} = options
const filter = createFilter(include, exclude)
const copies = Object.create(null)
return {
load(id) {
if (!filter(id)) {
return null
}
return Promise.all([
promise(fs.stat, id),
promise(fs.readFile, id),
]).then(([stats, buffer]) => {
let data
if ((limit && stats.size > limit) || limit === 0) {
const hash = crypto.createHash("sha1")
.update(buffer)
.digest("hex")
.substr(0, 16)
const ext = path.extname(id)
const name = path.basename(id, ext)
// Determine the directory name of the file based
// on either the relative path provided in options,
// or the parent directory
const relativeDir = options.sourceDir
? path.relative(options.sourceDir, path.dirname(id))
: path.dirname(id).split(path.sep).pop()
// Generate the output file name based on some string
// replacement parameters
const outputFileName = fileName
.replace(/\[hash\]/g, hash)
.replace(/\[extname\]/g, ext)
.replace(/\[dirname\]/g, `${relativeDir}/`)
.replace(/\[name\]/g, name)
data = `${publicPath}${outputFileName}`
copies[id] = outputFileName
} else {
const mimetype = mime.getType(id)
const isSVG = mimetype === "image/svg+xml"
data = isSVG
? encodeSVG(buffer)
: buffer.toString("base64")
const encoding = isSVG ? "" : ";base64"
data = `data:${mimetype}${encoding},${data}`
}
return `export default "${data}"`
})
},
generateBundle: async function write(outputOptions) {
// Allow skipping saving files for server side builds.
if (!emitFiles) return
const base = options.destDir || outputOptions.dir || path.dirname(outputOptions.file)
await promise(mkpath, base)
return Promise.all(Object.keys(copies).map(async name => {
const output = copies[name]
// Create a nested directory if the fileName pattern contains
// a directory structure
const outputDirectory = path.join(base, path.dirname(output))
await promise(mkpath, outputDirectory)
return copy(name, path.join(base, output))
}))
}
}
}
function promise(fn, ...args) {
return new Promise((resolve, reject) =>
fn(...args, (err, res) =>
err ? reject(err) : resolve(res)))
}
function copy(src, dest) {
return new Promise((resolve, reject) => {
const read = fs.createReadStream(src)
read.on("error", reject)
const write = fs.createWriteStream(dest)
write.on("error", reject)
write.on("finish", resolve)
read.pipe(write)
})
}
// https://github.com/filamentgroup/directory-encoder/blob/master/lib/svg-uri-encoder.js
function encodeSVG(buffer) {
return encodeURIComponent(buffer.toString("utf-8")
// strip newlines and tabs
.replace(/[\n\r]/gmi, "")
.replace(/\t/gmi, " ")
// strip comments
.replace(/<!\-\-(.*(?=\-\->))\-\->/gmi, "")
// replace
.replace(/'/gmi, "\\i"))
// encode brackets
.replace(/\(/g, "%28").replace(/\)/g, "%29")
}
// use fs.mkdir to instead of mkpath package, see https://github.com/jrajav/mkpath/issues/6
function mkpath(path, err) {
return fs.mkdir(path, { recursive: true }, err);
}