@aem-vite/import-rewriter
Version:
Dynamic imports transformer and CSS path rewriter for Vite when using Adobe Experience Manager
207 lines (202 loc) • 9.46 kB
JavaScript
;Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/bundles.ts
var _esmodulelexer = require('es-module-lexer');
var _magicstring = require('magic-string'); var _magicstring2 = _interopRequireDefault(_magicstring);
// src/helpers.ts
var _debug2 = require('debug'); var _debug3 = _interopRequireDefault(_debug2);
var _crypto = require('crypto');
var _fs = require('fs');
var _path = require('path');
var entryPaths = /* @__PURE__ */ new Set();
var debug = _debug3.default.call(void 0, "aem-vite-import-rewriter");
var relativePathPattern = /([.]{1,2}\/)+/;
function getEntryPaths() {
return entryPaths;
}
function setEntryPath(path) {
entryPaths.add(path);
}
function generateChecksum(source) {
return _crypto.createHash.call(void 0, "md5").update(source, "utf8").digest("hex");
}
function getCacheKey(entryPath, keyFormat) {
let keyFormatString = "";
switch (keyFormat) {
case "cloud":
keyFormatString = "lc-%s-lc.%m";
break;
case "acs-classic":
keyFormatString = "%s.%m";
break;
case "acs-modern":
keyFormatString = "%m.ACSHASH%s";
break;
default:
if (typeof keyFormat === "object" && keyFormat.type === "custom" && keyFormat.format) {
keyFormatString = keyFormat.format;
} else {
throw new Error(`Invalid key format provided: ${keyFormat}`);
}
}
const combinedContents = [...entryPaths].map((entry) => {
const path = _path.join.call(void 0, entryPath, entry);
return _fs.existsSync.call(void 0, path) ? _fs.readFileSync.call(void 0, path).toString() : "";
});
return keyFormatString.replace("%s", generateChecksum(combinedContents.join("")));
}
function getAemClientLibPath(options, forImport = false, withChecksum = false, rollupOptions) {
let path = options.publicPath;
if (forImport) {
return `${path}/${options.resourcesPath}/`;
}
if (withChecksum && options.caching && options.caching.enabled && rollupOptions !== void 0) {
const entryPath = rollupOptions.dir;
path = `${path}.${getCacheKey(entryPath, options.caching.keyFormat)}`;
path = path.replace(".%m", options.minify === true ? ".min" : "");
}
return `${path}.js`;
}
function getReplacementPath(parentPath, path, options, entryAliases) {
const isEntryPath = entryPaths.has(parentPath);
if (isEntryPath) {
return path.replace(new RegExp(`^${relativePathPattern.source}`), getAemClientLibPath(options, true));
}
return isInputAnEntryAlias(path, entryAliases) ? path.replace(
new RegExp(`${relativePathPattern.source}${path.replace(relativePathPattern, "")}`),
getAemClientLibPath(options)
) : path;
}
function isInputAnEntryAlias(input, entryAliases) {
const entryAliasesExpr = new RegExp(`^[./]+(${Object.keys(entryAliases).join("|")})\\.js$`);
return !!_optionalChain([RegExp, 'call', _ => _(entryAliasesExpr), 'access', _2 => _2.exec, 'call', _3 => _3(input), 'optionalAccess', _4 => _4[0]]);
}
// src/bundles.ts
function bundlesImportRewriter(options) {
const entryAliases = {};
return {
apply: "build",
enforce: "post",
name: "aem-vite:import-rewriter",
configResolved(config) {
const inputs = config.build.rollupOptions.input;
if (!inputs || typeof inputs !== "object" || Array.isArray(inputs)) {
throw new Error(
"Missing valid input aliases which are required to map to an AEM ClientLib path, see https://www.aemvite.dev/guide/front-end/vite/#source-structure for more information."
);
}
for (const [key, value] of Object.entries(inputs)) {
if (/(ts|js)x?$/.test(value)) {
entryAliases[key] = value;
}
}
if (Object.keys(entryAliases).length > 1) {
throw new Error(
"Invalid number of JavaScript inputs provided. Only a single input is currently supported which is a limitation of AEM ClientLibs. It is recommended to create a second ClientLib and Vite config if you need to meet this need."
);
}
},
async renderChunk(source, chunk, rollupOptions) {
if (rollupOptions.format !== "es") {
return null;
}
if (!_optionalChain([options, 'optionalAccess', _5 => _5.publicPath, 'access', _6 => _6.length])) {
this.error(
`'publicPath' doesn't appear to be defined, see https://aemvite.dev/guide/faqs/#vite-errors for more information.`
);
}
if (chunk.isEntry && chunk.facadeModuleId && /(ts|js)x?$/.test(chunk.facadeModuleId)) {
debug("setting new entry path: %s\n", chunk.fileName);
setEntryPath(chunk.fileName);
}
await _esmodulelexer.init;
let imports = [];
try {
imports = _esmodulelexer.parse.call(void 0, source)[0];
} catch (e) {
this.error({ ...e });
}
if (!imports.length) {
return null;
}
let s;
const str = () => s || (s = new (0, _magicstring2.default)(source));
for (const element of imports) {
const { e: end, d: dynamicIndex, n: importPath, s: start } = element;
if (dynamicIndex === -1 && importPath && relativePathPattern.test(importPath)) {
const replacementPath = getReplacementPath(chunk.fileName, importPath, options, entryAliases);
debug("(render chunk)");
debug("chunk file name: %s", chunk.fileName);
debug("import path: %s", importPath);
debug("updated import path: %s\n", replacementPath);
str().overwrite(start, end, replacementPath);
}
}
if (s) {
return {
code: s.toString(),
map: rollupOptions.sourcemap !== false ? s.generateMap({ hires: true }) : null
};
}
return null;
},
async generateBundle(rollupOptions, output, isWrite) {
const aemClientLibPath = getAemClientLibPath(options);
debug("(generate bundle)");
debug("aem clientlib path: %s", aemClientLibPath);
debug("is write: %s", isWrite);
for (const [fileName, chunk] of Object.entries(output)) {
if (chunk.type !== "chunk" || !chunk.imports) {
continue;
}
debug("(generate bundle)");
debug("bundle name: %s", fileName);
const source = chunk.code;
await _esmodulelexer.init;
let imports = [];
try {
imports = _esmodulelexer.parse.call(void 0, source)[0];
} catch (e) {
this.error({ ...e });
}
if (!imports.length) {
continue;
}
let s;
const str = () => s || (s = new (0, _magicstring2.default)(source));
for (const element of imports) {
const { e: end, d: dynamicIndex, n: importPath, s: start } = element;
if (dynamicIndex === -1 && importPath && relativePathPattern.test(importPath)) {
const replacementPath = getReplacementPath(chunk.fileName, importPath, options, entryAliases);
debug("chunk file name: %s", chunk.fileName);
debug("import type: native");
debug("import path: %s\n", importPath);
str().overwrite(start, end, replacementPath);
}
if (dynamicIndex > -1 && importPath) {
debug("chunk file name: %s", chunk.fileName);
debug("import type: dynamic");
debug("import path: %s", importPath);
const dynamicEnd = source.indexOf(")", end) + 1;
const original = source.slice(dynamicIndex + 8, dynamicEnd - 2);
debug("updated import path: %s\n", getReplacementPath(chunk.fileName, importPath, options, entryAliases));
if (!original.startsWith("/")) {
str().overwrite(start + 1, end - 1, getReplacementPath(chunk.fileName, importPath, options, entryAliases));
}
}
}
let aemImportPath = aemClientLibPath;
let newSource = _nullishCoalesce(_optionalChain([s, 'optionalAccess', _7 => _7.toString, 'call', _8 => _8()]), () => ( source));
if (options.caching && options.caching.enabled) {
aemImportPath = getAemClientLibPath(options, false, true, rollupOptions);
}
newSource = newSource.replace(new RegExp(aemClientLibPath, "g"), aemImportPath);
const relativeClientLibPath = aemImportPath.substring(aemImportPath.lastIndexOf("/") + 1);
getEntryPaths().forEach((path) => {
newSource = newSource.replace(new RegExp(path, "g"), relativeClientLibPath);
});
chunk.code = newSource;
chunk.map = rollupOptions.sourcemap !== false ? s.generateMap({ hires: true }) : null;
}
}
};
}
exports.bundlesImportRewriter = bundlesImportRewriter;