UNPKG

react-native-svg-asset-plugin

Version:
144 lines (115 loc) 5.12 kB
"use strict"; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const fse = require('fs-extra'); const path = require('path'); const cache = require('./cache'); const config = require('./config'); const sharp = require('./sharp'); const funcUtils = require('./utils/func'); const fsUtils = require('./utils/fs'); const asyncConfig = config.load(); async function reactNativeSvgAssetPlugin(assetData) { const filePath = assetData.files.length ? assetData.files[0] : ''; if (await shouldConvertFile(assetData, filePath)) { return convertSvg(assetData); } else { return assetData; } } async function shouldConvertFile(assetData, filePath) { if (assetData.type !== 'svg') { return false; } const ignoreRegex = (await asyncConfig).ignoreRegex; if (ignoreRegex && ignoreRegex.test(filePath)) { return false; } return true; } async function convertSvg(assetData) { if (assetData.scales.length !== assetData.files.length) { throw new Error("Passed scales doesn't match passed files."); } else if (assetData.files.length === 0) { throw new Error('No files passed.'); } else if (assetData.files.length > 1) { throw new Error('Multiple SVG scales not supported.'); } else if (assetData.scales[0] !== 1) { throw new Error('Scaled SVGs not supported.'); } const inputFilePath = assetData.files[0]; const inputFileScale = assetData.scales[0]; const config = await asyncConfig; const outputDirectory = path.join(assetData.fileSystemLocation, config.cacheDir); const outputName = `${assetData.name}-${assetData.hash}`; await fse.ensureDir(outputDirectory); const imageLoader = createimageLoader(inputFilePath); const outputImages = await Promise.all(config.scales.map(imageScale => ensurePngUpToDate(imageLoader, imageScale / inputFileScale, path.join(outputDirectory, `${outputName}${getScaleSuffix(imageScale)}.png`), config.output))); return _objectSpread(_objectSpread({}, assetData), {}, { fileSystemLocation: outputDirectory, httpServerLocation: `${assetData.httpServerLocation}/${config.cacheDir}`, files: outputImages.map(outputImage => outputImage.filePath), scales: outputImages.map(outputImage => outputImage.scale), name: outputName, type: 'png' }); } /** * Creates an image loader for input file. * This provides lazy cached loading of image data. */ function createimageLoader(inputFilePath) { return funcUtils.memo(async () => { const [fileBuffer, loadedSharp] = await Promise.all([fse.readFile(inputFilePath), sharp.load()]); const metadata = await loadedSharp(fileBuffer).metadata(); return { buffer: fileBuffer, metadata: metadata }; }); } /** * Ensures that the resultign PNG file exists on the fileystem. * * In case the file does not exist yet, or it is older than the * current configuration, it will be generated. * * Otherwise the existing file will be left in place, and its * last modified time will be updated. */ async function ensurePngUpToDate(imageLoader, scale, outputFilePath, outputOptions) { if (await cache.isFileOutdated(outputFilePath, await asyncConfig)) { const inputFile = await imageLoader(); await generatePng(inputFile, scale, outputFilePath, outputOptions); } else { await fsUtils.updateLastModifiedTime(outputFilePath); } return { filePath: outputFilePath, scale: scale }; } /** * Generates a PNG file from a loaded SVG file. */ async function generatePng(inputFile, scale, outputFilePath, outputOptions) { if (inputFile.metadata.density === undefined) { throw new Error('Input image missing density information'); } const density = inputFile.metadata.density; const loadedSharp = await sharp.load(); await loadedSharp(inputFile.buffer, { density: density * scale }).png(outputOptions).toFile(outputFilePath); } function getScaleSuffix(scale) { switch (scale) { case 1: return ''; default: return `@${scale}x`; } } const assetDataPlugin = reactNativeSvgAssetPlugin; module.exports = assetDataPlugin;