babel-plugin-transform-assets-import-to-string
Version:
Babel plugin that transforms image assets import and requires to urls / cdn
249 lines (241 loc) • 8.04 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
default: () => plugin,
resetBuildCache: () => resetBuildCache
});
module.exports = __toCommonJS(index_exports);
// src/transform.ts
var import_node_path3 = __toESM(require("path"), 1);
// src/steps/fileHash.ts
var import_node_crypto = __toESM(require("crypto"), 1);
var import_node_fs = __toESM(require("fs"), 1);
function computeFileHash(absPath, hashLength) {
if (hashLength === 0) {
return "";
}
const content = import_node_fs.default.readFileSync(absPath);
const hash = import_node_crypto.default.createHash("sha1").update(content).digest("hex").slice(0, hashLength);
return hash;
}
// src/steps/buildOutputPath.ts
var import_node_path = __toESM(require("path"), 1);
function buildOutputPath(options) {
const { absPath, hash, preservePaths, projectRoot } = options;
const ext = import_node_path.default.extname(absPath);
const basename = import_node_path.default.basename(absPath, ext);
const hashedName = hash ? `${basename}.${hash}${ext}` : `${basename}${ext}`;
if (!preservePaths) {
return hashedName;
}
const normalizedBase = preservePaths.replace(/^\/|\/$/g, "");
const relativePath = import_node_path.default.relative(projectRoot, absPath);
const segments = relativePath.split(import_node_path.default.sep);
const baseIndex = segments.indexOf(normalizedBase);
let dirPath;
if (baseIndex !== -1) {
dirPath = segments.slice(baseIndex + 1, -1).join("/");
} else {
dirPath = import_node_path.default.dirname(relativePath).split(import_node_path.default.sep).join("/");
}
if (dirPath && dirPath !== ".") {
return `${dirPath}/${hashedName}`;
}
return hashedName;
}
// src/steps/copyFile.ts
var import_node_fs2 = __toESM(require("fs"), 1);
var import_node_path2 = __toESM(require("path"), 1);
function copyFile(options) {
const { absPath, outputPath, outputDir, cache } = options;
if (cache.pathMap.has(absPath)) {
return;
}
const existingSource = cache.outputMap.get(outputPath);
if (existingSource && existingSource !== absPath) {
throw new Error(
`Filename collision detected (hashLength is 0)
- ${existingSource}
- ${absPath}
Both would output to: ${import_node_path2.default.join(outputDir, outputPath)}
Consider enabling hashLength or renaming one of the files.`
);
}
const destPath = import_node_path2.default.join(outputDir, outputPath);
const destDir = import_node_path2.default.dirname(destPath);
if (!import_node_fs2.default.existsSync(destDir)) {
import_node_fs2.default.mkdirSync(destDir, { recursive: true });
}
import_node_fs2.default.copyFileSync(absPath, destPath);
cache.pathMap.set(absPath, outputPath);
cache.outputMap.set(outputPath, absPath);
}
// src/steps/replaceNode.ts
function getVariableName(node) {
if (node.specifiers?.[0]?.type === "ImportDefaultSpecifier") {
return node.specifiers[0].local.name;
}
return void 0;
}
function replaceNode(scope, uri, types) {
const content = types.stringLiteral(uri);
if (scope.callee === "require") {
scope.path.replaceWith(content);
return;
}
const importPath = scope.path;
const variableName = getVariableName(importPath.node);
if (variableName) {
scope.path.replaceWith(
types.variableDeclaration("const", [
types.variableDeclarator(types.identifier(variableName), content)
])
);
}
}
// src/transform.ts
function transform(scope, options, types, cache, projectRoot) {
const ext = import_node_path3.default.extname(scope.value);
if (!options.extensions || !options.extensions.includes(ext)) {
return;
}
const dir = import_node_path3.default.dirname(import_node_path3.default.resolve(scope.filename));
const absPath = import_node_path3.default.resolve(dir, scope.value);
if (absPath.includes("node_modules")) {
return;
}
const hashLength = options.hashLength ?? 8;
const hash = computeFileHash(absPath, hashLength);
const outputPath = buildOutputPath({
absPath,
hash,
preservePaths: options.preservePaths,
projectRoot
});
if (options.outputDir) {
copyFile({
absPath,
outputPath,
outputDir: options.outputDir,
cache
});
}
const baseUri = options.baseUri || "";
const separator = baseUri && !baseUri.endsWith("/") ? "/" : "";
const uri = `${baseUri}${separator}${outputPath}`;
replaceNode(scope, uri, types);
}
// src/index.ts
var DEFAULT_EXTENSIONS = [".gif", ".jpeg", ".jpg", ".png", ".svg"];
function isRequireStatement(path4) {
const callee = path4.get("callee");
return !Array.isArray(callee) && callee.isIdentifier() && callee.node.name === "require";
}
function isValidArgument(path4) {
const args = path4.get("arguments");
const arg = args[0];
return arg !== void 0 && arg.isStringLiteral();
}
var buildCache = null;
function plugin({
types: t
}) {
return {
name: "transform-assets-import-to-string",
pre() {
if (!buildCache) {
buildCache = {
pathMap: /* @__PURE__ */ new Map(),
outputMap: /* @__PURE__ */ new Map()
};
}
},
post() {
},
visitor: {
ImportDeclaration(nodePath, state) {
const opts = {
baseUri: "",
extensions: DEFAULT_EXTENSIONS,
hashLength: 8,
...state.opts
};
const projectRoot = state.cwd || process.cwd();
transform(
{
path: nodePath,
filename: state.filename,
value: nodePath.node.source.value,
callee: "import"
},
opts,
t,
buildCache,
projectRoot
);
},
CallExpression(nodePath, state) {
if (isRequireStatement(nodePath) && isValidArgument(nodePath)) {
const args = nodePath.get("arguments");
const arg = args[0];
if (!arg.isStringLiteral()) return;
const opts = {
baseUri: "",
extensions: DEFAULT_EXTENSIONS,
hashLength: 8,
...state.opts
};
const projectRoot = state.cwd || process.cwd();
transform(
{
path: nodePath,
filename: state.filename,
value: arg.node.value,
callee: "require"
},
opts,
t,
buildCache,
projectRoot
);
}
}
}
};
}
function resetBuildCache() {
buildCache = null;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
resetBuildCache
});
//# sourceMappingURL=index.cjs.map