Describe the solution
Esbuild's metafile is a great way to get additional information about a build, and for example use it in Esbuild Size Analyzer to understand the bundle size. If the CLI could "export" the Esbuild metafile it creates under the hood, that would be optimal.
As this is currently not implements, I quickly hacked together this almost-close-enough esbuild script that uses similar plugins. It brings most of my workers pretty close in size and code - so I am ok using this for now:
import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill'
import { NodeModulesPolyfillPlugin } from '@esbuild-plugins/node-modules-polyfill'
import { build } from 'esbuild'
import fs from 'fs'
import { relative, resolve } from "node:path";
import path from "path"
// ChatGPT
function isNodeCompat() {
const filePath = 'wrangler.toml'; // Hardcoded file path as 'wrangler.toml'
try {
// Read the content of the file
const data = fs.readFileSync(filePath, 'utf8');
// Parse the content to extract variables
const lines = data.split('\n');
const variables = {};
lines.forEach((line) => {
const match = line.match(/^\s*([\w_]+)\s*=\s*(.+)/);
if (match) {
const key = match[1];
const value = match[2].trim();
variables[key] = value;
}
});
// Check for the presence and value of node_compat
return variables.node_compat && variables.node_compat.toLowerCase() === 'true';
} catch (err) {
console.error('Error reading the file:', err);
return false;
}
}
let plugins = [
{
name: "Copy wasm next to bundle",
setup(build) {
build.onResolve({ filter: /.*\.(wasm)$/ }, async (args) => {
const to = resolve(path.join("dist-esbuild", args.path))
fs.mkdirSync(path.dirname(to), { recursive: true })
fs.copyFileSync(resolve(args.resolveDir, args.path), to)
return {
path: args.path,
external: true
};
});
},
},
// via https://github.com/cloudflare/workers-sdk/blob/3b5407a968189e60974233c5db8615162db37fd2/packages/wrangler/src/deployment-bundle/esbuild-plugins/cloudflare-internal.ts
{
name: "Cloudflare internal imports plugin",
setup(pluginBuild) {
pluginBuild.onResolve({ filter: /^cloudflare:.*/ }, () => {
return { external: true };
});
},
}
]
if (isNodeCompat() === true) {
console.log("found node_compat=true, adding plugins")
// via https://github.com/cloudflare/workers-sdk/blob/1b34878287e3c98e8743e0a9c30b860107d4fcbe/packages/wrangler/src/deployment-bundle/bundle.ts#L327-L329
plugins.push(
NodeGlobalsPolyfillPlugin({ buffer: true }),
NodeModulesPolyfillPlugin()
)
}
let result = await build({
plugins: plugins,
entryPoints: ['function.js'],
bundle: true,
outfile: 'dist-esbuild/function.js',
metafile: true,
format: 'esm',
sourcemap: 'external',
platform: 'node',
// via https://github.com/cloudflare/workers-sdk/blob/3b5407a968189e60974233c5db8615162db37fd2/packages/wrangler/src/deployment-bundle/bundle.ts#L27-L31
target: "es2022",
loader: { ".js": "jsx", ".mjs": "jsx", ".cjs": "jsx" },
// mainFields: ['workerd', 'worker', 'Here is our `esbuild.mjs`:
browser', 'module', 'main'],
conditions: ["workerd", "worker", "browser"]
})
fs.writeFileSync('dist-esbuild/meta.json', JSON.stringify(result.metafile, null, 2))
Describe the solution
Esbuild's metafile is a great way to get additional information about a build, and for example use it in Esbuild Size Analyzer to understand the bundle size. If the CLI could "export" the Esbuild metafile it creates under the hood, that would be optimal.
As this is currently not implements, I quickly hacked together this almost-close-enough esbuild script that uses similar plugins. It brings most of my workers pretty close in size and code - so I am ok using this for now: