@hpcc-js/esbuild-plugins 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +206 -7
- package/dist/index.js.map +4 -4
- package/package.json +3 -2
- package/src/build.ts +140 -0
- package/src/exclude-sourcemap.ts +20 -0
- package/src/index.ts +5 -0
- package/src/problem-matcher.ts +22 -0
- package/src/rebuild-logger.ts +22 -0
- package/src/sfx-wrapper.ts +108 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hpcc-js/esbuild-plugins",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Various esbuild plugins",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
"types": "./types/index.d.ts",
|
|
18
18
|
"files": [
|
|
19
19
|
"dist/**/*",
|
|
20
|
+
"src/**/*",
|
|
20
21
|
"types/**/*"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"clean": "rimraf ./dist ./types",
|
|
24
25
|
"build-types": "tsc --project tsconfig.json --emitDeclarationOnly",
|
|
25
26
|
"build-types-watch": "npm run build-types -- --watch",
|
|
26
|
-
"build-ts-dev": "esbuild ./src/index.ts --platform=node --format=esm --bundle --
|
|
27
|
+
"build-ts-dev": "esbuild ./src/index.ts --platform=node --format=esm --bundle --sourcemap --outfile=./dist/index.js",
|
|
27
28
|
"build-ts": "npm run build-ts-dev -- --minify",
|
|
28
29
|
"build-ts-watch": "npm run build-ts-dev -- --watch",
|
|
29
30
|
"build-dev": "run-p build-types build-ts-dev",
|
package/src/build.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as process from "process";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as esbuild from "esbuild";
|
|
5
|
+
import type { BuildOptions, Format } from "esbuild";
|
|
6
|
+
import { umdWrapper } from "esbuild-plugin-umd-wrapper";
|
|
7
|
+
import yargs from "yargs";
|
|
8
|
+
import { hideBin } from "yargs/helpers";
|
|
9
|
+
import { rebuildLogger } from "./rebuild-logger.ts";
|
|
10
|
+
import { sfxWasm } from "./sfx-wrapper.ts";
|
|
11
|
+
|
|
12
|
+
const pkg = JSON.parse(readFileSync(path.join(process.cwd(), "./package.json"), "utf8"));
|
|
13
|
+
const NODE_MJS = pkg.type === "module" ? "js" : "mjs";
|
|
14
|
+
const NODE_CJS = pkg.type === "module" ? "cjs" : "js";
|
|
15
|
+
|
|
16
|
+
const myYargs = yargs(hideBin(process.argv));
|
|
17
|
+
myYargs
|
|
18
|
+
.usage("Usage: node esbuild.mjs [options]")
|
|
19
|
+
.demandCommand(0, 0)
|
|
20
|
+
.example("node esbuild.mjs --watch", "Bundle and watch for changes")
|
|
21
|
+
.option("mode", {
|
|
22
|
+
alias: "m",
|
|
23
|
+
describe: "Build mode",
|
|
24
|
+
choices: ["development", "production"],
|
|
25
|
+
default: "production"
|
|
26
|
+
})
|
|
27
|
+
.option("w", {
|
|
28
|
+
alias: "watch",
|
|
29
|
+
describe: "Watch for changes",
|
|
30
|
+
type: "boolean"
|
|
31
|
+
})
|
|
32
|
+
.help("h")
|
|
33
|
+
.alias("h", "help")
|
|
34
|
+
.epilog("https://github.com/hpcc-systems/hpcc-js-wasm")
|
|
35
|
+
;
|
|
36
|
+
const argv = await myYargs.argv;
|
|
37
|
+
const isDevelopment = argv.mode === "development";
|
|
38
|
+
const isProduction = !isDevelopment;
|
|
39
|
+
const isWatch = argv.watch;
|
|
40
|
+
|
|
41
|
+
export function build(config: BuildOptions) {
|
|
42
|
+
if (isDevelopment && Array.isArray(config.entryPoints)) {
|
|
43
|
+
console.log("Start: ", config.entryPoints[0], config.outfile);
|
|
44
|
+
}
|
|
45
|
+
return esbuild.build({
|
|
46
|
+
...config,
|
|
47
|
+
sourcemap: "linked",
|
|
48
|
+
plugins: [
|
|
49
|
+
...(config.plugins ?? []),
|
|
50
|
+
sfxWasm()
|
|
51
|
+
]
|
|
52
|
+
}).finally(() => {
|
|
53
|
+
if (isDevelopment && Array.isArray(config.entryPoints)) {
|
|
54
|
+
console.log("Stop: ", config.entryPoints[0], config.outfile);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function watch(config: BuildOptions) {
|
|
60
|
+
await build(config);
|
|
61
|
+
return esbuild.context({
|
|
62
|
+
...config,
|
|
63
|
+
sourcemap: "external",
|
|
64
|
+
plugins: [
|
|
65
|
+
...(config.plugins ?? []),
|
|
66
|
+
rebuildLogger(config),
|
|
67
|
+
sfxWasm()
|
|
68
|
+
]
|
|
69
|
+
}).then(ctx => {
|
|
70
|
+
return ctx.watch();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function buildWatch(config: BuildOptions) {
|
|
75
|
+
return isWatch ? watch(config) : build(config);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function browserTpl(input: string, output: string, format: Format | "umd" = "esm", globalName?: string, external: string[] = []) {
|
|
79
|
+
return buildWatch({
|
|
80
|
+
entryPoints: [input],
|
|
81
|
+
outfile: `${output}.${format === "esm" ? "js" : "umd.js"}`,
|
|
82
|
+
platform: "browser",
|
|
83
|
+
target: "es2022",
|
|
84
|
+
format: format as Format,
|
|
85
|
+
globalName,
|
|
86
|
+
bundle: true,
|
|
87
|
+
minify: isProduction,
|
|
88
|
+
external,
|
|
89
|
+
plugins: format === "umd" ? [umdWrapper()] : []
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function browserBoth(input: string, output: string, globalName?: string, external: string[] = []) {
|
|
94
|
+
return Promise.all([
|
|
95
|
+
browserTpl(input, output, "esm", globalName, external),
|
|
96
|
+
browserTpl(input, output, "umd", globalName, external)
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function nodeTpl(input: string, output: string, format: Format | "umd" = "esm", external: string[] = []) {
|
|
101
|
+
return buildWatch({
|
|
102
|
+
entryPoints: [input],
|
|
103
|
+
outfile: `${output}.${format === "esm" ? NODE_MJS : NODE_CJS}`,
|
|
104
|
+
platform: "node",
|
|
105
|
+
target: "node20",
|
|
106
|
+
format: format as Format,
|
|
107
|
+
bundle: true,
|
|
108
|
+
minify: isProduction,
|
|
109
|
+
external
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function neutralTpl(input: string, output: string, format: Format | "umd" = "esm", globalName?: string, external: string[] = []) {
|
|
114
|
+
return buildWatch({
|
|
115
|
+
entryPoints: [input],
|
|
116
|
+
outfile: `${output}.${format === "esm" ? "js" : "umd.js"}`,
|
|
117
|
+
platform: "neutral",
|
|
118
|
+
target: "es2022",
|
|
119
|
+
format: format as Format,
|
|
120
|
+
globalName,
|
|
121
|
+
bundle: true,
|
|
122
|
+
minify: isProduction,
|
|
123
|
+
external,
|
|
124
|
+
plugins: format === "umd" ? [umdWrapper()] : []
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function nodeBoth(input: string, output: string, external: string[] = []) {
|
|
129
|
+
return Promise.all([
|
|
130
|
+
nodeTpl(input, output, "esm", external),
|
|
131
|
+
nodeTpl(input, output, "cjs", external)
|
|
132
|
+
]);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function bothTpl(input: string, output: string, globalName?: string, external: string[] = []) {
|
|
136
|
+
return Promise.all([
|
|
137
|
+
browserBoth(input, output, globalName, external),
|
|
138
|
+
nodeTpl(input, output, "cjs", external)
|
|
139
|
+
]);
|
|
140
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import type { PluginBuild, Plugin } from "esbuild";
|
|
3
|
+
|
|
4
|
+
export interface ExcludeSourcemapOptions {
|
|
5
|
+
filter: RegExp;
|
|
6
|
+
}
|
|
7
|
+
export function excludeSourcemap(opts: ExcludeSourcemapOptions): Plugin {
|
|
8
|
+
return {
|
|
9
|
+
name: "exclude-sourcemap",
|
|
10
|
+
|
|
11
|
+
setup(build: PluginBuild) {
|
|
12
|
+
build.onLoad({ filter: opts.filter }, async args => {
|
|
13
|
+
return {
|
|
14
|
+
contents: await readFile(args.path, "utf8") + "\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==",
|
|
15
|
+
loader: "default",
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PluginBuild, Plugin } from "esbuild";
|
|
2
|
+
|
|
3
|
+
export function problemMatcher(): Plugin {
|
|
4
|
+
return {
|
|
5
|
+
name: "problem-matcher",
|
|
6
|
+
|
|
7
|
+
setup(build: PluginBuild) {
|
|
8
|
+
|
|
9
|
+
build.onStart(() => {
|
|
10
|
+
console.log("[watch] build started");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
build.onEnd((result) => {
|
|
14
|
+
result.errors.forEach(({ text, location }) => {
|
|
15
|
+
console.error(`✘ [ERROR] ${text}`);
|
|
16
|
+
console.error(` ${location?.file}:${location?.line}:${location?.column}:`);
|
|
17
|
+
});
|
|
18
|
+
console.log("[watch] build finished");
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PluginBuild, Plugin } from "esbuild";
|
|
2
|
+
|
|
3
|
+
export interface RebuildLoggerOptions {
|
|
4
|
+
outfile?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function rebuildLogger(opts: RebuildLoggerOptions): Plugin {
|
|
8
|
+
return {
|
|
9
|
+
name: "rebuild-logger",
|
|
10
|
+
|
|
11
|
+
setup(build: PluginBuild) {
|
|
12
|
+
|
|
13
|
+
build.onStart(() => {
|
|
14
|
+
console.log("[watch] build started");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
build.onEnd(() => {
|
|
18
|
+
console.log(`Rebuilt ${opts.outfile ?? "Unknown"}`);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { Base91 } from "@hpcc-js/wasm-base91";
|
|
4
|
+
import { Zstd } from "@hpcc-js/wasm-zstd";
|
|
5
|
+
import type { Plugin, PluginBuild } from "esbuild";
|
|
6
|
+
|
|
7
|
+
function tpl(wasmJsPath: string, base91Wasm: string, base91CompressedWasm: string) {
|
|
8
|
+
|
|
9
|
+
const compressed = (base91CompressedWasm.length + 8 * 1024) <= base91Wasm.length;
|
|
10
|
+
const wasmJsExists = existsSync(wasmJsPath);
|
|
11
|
+
|
|
12
|
+
return `\
|
|
13
|
+
${compressed ? 'import { decompress } from "fzstd";' : ''}
|
|
14
|
+
${wasmJsExists ? `import wrapper from "${wasmJsPath}";` : ''}
|
|
15
|
+
|
|
16
|
+
const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_\`{|}~"';
|
|
17
|
+
|
|
18
|
+
function decode(raw: string): Uint8Array {
|
|
19
|
+
const len = raw.length;
|
|
20
|
+
const ret: number[] = [];
|
|
21
|
+
|
|
22
|
+
let b = 0;
|
|
23
|
+
let n = 0;
|
|
24
|
+
let v = -1;
|
|
25
|
+
|
|
26
|
+
for (let i = 0; i < len; i++) {
|
|
27
|
+
const p = table.indexOf(raw[i]);
|
|
28
|
+
/* istanbul ignore next */
|
|
29
|
+
if (p === -1) continue;
|
|
30
|
+
if (v < 0) {
|
|
31
|
+
v = p;
|
|
32
|
+
} else {
|
|
33
|
+
v += p * 91;
|
|
34
|
+
b |= v << n;
|
|
35
|
+
n += (v & 8191) > 88 ? 13 : 14;
|
|
36
|
+
do {
|
|
37
|
+
ret.push(b & 0xff);
|
|
38
|
+
b >>= 8;
|
|
39
|
+
n -= 8;
|
|
40
|
+
} while (n > 7);
|
|
41
|
+
v = -1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (v > -1) {
|
|
46
|
+
ret.push((b | v << n) & 0xff);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return new Uint8Array(ret);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const blobStr = '${compressed ? base91CompressedWasm : base91Wasm}';
|
|
53
|
+
|
|
54
|
+
let g_module: Uint8Array | undefined;
|
|
55
|
+
let g_wasmBinary: Uint8Array | undefined;
|
|
56
|
+
export default function() {
|
|
57
|
+
if (!g_wasmBinary) {
|
|
58
|
+
g_wasmBinary = ${compressed ? "decompress(decode(blobStr))" : "decode(blobStr)"};
|
|
59
|
+
}
|
|
60
|
+
${!wasmJsExists ? `\
|
|
61
|
+
return g_wasmBinary;
|
|
62
|
+
`: `\
|
|
63
|
+
if (!g_module) {
|
|
64
|
+
g_module = wrapper({
|
|
65
|
+
wasmBinary: g_wasmBinary,
|
|
66
|
+
locateFile: undefined
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return g_module;
|
|
70
|
+
`}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function reset() {
|
|
74
|
+
if (g_module) {
|
|
75
|
+
g_module = undefined;
|
|
76
|
+
}
|
|
77
|
+
} `.trim();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function wrap(path: string) {
|
|
81
|
+
const base91 = await Base91.load();
|
|
82
|
+
const zstd = await Zstd.load();
|
|
83
|
+
|
|
84
|
+
const wasm = await readFile(path);
|
|
85
|
+
path = path.replace(/\.js$/, ".xxx");
|
|
86
|
+
const wasmJsPath = path.replace(/\.wasm$/, ".js");
|
|
87
|
+
const base91Wasm = base91.encode(wasm);
|
|
88
|
+
const compressedWasm = zstd.compress(wasm);
|
|
89
|
+
const base91CompressedWasm = base91.encode(compressedWasm);
|
|
90
|
+
|
|
91
|
+
return tpl(wasmJsPath, base91Wasm, base91CompressedWasm);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function sfxWasm(): Plugin {
|
|
95
|
+
return {
|
|
96
|
+
name: "sfx-wasm",
|
|
97
|
+
|
|
98
|
+
setup(build: PluginBuild) {
|
|
99
|
+
|
|
100
|
+
build.onLoad({ filter: /\.wasm$/ }, async args => {
|
|
101
|
+
return {
|
|
102
|
+
contents: await wrap(args.path),
|
|
103
|
+
loader: "ts",
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|