UNPKG

@froxz/vite-plugin-s3

Version:

Allows you to upload files to AWS S3 or any other S3 compatible provider

181 lines (174 loc) 4.98 kB
// src/helpers.ts import path from "path"; import { isRegExp, isString } from "es-toolkit"; import readDir from "recursive-readdir"; var S3_PATH_SEP = "/"; var PATH_SEP = path.sep; var DEFAULT_UPLOAD_OPTIONS = { ACL: "public-read" }; var UPLOAD_IGNORES = [ ".DS_Store" ]; function addTrailingS3Sep(fPath) { return fPath ? fPath.replace(/\/?(\?|#|$)/, "/$1") : fPath; } function addSeperatorToPath(fPath) { if (!fPath) return fPath; return fPath.endsWith(PATH_SEP) ? fPath : fPath + PATH_SEP; } function translatePathFromFiles(dir, files) { return files.map((file) => ({ path: file, name: file.replace(dir, "").split(PATH_SEP).join(S3_PATH_SEP) })); } function getDirectoryFilesRecursive(dir, ignores = []) { return new Promise((resolve2, reject) => { readDir(dir, ignores, (error, files) => { if (error) reject(error); else resolve2(translatePathFromFiles(dir, files)); }); }); } function testRule(rule, subject) { if (isRegExp(rule)) return rule.test(subject); else if (typeof rule === "function") return !!rule(subject); else if (Array.isArray(rule)) return rule.every((condition) => testRule(condition, subject)); else if (isString(rule)) return new RegExp(rule).test(subject); else throw new Error("Invalid include / exclude rule"); } // src/context.ts function createContext(options) { const basePath = options.basePath ? addTrailingS3Sep(options.basePath) : ""; return { ...options, basePath }; } // src/uploader.ts import fs from "fs"; import { resolve } from "path"; import { S3 } from "@aws-sdk/client-s3"; import { mapValues } from "es-toolkit"; import { lookup } from "mime-types"; // src/log.ts import { relative } from "path"; import { cyan, dim } from "kolorist"; // package.json var version = "2.0.5"; // src/log.ts function logResult(files, vite) { const { root, logLevel = "info" } = vite; if (logLevel === "silent") return; if (logLevel === "info") { console.info([ "", `${cyan(`ViteS3 v${version}`)}`, `\u2713 ${files.length} files uploaded`, ...files.map((p) => `${dim(relative(root, p.path))}`) ].join("\n")); } } // src/uploader.ts var Uploader = class { options; vite; client; directory; constructor(options, vite) { this.options = options; this.vite = vite; this.client = new S3(this.options.clientConfig); this.directory = resolve(this.vite.root, this.options.directory ? this.options.directory : this.vite.build.outDir); } uploadFile(fileName, file) { let Key = this.options.basePath + fileName; const params = mapValues(this.options.uploadOptions, (optionConfig) => { return typeof optionConfig === "function" ? optionConfig(fileName, file) : optionConfig; }); if (Key[0] === "/") Key = Key.substr(1); if (params.ContentType === void 0) params.ContentType = lookup(fileName) || "application/octet-stream"; const Body = fs.createReadStream(file); return this.client.putObject({ Key, Body, ...DEFAULT_UPLOAD_OPTIONS, ...params }); } async uploadFiles(files) { if (this.options.sequentialUploads === true) { const uploadResponses = []; for (const file of files) { const response = await this.uploadFile(file.name, file.path); uploadResponses.push(response); } return uploadResponses; } const uploadFiles = files.map((file) => this.uploadFile(file.name, file.path)); return await Promise.all(uploadFiles); } isIgnoredFile(file) { return UPLOAD_IGNORES.some((ignore) => new RegExp(ignore).test(file)); } isIncludeAndNotExclude(file) { const { include, exclude } = this.options; const isInclude = include ? testRule(include, file) : true; const isExclude = exclude ? testRule(exclude, file) : false; return isInclude && !isExclude; } filterAllowedFiles(files) { return files.reduce((res, file) => { if (this.isIncludeAndNotExclude(file.name) && !this.isIgnoredFile(file.name)) res.push(file); return res; }, []); } async apply() { const dPath = addSeperatorToPath(this.directory); const allFiles = await getDirectoryFilesRecursive(dPath); const files = this.filterAllowedFiles(allFiles); await this.uploadFiles(files); logResult(files, this.vite); } }; // src/index.ts function ViteS3(enabled, userOptions) { const options = createContext(userOptions); let vite; return { name: "vite-plugin-s3", enforce: "post", apply(config, { command }) { return command === "build" && enabled; }, configResolved(config) { vite = config; }, closeBundle: { async handler() { if (!vite.build.ssr && enabled) { const uploader = new Uploader(options, vite); await uploader.apply(); } } } }; } export { ViteS3 as S3Plugin, ViteS3 }; //# sourceMappingURL=index.js.map