babel-plugin-file-loader
Version:
Like file-loader for webpack, but for Babel. Works with SSE apps.
128 lines (104 loc) • 3.39 kB
JavaScript
const crypto = require('crypto')
const fs = require('fs-extra')
const path = require('path')
const mime = require('mime')
const baseEncodeTables = {
26: 'abcdefghijklmnopqrstuvwxyz',
32: '123456789abcdefghjkmnpqrstuvwxyz', // no 0lio
36: '0123456789abcdefghijklmnopqrstuvwxyz',
49: 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', // no lIO
52: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
58: '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ', // no 0lIO
62: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
64: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_'
}
function encodeBufferToBase (buffer, base) {
const encodeTable = baseEncodeTables[base]
if (!encodeTable) throw new Error('Unknown encoding base' + base)
const readLength = buffer.length
const Big = require('big.js')
Big.RM = Big.DP = 0
let b = new Big(0)
for (let i = readLength - 1; i >= 0; i--) {
b = b.times(256).plus(buffer[i])
}
let output = ''
while (b.gt(0)) {
output = encodeTable[b.mod(base)] + output
b = b.div(base)
}
Big.DP = 20
Big.RM = 1
return output
}
function hash (contents, hashName, digestType, maxLength) {
hashName = hashName || 'md5'
maxLength = maxLength || 128
const hasher = crypto.createHash(hashName).update(contents)
if (
digestType === 'base26' ||
digestType === 'base32' ||
digestType === 'base36' ||
digestType === 'base49' ||
digestType === 'base52' ||
digestType === 'base58' ||
digestType === 'base62' ||
digestType === 'base64'
) {
return encodeBufferToBase(hasher.digest(), digestType.substr(4)).substr(
0,
maxLength
)
} else {
return hasher.digest(digestType || 'hex').substr(0, maxLength)
}
}
function transform (rootPath, filePath, opts) {
let url = opts.name
let ext = 'bin'
let basename = 'file'
let directory = ''
const outputPath = opts.outputPath
const publicPath = opts.publicPath.replace(/\/$/, '')
const context =
opts.context[0] === '/' ? opts.context.substr(1) : opts.context
const limit = opts.limit
const contextPath = path.resolve(rootPath, context)
if (!fs.existsSync(filePath)) {
throw new Error('File does not exist')
}
const parsed = path.parse(filePath)
if (parsed.ext) {
ext = parsed.ext.substr(1)
}
let basePath
if (parsed.dir) {
basename = parsed.name
basePath = parsed.dir + path.sep
}
directory = path
.relative(contextPath, basePath + '_')
.replace(/\\/g, '/')
.replace(/\.\.(\/)?/g, '_$1')
directory = directory.substr(0, directory.length - 1)
url = url
.replace(/\[ext\]/gi, () => ext)
.replace(/\[name\]/gi, () => basename)
.replace(/\[path\]/gi, () => directory)
const contents = fs.readFileSync(filePath)
if (contents.length < limit) {
const src = Buffer.from(contents)
const mimetype = mime.getType(filePath) || ''
return `data:${mimetype};base64,${src.toString('base64')}`
}
url = url.replace(
/\[(?:([^:]+):)?hash(?::([a-z]+\d*))?(?::(\d+))?\]/gi,
(_, hashType, digestType, maxLength) =>
hash(contents, hashType, digestType, parseInt(maxLength, 10))
)
if (outputPath !== null) {
fs.copySync(filePath, path.join(rootPath, outputPath, url.split('?')[0]))
}
return publicPath + '/' + url
}
module.exports = transform