Skip to content

Commit 63063be

Browse files
committed
feat: add lit-actions-ts-bundling example
1 parent bdf8920 commit 63063be

File tree

17 files changed

+1756
-4
lines changed

17 files changed

+1756
-4
lines changed

lit-actions-ts-bundling/README.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Getting started
2+
3+
```
4+
npm install
5+
```
6+
7+
## Start writing your Lit Action like a regular TS
8+
9+
- See demo in `./src/lit-actions/hello-world.ts`
10+
11+
## To build and bundle the TS Lit Action code
12+
13+
```
14+
npm run build
15+
```
16+
17+
This will build and bundle all files in `./src/lit-actions/*.ts`, and the output will be in `./src/lit-actions/dist`.
18+
19+
## Getting the bundled Lit Action Code
20+
21+
In your `./src/index.ts` file, you can import the bundled Lit Action code like this:
22+
23+
```ts
24+
import { code } from "./lit-actions/dist/hello-world.js";
25+
26+
console.log("litActionCode:", code);
27+
```
28+
29+
## output
30+
31+
```
32+
npm run build
33+
34+
35+
> node esbuild.config.js
36+
37+
🗂️ File: src/lit-actions/dist/hello-world.js
38+
Size: 0.0251 MB (decimal) | 0.0239 MB (binary)
39+
================================================
40+
✅ Lit actions built successfully in 0.02 seconds
41+
```
+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { Buffer } from 'buffer';
2+
globalThis.Buffer = Buffer;
+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
const fs = require("fs");
2+
const path = require("path");
3+
const esbuild = require("esbuild");
4+
const glob = require("glob");
5+
6+
// automatically find all files in the src/lit-actions/src directory
7+
const ENTRY_POINTS = glob.sync("./src/lit-actions/**/*.ts");
8+
9+
const configs = ENTRY_POINTS.map((entryPoint) => {
10+
// Read the content and extract the comment block
11+
const content = fs.readFileSync(entryPoint, "utf8");
12+
const commentBlock = content.match(/\/\*\*([\s\S]*?)\*\//)?.[1];
13+
14+
if (!commentBlock) return { entryPoint };
15+
16+
// Find all lines containing 'inject' or 'inject:'
17+
const injectLines = commentBlock
18+
.split("\n")
19+
.filter((line) => line.includes("inject"));
20+
21+
// Extract the injected values
22+
const injectedValues = injectLines.map((line) => {
23+
const match = line.match(/inject:?\s*([^\s]+)/);
24+
return match ? match[1] : null;
25+
});
26+
27+
// for each injected value, check if the file exist
28+
injectedValues.forEach((injectedValue) => {
29+
if (injectedValue && !fs.existsSync(injectedValue)) {
30+
throw new Error(`❌ File ${injectedValue} does not exist`);
31+
}
32+
});
33+
34+
return {
35+
entryPoint,
36+
...(injectedValues.length > 0 && { injectedValues }),
37+
};
38+
});
39+
40+
const ensureDirectoryExistence = (filePath) => {
41+
const dirname = path.dirname(filePath);
42+
if (!fs.existsSync(dirname)) {
43+
fs.mkdirSync(dirname, { recursive: true });
44+
}
45+
};
46+
47+
const wrapIIFEInStringPlugin = {
48+
name: "wrap-iife-in-string",
49+
setup(build) {
50+
// Ensure write is set to false so our plugin will always receive outputFiles
51+
build.initialOptions.write = false;
52+
53+
build.onEnd((result) => {
54+
if (result.errors.length > 0) {
55+
console.error("Build failed with errors:", result.errors);
56+
return;
57+
}
58+
59+
result.outputFiles.forEach((outputFile) => {
60+
let content = outputFile.text;
61+
62+
// IMPORTANT: if minify is disabled, we need to:
63+
// 1. remove var import_ethers = __require("ethers");
64+
// 2. remove import_ethers.
65+
content = content
66+
.replace(/var import_ethers = __require\("ethers"\);/g, "")
67+
.replace(/import_ethers\./g, "");
68+
69+
// IMPORTANT: if minify is enabled, we need to:
70+
// 1. remove var t=o(\"ethers\");
71+
// 2. replace t.ethers to ethers
72+
content = content
73+
.replace(/var t=o\("ethers"\);/g, "")
74+
.replace(/t\.ethers/g, "ethers");
75+
76+
// Use JSON.stringify to safely encode the content
77+
const wrappedContent = `/**
78+
* DO NOT EDIT THIS FILE. IT IS GENERATED ON BUILD. RUN \`yarn generate-lit-actions\` IN THE ROOT DIRECTORY TO UPDATE THIS FILE.
79+
*
80+
* @type { string } code - Lit Action code. You want to use the content in the "code" constant and NOT the content of this file.
81+
*
82+
*/
83+
export const code = ${JSON.stringify(content, null, 2)};
84+
`;
85+
86+
// Ensure the output directory exists
87+
const outputPath = path.resolve(outputFile.path);
88+
ensureDirectoryExistence(outputPath);
89+
90+
// Write the modified content back to the output file
91+
fs.writeFileSync(outputPath, wrappedContent);
92+
});
93+
});
94+
},
95+
};
96+
97+
const promises = configs.map((config) => {
98+
return esbuild.build({
99+
entryPoints: [config.entryPoint],
100+
bundle: true,
101+
minify: true,
102+
treeShaking: true,
103+
outdir: "./src/lit-actions/dist",
104+
external: ["ethers"],
105+
plugins: [wrapIIFEInStringPlugin],
106+
...(config?.injectedValues && { inject: config?.injectedValues }),
107+
});
108+
});
109+
110+
// resolve all promises
111+
const startTime = Date.now();
112+
113+
Promise.all(promises)
114+
.then((results) => {
115+
results.forEach((result) => {
116+
// Check if outputFiles is defined and is an array
117+
if (result.outputFiles && Array.isArray(result.outputFiles)) {
118+
result.outputFiles.forEach((file) => {
119+
const bytes = file.contents.length;
120+
const mbInBinary = (bytes / (1024 * 1024)).toFixed(4);
121+
const mbInDecimal = (bytes / 1_000_000).toFixed(4);
122+
const fileName = path.relative(process.cwd(), file.path);
123+
console.log(`🗂️ File: ${fileName}`);
124+
console.log(
125+
` Size: ${mbInDecimal} MB (decimal) | ${mbInBinary} MB (binary)`
126+
);
127+
});
128+
}
129+
});
130+
131+
const endTime = Date.now();
132+
const buildTime = (endTime - startTime) / 1000; // Convert to seconds
133+
const msg = `✅ Lit actions built successfully in ${buildTime.toFixed(
134+
2
135+
)} seconds`;
136+
console.log(
137+
msg
138+
.split("")
139+
.map((char) => "=")
140+
.join("")
141+
);
142+
console.log(msg);
143+
})
144+
.catch((error) => {
145+
console.error("❌ Error building lit actions: ", error);
146+
process.exit(1);
147+
});

0 commit comments

Comments
 (0)