Skip to content

Commit 2a4e2ce

Browse files
chore: Initial cut of refactoring esbuild to a generic function with our plugins extracted to their own files
1 parent 910537d commit 2a4e2ce

File tree

12 files changed

+233
-647
lines changed

12 files changed

+233
-647
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { BuildResult } from 'esbuild';
2+
3+
import path from 'path';
4+
5+
import esbuild from 'esbuild';
6+
7+
import type { BuildLitActionOptions } from './types';
8+
9+
import { aliasFetch } from './plugins/aliasFetch';
10+
import { createBundledFile } from './plugins/createBundledFile';
11+
import { wrapIIFEInStringPlugin } from './plugins/wrapIIFEInString';
12+
import { assertOutputFiles } from './utils';
13+
14+
/** Builds a Lit Action
15+
*/
16+
export async function buildLitAction({
17+
entryPoint,
18+
outdir,
19+
tsconfigPath,
20+
getLitActionHandler,
21+
}: BuildLitActionOptions) {
22+
const sourceDir = path.dirname(entryPoint);
23+
24+
await esbuild
25+
.build({
26+
outdir,
27+
tsconfig: tsconfigPath,
28+
entryPoints: [entryPoint],
29+
bundle: true,
30+
minify: false,
31+
sourcemap: false,
32+
treeShaking: true,
33+
metafile: true,
34+
plugins: [
35+
aliasFetch(),
36+
await wrapIIFEInStringPlugin(),
37+
await createBundledFile({ sourceDir: sourceDir, getLitActionHandler: getLitActionHandler }),
38+
],
39+
platform: 'browser',
40+
write: false,
41+
})
42+
.then((result: BuildResult) => {
43+
assertOutputFiles(result);
44+
45+
result.outputFiles.forEach((file) => {
46+
const bytes = file.text.length;
47+
const mbInDecimal = (bytes / 1_000_000).toFixed(4);
48+
49+
const filePathArr = file.path.split('/');
50+
console.log(
51+
`✅ ${filePathArr.slice(filePathArr.length - 2, filePathArr.length - 1)} - ${mbInDecimal} MB`,
52+
);
53+
});
54+
});
55+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { Plugin } from 'esbuild';
2+
3+
const DENO_FETCH_SHIM = './deno-fetch-shim.js';
4+
5+
export function aliasFetch(): Plugin {
6+
return {
7+
name: 'alias-fetch',
8+
setup(build) {
9+
build.onResolve({ filter: /^node-fetch$/ }, () => ({ path: DENO_FETCH_SHIM }));
10+
build.onResolve({ filter: /^cross-fetch(\/.*)?$/ }, () => ({ path: DENO_FETCH_SHIM }));
11+
},
12+
};
13+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import type { Plugin } from 'esbuild';
2+
3+
import fs from 'fs';
4+
import path from 'path';
5+
6+
/** @ts-expect-error No types for this pkg */
7+
import Hash from 'ipfs-only-hash';
8+
9+
import type { GetLitActionHandlerFunc } from '../types';
10+
11+
import { getMetadataJsonFileContent } from '../templates';
12+
import { assertOutputFiles, ensureDirectoryExistence } from '../utils';
13+
14+
export async function createBundledFile({
15+
sourceDir,
16+
getLitActionHandler,
17+
}: {
18+
sourceDir: string;
19+
getLitActionHandler: GetLitActionHandlerFunc;
20+
}): Promise<Plugin> {
21+
return {
22+
name: `create-bundled-lit-action-file`,
23+
setup(build) {
24+
build.initialOptions.write = false;
25+
26+
build.onEnd(async (result) => {
27+
if (result.errors.length > 0) {
28+
console.error('Build failed with errors:', result.errors);
29+
return;
30+
}
31+
32+
assertOutputFiles(result);
33+
34+
const outputFile = result.outputFiles[0];
35+
const content = outputFile.text;
36+
const ipfsCid = await Hash.of(content);
37+
38+
const outputPath = path.dirname(path.resolve(outputFile.path));
39+
40+
// Calculate the relative path from the output directory to the source directory so we can codegen the wrapper
41+
// using the passed `getLitActionHandler()` method
42+
const relativePathToSourceDir = path.relative(outputPath, sourceDir);
43+
44+
// Construct the path to the lit-action.ts file relative to the output directory
45+
const sourcePath = path.join(relativePathToSourceDir, `lit-action`);
46+
47+
// Generate the bundled source code with the computed relative path
48+
const bundledSource = getLitActionHandler({ outputPath, ipfsCid, sourcePath });
49+
50+
// Use the output path to determine the bundled path
51+
const bundledPath = path.join(outputPath, `bundled-lit-action.ts`);
52+
53+
ensureDirectoryExistence(bundledPath);
54+
fs.writeFileSync(bundledPath, bundledSource);
55+
56+
// Write metadata JSON
57+
// Use the directory of the generated output file
58+
const metadataPath = path.join(outputPath, `lit-action-metadata.json`);
59+
const metadataContent = getMetadataJsonFileContent({ ipfsCid });
60+
ensureDirectoryExistence(metadataPath);
61+
fs.writeFileSync(metadataPath, metadataContent);
62+
});
63+
},
64+
};
65+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { Plugin } from 'esbuild';
2+
3+
import fs from 'fs';
4+
import path from 'path';
5+
6+
/** @ts-expect-error No types for this pkg */
7+
import Hash from 'ipfs-only-hash';
8+
9+
import { getLitActionModuleFileContent } from '../templates';
10+
import { assertOutputFiles, ensureDirectoryExistence } from '../utils';
11+
12+
export async function wrapIIFEInStringPlugin(): Promise<Plugin> {
13+
return {
14+
name: 'wrap-iife-in-string',
15+
setup(build) {
16+
build.initialOptions.write = false;
17+
18+
build.onEnd(async (result) => {
19+
if (result.errors.length > 0) {
20+
console.error('Build failed with errors:', result.errors);
21+
return;
22+
}
23+
24+
assertOutputFiles(result);
25+
26+
const outputFile = result.outputFiles[0];
27+
const content = outputFile.text;
28+
const ipfsCid = await Hash.of(content);
29+
30+
const wrapped = getLitActionModuleFileContent({ content, ipfsCid });
31+
32+
// Use the path from the generated output file
33+
const outputPath = path.resolve(outputFile.path);
34+
35+
ensureDirectoryExistence(outputPath);
36+
fs.writeFileSync(outputPath, wrapped);
37+
});
38+
},
39+
};
40+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export function getLitActionModuleFileContent({
2+
ipfsCid,
3+
content,
4+
}: {
5+
ipfsCid: string;
6+
content: string;
7+
}) {
8+
return `/**
9+
* DO NOT EDIT THIS FILE. IT IS GENERATED ON BUILD.
10+
* @type {string}
11+
*/
12+
const code = ${JSON.stringify(content)};
13+
module.exports = {
14+
"code": code,
15+
"ipfsCid": "${ipfsCid}",
16+
};
17+
`;
18+
}
19+
20+
export function getMetadataJsonFileContent({ ipfsCid }: { ipfsCid: string }) {
21+
return `{
22+
"ipfsCid": "${ipfsCid}"
23+
}
24+
`;
25+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export type GetLitActionHandlerFunc = ({
2+
outputPath,
3+
ipfsCid,
4+
sourcePath,
5+
}: {
6+
outputPath: string;
7+
ipfsCid: string;
8+
sourcePath: string;
9+
}) => string;
10+
11+
export type BuildLitActionOptions = {
12+
entryPoint: string;
13+
outdir: string;
14+
tsconfigPath: string;
15+
getLitActionHandler: GetLitActionHandlerFunc;
16+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import type { BuildResult, OutputFile } from 'esbuild';
2+
3+
import fs from 'fs';
4+
import path from 'path';
5+
6+
export const ensureDirectoryExistence = (filePath: string) => {
7+
const dirname = path.dirname(filePath);
8+
if (!fs.existsSync(dirname)) {
9+
fs.mkdirSync(dirname, { recursive: true });
10+
}
11+
};
12+
13+
export function assertOutputFiles(
14+
result: BuildResult,
15+
): asserts result is BuildResult & { outputFiles: OutputFile[] } {
16+
if (!result.outputFiles) {
17+
throw new Error('No output files found');
18+
}
19+
}

packages/libs/lit-action-bundler/src/scripts/buildAllActions.js

Lines changed: 0 additions & 133 deletions
This file was deleted.

0 commit comments

Comments
 (0)