@marcuwynu23/webpack-plugin-alias-resolver
Version:
A Webpack plugin that rewrites path aliases like @/ into relative paths during build time.
113 lines (96 loc) • 3.33 kB
text/typescript
import fs from "fs";
import path from "path";
type MinimalCompiler = {
hooks: {
beforeRun: {
tap: (pluginName: string, callback: () => void) => void;
};
};
};
type PluginOptions = {
alias?: string;
baseDir?: string;
targetDir?: string;
fileTypes?: string | string[];
};
class AliasResolverPlugin {
alias: string;
baseDir: string;
targetDir: string;
fileTypes: string[];
constructor(options: PluginOptions = {}) {
this.alias = options.alias || "@/";
this.baseDir = path.resolve(options.baseDir || "dist");
this.targetDir = path.resolve(options.targetDir || "dist");
this.fileTypes = this.normalizeFileTypes(options.fileTypes);
}
normalizeFileTypes(fileTypes?: string | string[]): string[] {
if (!fileTypes) return ["js"];
if (typeof fileTypes === "string") {
if (fileTypes === "both") return ["js", "ts"];
return [fileTypes.replace(/^\./, "").toLowerCase()];
}
return fileTypes.map((ext) => ext.replace(/^\./, "").toLowerCase());
}
shouldProcessFile(filePath: string): boolean {
const ext = path.extname(filePath).replace(/^\./, "").toLowerCase();
return this.fileTypes.includes(ext);
}
toRelativeImport(currentFilePath: string, targetPath: string): string {
const relPath = path.relative(path.dirname(currentFilePath), targetPath);
return "./" + relPath.replace(/\\/g, "/").replace(/\.js$/, "");
}
fixFile(filePath: string): void {
let content = fs.readFileSync(filePath, "utf8");
const regex = new RegExp(
`(?:from\\s+['"]${this.alias}(.*?)['"]|require\\(['"]${this.alias}(.*?)['"]\\))`,
"g"
);
const updated = content.replace(
regex,
(
_match: string,
esImport: string | undefined,
requireImport: string | undefined
): string => {
const importPath = esImport || requireImport;
if (!importPath) return _match;
const targetPath = path.resolve(this.baseDir, `${importPath}.js`);
if (!fs.existsSync(targetPath)) {
console.warn(
`⚠️ Cannot resolve: ${filePath} -> ${this.alias}${importPath}`
);
return _match;
}
const relative = this.toRelativeImport(filePath, targetPath);
return _match.startsWith("from")
? `from '${relative}'`
: `require('${relative}')`;
}
);
fs.writeFileSync(filePath, updated, "utf8");
}
walk(dir: string): void {
for (const item of fs.readdirSync(dir)) {
const fullPath = path.join(dir, item);
if (fs.statSync(fullPath).isDirectory()) {
this.walk(fullPath);
} else if (this.shouldProcessFile(fullPath)) {
this.fixFile(fullPath);
}
}
}
apply(compiler: MinimalCompiler): void {
compiler.hooks.beforeRun.tap("AliasResolverPlugin", () => {
console.log(
`🔧 [AliasResolverPlugin] Rewriting ${
this.alias
} imports in [${this.fileTypes.join(", ")}] files...`
);
this.walk(this.targetDir);
console.log("✅ [AliasResolverPlugin] Import rewriting complete.");
});
}
}
module.exports = AliasResolverPlugin;
module.exports.default = AliasResolverPlugin;