1 | import {createFilter} from "rollup-pluginutils"
|
2 | import mime from "mime"
|
3 | import crypto from "crypto"
|
4 | import path from "path"
|
5 | import fs from "fs"
|
6 |
|
7 | const defaultInclude = [
|
8 | "**/*.svg",
|
9 | "**/*.png",
|
10 | "**/*.jpg",
|
11 | "**/*.gif",
|
12 | ]
|
13 |
|
14 | export default function url(options = {}) {
|
15 | const {
|
16 | limit = 14 * 1024,
|
17 | include = defaultInclude,
|
18 | exclude,
|
19 | publicPath = "",
|
20 | emitFiles = true
|
21 | } = options
|
22 | const filter = createFilter(include, exclude)
|
23 |
|
24 | const copies = Object.create(null)
|
25 |
|
26 | return {
|
27 | load(id) {
|
28 | if (!filter(id)) {
|
29 | return null
|
30 | }
|
31 | return Promise.all([
|
32 | promise(fs.stat, id),
|
33 | promise(fs.readFile, id),
|
34 | ]).then(([stats, buffer]) => {
|
35 | let data
|
36 | if ((limit && stats.size > limit) || limit === 0) {
|
37 | const hash = crypto.createHash("sha1")
|
38 | .update(buffer)
|
39 | .digest("hex")
|
40 | .substr(0, 16)
|
41 | const filename = hash + path.extname(id)
|
42 | data = `${publicPath}${filename}`
|
43 | copies[id] = filename
|
44 | } else {
|
45 | const mimetype = mime.lookup(id)
|
46 | const isSVG = mimetype === "image/svg+xml"
|
47 | data = isSVG
|
48 | ? encodeSVG(buffer)
|
49 | : buffer.toString("base64")
|
50 | const encoding = isSVG ? "" : ";base64"
|
51 | data = `data:${mimetype}${encoding},${data}`
|
52 | }
|
53 | return `export default "${data}"`
|
54 | })
|
55 | },
|
56 | onwrite: function write(options) {
|
57 |
|
58 | if (!emitFiles) return
|
59 |
|
60 | const base = path.dirname(options.dest)
|
61 | return Promise.all(Object.keys(copies).map(name => {
|
62 | const output = copies[name]
|
63 | return copy(name, path.join(base, output))
|
64 | }))
|
65 | }
|
66 | }
|
67 | }
|
68 |
|
69 | function promise(fn, ...args) {
|
70 | return new Promise((resolve, reject) =>
|
71 | fn(...args, (err, res) =>
|
72 | err ? reject(err) : resolve(res)))
|
73 | }
|
74 |
|
75 | function copy(src, dest) {
|
76 | return new Promise((resolve, reject) => {
|
77 | const read = fs.createReadStream(src)
|
78 | read.on("error", reject)
|
79 | const write = fs.createWriteStream(dest)
|
80 | write.on("error", reject)
|
81 | write.on("finish", resolve)
|
82 | read.pipe(write)
|
83 | })
|
84 | }
|
85 |
|
86 |
|
87 | function encodeSVG(buffer) {
|
88 | return encodeURIComponent(buffer.toString("utf-8")
|
89 |
|
90 | .replace(/[\n\r]/gmi, "")
|
91 | .replace(/\t/gmi, " ")
|
92 |
|
93 | .replace(/<!\-\-(.*(?=\-\->))\-\->/gmi, "")
|
94 |
|
95 | .replace(/'/gmi, "\\i"))
|
96 |
|
97 | .replace(/\(/g, "%28").replace(/\)/g, "%29")
|
98 | }
|