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

Bundler plugins #12

Merged
merged 59 commits into from
Aug 18, 2024
Merged
Changes from 1 commit
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
217adca
feat: rollup plugin
magne4000 Jul 16, 2024
8893dd1
tests: rollup
magne4000 Jul 16, 2024
ce61d2b
tests: rollup
magne4000 Jul 16, 2024
1d9dac6
tests: rollup
magne4000 Jul 16, 2024
20cc163
feat: esbuild plugin
magne4000 Jul 16, 2024
ace5ca3
fix: rollup
magne4000 Jul 16, 2024
15b44b1
fix: rollup
magne4000 Jul 16, 2024
97d7201
chore(esbuild): respect outbase
magne4000 Jul 17, 2024
873e0ca
feat(esbuild): generate report
magne4000 Jul 17, 2024
434b3f2
chore: pnpm-lock
magne4000 Jul 17, 2024
ea40a65
refactor: share code between esbuild and rollup
magne4000 Jul 17, 2024
09f3ef2
chore(rollup): ensure externals
magne4000 Jul 17, 2024
f9f1c32
chore: force build order
magne4000 Jul 17, 2024
d7bc7ce
chore: windows tests
magne4000 Jul 17, 2024
1812dd8
chore: remove comments
magne4000 Jul 17, 2024
29fbcae
chore: windows tests
magne4000 Jul 17, 2024
64ac9ce
chore: windows tests
magne4000 Jul 17, 2024
de9c817
chore: windows tests
magne4000 Jul 17, 2024
3c60201
chore: windows tests
magne4000 Jul 17, 2024
f048657
chore: windows tests
magne4000 Jul 17, 2024
2264f83
chore: windows tests
magne4000 Jul 17, 2024
82b8c24
tests: report
magne4000 Jul 17, 2024
15315f2
chore: fix build
magne4000 Jul 17, 2024
1bccff9
chore: windows tests
magne4000 Jul 17, 2024
e4d3406
chore: eslint ignore
magne4000 Jul 17, 2024
8dc6134
chore: windows tests
magne4000 Jul 17, 2024
5baefa8
chore: windows tests
magne4000 Jul 17, 2024
f14c17b
chore: tests-tool
magne4000 Jul 17, 2024
5891cad
chore: edit package.json
magne4000 Jul 17, 2024
97e0042
chore: working tests-example
magne4000 Jul 17, 2024
fa8e540
tests: e2e tests
magne4000 Jul 17, 2024
eb5b7df
tests: types
magne4000 Jul 17, 2024
cdf09c3
chore
magne4000 Jul 17, 2024
417c71c
feat: Add ability to forwards args to underlying handler or middlewar…
magne4000 Jul 17, 2024
04b80f7
Merge branch 'main' into plugin
magne4000 Jul 19, 2024
e14a8dc
feat: support for In and Out Context
magne4000 Aug 17, 2024
1cb1080
feat: webroute adapter
magne4000 Aug 17, 2024
c9af0d4
chore: deno.lock
magne4000 Aug 17, 2024
1c923ac
fixes
magne4000 Aug 17, 2024
5684fb0
fix: typings
magne4000 Aug 17, 2024
c1ac056
feat: initial support for runtime parameter
magne4000 Aug 18, 2024
d1c2f86
chore: update package.sjon
magne4000 Aug 18, 2024
117733a
chore: update package.sjon
magne4000 Aug 18, 2024
819f8a6
chore: dedupe webroute
magne4000 Aug 18, 2024
53407b3
chore: return context update
magne4000 Aug 18, 2024
043298c
feat: complete webroute support
magne4000 Aug 18, 2024
7b8a994
chore: better TS types for webroute generated exports
magne4000 Aug 18, 2024
edb8959
refactor: dts generation
magne4000 Aug 18, 2024
150d7c6
tests: auto generated exports typings
magne4000 Aug 18, 2024
ee3a451
chore: deps
magne4000 Aug 18, 2024
c267778
release: @universal-middleware/[email protected]
magne4000 Aug 18, 2024
57624e4
chore: prepare files for release
magne4000 Aug 18, 2024
43c8836
chore: update deno lock files
magne4000 Aug 18, 2024
cfa17a4
chore: deno lock false
magne4000 Aug 18, 2024
e008ac4
chore: deno --unstable-byonm
magne4000 Aug 18, 2024
c084f99
doc(universal-middleware): readme
magne4000 Aug 18, 2024
dbcd8ac
doc: symlink global README to universal-middleware package
magne4000 Aug 18, 2024
3d1a75e
doc: intro to universal-middleware usage
magne4000 Aug 18, 2024
88143c4
doc: README
magne4000 Aug 18, 2024
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
Prev Previous commit
Next Next commit
feat: esbuild plugin
  • Loading branch information
magne4000 committed Jul 16, 2024
commit 20cc163cf2fbce2660ea48e7d129e3fb32a5c89f
177 changes: 153 additions & 24 deletions packages/universal-middleware/src/build.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import { parse } from "node:path";
import { join, parse, resolve } from "node:path";
import { createUnplugin } from "unplugin";

const wrappers = ["hono", "express", "hattip"];
export interface Options {
servers?: (typeof defaultWrappers)[number][];
ignoreRecommendations?: boolean;
}

const defaultWrappers = ["hono", "express", "hattip"] as const;
const namespace = "virtual:universal-middleware";

