Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce alias option support #203

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
],
"scripts": {
"build": "unbuild",
"dev": "pnpm mkdist test/fixture -d",
"dev": "jiti src/cli test/fixture -d --alias={\\\"~\\\":\\\"\\\u0024\u005cSRC\\\"}",
"lint": "eslint --ext .ts,.mjs,.cjs . && prettier --check src test",
"lint:fix": "eslint --fix --ext .ts,.mjs,.cjs . && prettier --write -c src test",
"mkdist": "jiti src/cli",
Expand Down
5 changes: 5 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const main = defineCommand({
description: "Pattern includes or excludes files",
default: "**",
},
alias: {
type: "string",
description: "Custom alias map used to resolve ids",
},
format: {
type: "string",
description: "File format",
Expand Down Expand Up @@ -88,6 +92,7 @@ const main = defineCommand({
distDir: args.dist,
format: args.format,
pattern: args.pattern,
alias: args.alias ? JSON.parse(args.alias) : undefined,
ext: args.ext,
declaration: args.declaration,
loaders: args.loaders?.split(","),
Expand Down
76 changes: 75 additions & 1 deletion src/make.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { resolve, extname, join, basename, dirname } from "pathe";
import {
resolve,
extname,
join,
basename,
dirname,
relative,
parse,
} from "pathe";
import { resolveAlias } from "pathe/utils";
import fse from "fs-extra";
import { copyFileWithStream } from "./utils/fs";
import {
Expand All @@ -20,6 +29,7 @@ export interface MkdistOptions extends LoaderOptions {
cleanDist?: boolean;
loaders?: (LoaderName | Loader)[];
addRelativeDeclarationExtensions?: boolean;
alias?: { [find: string]: string };
}

export async function mkdist(
Expand Down Expand Up @@ -63,6 +73,70 @@ export async function mkdist(
outputs.push(...((await loadFile(file)) || []));
}

// Resolve aliases
if (options.alias && Object.keys(options.alias).length > 0) {
// Fast transform variables for alias
for (const [find, replace] of Object.entries(options.alias)) {
options.alias[find] = replace.replaceAll("$SRC", options.distDir);
}
const _resolveAlias = (
path: string,
aliases: Record<string, string>,
outputPath: OutputFile["path"] & string,
) => {
// Resolve the alias and transform srcDir to distDir
const resolvedId = resolveAlias(path, aliases).replace(
options.srcDir,
options.distDir,
);

// if resolved path is in distDir, we transform it into a relative path
if (resolvedId.startsWith(options.distDir)) {
const from = parse(resolve(options.distDir, outputPath));
const to = parse(resolvedId);

// the OR `||` clause here means that the two files is in the same dir
const relativePath = relative(from.dir, join(to.dir, to.base));
// for cases like ('/index.ts, '/subfolder/index.ts'), `relative()` returns 'subfolder', without the leading './' which is incompatible with import/require path parameter
return relativePath.startsWith(".")
? relativePath
: `./${relativePath}`;
}

return resolvedId;
};

for (const output of outputs.filter((o) => !o.raw)) {
output.contents = output.contents
// Resolve require statements
.replace(
/require\((["'])(.*)(["'])\)/g,
(_, head, id, tail) =>
"require(" +
head +
_resolveAlias(id, options.alias, output.path) +
tail +
")",
)
// Resolve import statements
.replace(
/(import|export)(\s+(?:.+|{[\s\w,]+})\s+from\s+["'])(.*)(["'])/g,
(_, type, head, id, tail) =>
type + head + _resolveAlias(id, options.alias, output.path) + tail,
)
// Resolve dynamic import
.replace(
/import\((["'])(.*)(["'])\)/g,
(_, head, id, tail) =>
"import(" +
head +
_resolveAlias(id, options.alias, output.path) +
tail +
")",
);
}
}

// Normalize output extensions
for (const output of outputs.filter((o) => o.extension)) {
const renamed =
Expand Down
12 changes: 12 additions & 0 deletions test/fixture/src/alias.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { foo2bar2 } from "~/nestedFolder/level2c";
import { foo2 } from "~/nestedFolder/level2a";
export { foo } from "~/nestedFolder/index";
export const bar = () => import("~/nestedFolder").then((r) => r.bar);
export const foo2bar = async () => {
const r = await bar();
return foo2 + r;
};
export const foo2baz2 = foo2bar2.replace("bar", "baz");

// `require()` transform works but errors out because `mkdist` does not currently support mixed cjs and mjs building.
// export const { baz } = require("~/nestedFolder/cjs")
1 change: 1 addition & 0 deletions test/fixture/src/nestedFolder/cjs.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { baz: "baz" };
2 changes: 2 additions & 0 deletions test/fixture/src/nestedFolder/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const foo = "foo";
export const bar = "bar";
3 changes: 3 additions & 0 deletions test/fixture/src/nestedFolder/level2a/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { foo } from "~/nestedFolder";

export const foo2 = foo.repeat(2);
3 changes: 3 additions & 0 deletions test/fixture/src/nestedFolder/level2b/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { bar } from "~/nestedFolder";

export const bar2 = bar.repeat(2);
4 changes: 4 additions & 0 deletions test/fixture/src/nestedFolder/level2c/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { foo2 } from "~/nestedFolder/level2a";
import { bar2 } from "~/nestedFolder/level2b";

export const foo2bar2 = foo2 + bar2;
9 changes: 9 additions & 0 deletions test/fixture/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["src/*"]
}
},
"include": ["src"]
}
57 changes: 57 additions & 0 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,51 @@ describe("mkdist", () => {
"dist/ts/test1.mjs",
"dist/ts/test2.mjs",
"dist/nested.css",
"dist/alias.mjs",
"dist/nestedFolder/cjs.mjs",
"dist/nestedFolder/index.mjs",
"dist/nestedFolder/level2a/index.mjs",
"dist/nestedFolder/level2b/index.mjs",
"dist/nestedFolder/level2c/index.mjs",
]
.map((f) => resolve(rootDir, f))
.sort(),
);
});

it("mkdist (resolve aliases)", async () => {
const rootDir = resolve(__dirname, "fixture");
const { writtenFiles } = await mkdist({
rootDir,
alias: { "~": resolve(rootDir, "src") },
pattern: ["alias.ts", "nestedFolder/**"],
});
expect(writtenFiles.sort()).containSubset(
[
"dist/alias.mjs",
"dist/nestedFolder/cjs.mjs",
"dist/nestedFolder/index.mjs",
"dist/nestedFolder/level2a/index.mjs",
"dist/nestedFolder/level2b/index.mjs",
"dist/nestedFolder/level2c/index.mjs",
]
.map((f) => resolve(rootDir, f))
.sort(),
);

// Expect file to not contains any unresolved '`' alias
const indexFile = await readFile(
resolve(rootDir, "dist/alias.mjs"),
"utf8",
);
expect(indexFile).not.toMatch("~/");

// Expect the file to be able to execute normally
await import(resolve(rootDir, "dist/alias.mjs")).then(async (res) =>
expect(res.foo + (await res.bar())).toBe("foobar"),
);
});

it("mkdist (custom glob pattern)", async () => {
const rootDir = resolve(__dirname, "fixture");
const { writtenFiles } = await mkdist({
Expand Down Expand Up @@ -113,6 +152,18 @@ describe("mkdist", () => {
"dist/ts/test1.d.mts",
"dist/ts/test2.d.cts",
"dist/nested.css",
"dist/alias.mjs",
"dist/alias.d.ts",
"dist/nestedFolder/cjs.mjs",
"dist/nestedFolder/cjs.d.cts",
"dist/nestedFolder/index.mjs",
"dist/nestedFolder/level2a/index.mjs",
"dist/nestedFolder/level2b/index.mjs",
"dist/nestedFolder/level2c/index.mjs",
"dist/nestedFolder/index.d.ts",
"dist/nestedFolder/level2a/index.d.ts",
"dist/nestedFolder/level2b/index.d.ts",
"dist/nestedFolder/level2c/index.d.ts",
]
.map((f) => resolve(rootDir, f))
.sort(),
Expand Down Expand Up @@ -191,6 +242,12 @@ describe("mkdist", () => {
"dist/ts/test1.mjs",
"dist/ts/test2.mjs",
"dist/nested.css",
"dist/alias.mjs",
"dist/nestedFolder/cjs.mjs",
"dist/nestedFolder/index.mjs",
"dist/nestedFolder/level2a/index.mjs",
"dist/nestedFolder/level2b/index.mjs",
"dist/nestedFolder/level2c/index.mjs",
]
.map((f) => resolve(rootDir, f))
.sort(),
Expand Down