function getVirtualInputs(type: "handler" | "middleware", handler: string) {
function getVirtualInputs(
type: "handler" | "middleware",
handler: string,
wrappers: ReadonlyArray<(typeof defaultWrappers)[number]> = defaultWrappers,
) {
const parsed = parse(handler);
return wrappers.map((server) => ({
server,
type,
@@ -13,7 +23,10 @@ function getVirtualInputs(type: "handler" | "middleware", handler: string) {
return `${namespace}:${this.server}:${this.type}:${this.handler}`;
},
get key() {
return `universal-${this.server}-${this.type}`;
return join(
parsed.dir,
`universal-${this.server}-${this.type}-${parsed.name}`,
);
},
}));
}
@@ -29,36 +42,80 @@ function filterInput(input: string) {
}

function normalizeInput(
input: undefined | string | string[] | Record<string, string>,
input:
| undefined
| string
| string[]
| Record<string, string>
| { in: string; out: string }[],
) {
const keys = new Set<string>();

function getTuple(key: string, value: string) {
if (keys.has(key)) {
throw new Error(`Conflict on entry ${key}: ${value}`);
} else {
keys.add(key);
}
return [key, value] as const;
}

if (typeof input === "string") {
const filtered = filterInput(input);
if (filtered) {
const parsed = parse(input);
const tuple = getTuple(join(parsed.dir, parsed.name), input);
return {
[parse(input).name]: input,
[tuple[0]]: tuple[1],
};
}
} else if (Array.isArray(input)) {
return Object.fromEntries(input.map((e) => [parse(e).name, e]));
return Object.fromEntries(
input.map((e) => {
if (typeof e === "string") {
const parsed = parse(e);
return getTuple(join(parsed.dir, parsed.name), e);
}
return getTuple(e.out, e.in);
}),
);
} else if (input && typeof input === "object") {
return input;
}
return null;
}

function appendVirtualInputs(input: Record<string, string>) {
function appendVirtualInputs(
input: Record<string, string>,
wrappers: ReadonlyArray<(typeof defaultWrappers)[number]> = defaultWrappers,
) {
Object.values(input).forEach((v) => {
const filtered = filterInput(v);
if (filtered) {
const virtualInputs = getVirtualInputs(filtered, v);
const virtualInputs = getVirtualInputs(filtered, v, wrappers);
virtualInputs.forEach((vinput) => {
input[vinput.key] = vinput.value;
});
}
});
}

const universalMiddleware = createUnplugin((options = {}) => {
function load(id: string) {
const [, , server, type, handler] = id.split(":");

const fn = type === "handler" ? "createHandler" : "createMiddleware";
const code = `import { ${fn} } from "@universal-middleware/${server}";
import ${type} from "${handler}";
export default ${fn}(${type});
`;
return { code };
}

function cleanPath(s: string) {
return s.replace(`?middleware`, "").replace(`?handler`, "");
}

const universalMiddleware = createUnplugin((options?: Options) => {
return {
name: namespace,
enforce: "post",
@@ -67,8 +124,92 @@ const universalMiddleware = createUnplugin((options = {}) => {
const normalizedInput = normalizeInput(opts.input);
if (normalizedInput) {
opts.input = normalizedInput;
appendVirtualInputs(opts.input);
appendVirtualInputs(opts.input, options?.servers);
}
},
},

esbuild: {
setup(builder) {
if (builder.initialOptions.bundle !== true) {
throw new Error(
"`bundle` options must be `true` for universal-middleware to work properly",
);
}

if (!options?.ignoreRecommendations) {
if (
builder.initialOptions.entryNames &&
!builder.initialOptions.entryNames.includes("[hash]")
) {
console.warn(
"esbuild config specifies `entryNames` without [hash]. This could lead to unknown behaviour",
);
}
if (!builder.initialOptions.splitting) {
console.warn(
"enable esbuild `splitting` option to reduce bundle size",
);
}
// TODO
}

if (!builder.initialOptions.entryNames) {
builder.initialOptions.entryNames = "[name]-[hash]";
}

if (builder.initialOptions.bundle) {
builder.initialOptions.external = [
...(builder.initialOptions.external ?? []),
"@universal-middleware/express",
"@universal-middleware/hattip",
"@universal-middleware/hono",
];
}

const normalizedInput = normalizeInput(
builder.initialOptions.entryPoints,
);

if (!normalizedInput) return;

builder.initialOptions.entryPoints = normalizedInput;
appendVirtualInputs(
builder.initialOptions.entryPoints,
options?.servers,
);

builder.onResolve(
{ filter: /^virtual:universal-middleware/ },
(args) => {
// console.log("onResolve:virtual", args);
return {
path: args.path,
namespace,
pluginData: {
resolveDir: args.resolveDir,
},
};
},
);

builder.onResolve({ filter: /\?(middleware|handler)$/ }, (args) => {
// console.log("onResolve:?", args);
return {
path: resolve(cleanPath(args.path)),
};
});

builder.onLoad({ filter: /.*/, namespace }, async (args) => {
// console.log("onLoad", args);
const { code } = load(args.path);

return {
contents: code,
resolveDir: args.pluginData.resolveDir,
loader: "js",
};
});
},
},

@@ -77,25 +218,13 @@ const universalMiddleware = createUnplugin((options = {}) => {
if (filtered) {
return id.replace(`?${filtered}`, "");
}
if (id.startsWith("file:")) {
id.replace("file:", "");
}
},

loadInclude(id) {
return id.startsWith(namespace);
},

load(id) {
const [, , server, type, handler] = id.split(":");

const fn = type === "handler" ? "createHandler" : "createMiddleware";
const code = `import { ${fn} } from "@universal-middleware/${server}";
import ${type} from "${handler}?${type}";
export default ${fn}(${type});
`;
return { code };
},
load,
};
});

Loading
Loading