-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Doubts and possible Features #2799
Comments
See here for an example: #337 (comment)
It’s unclear what is going on here. This screenshot doesn’t look like esbuild’s output. |
import { build } from "esbuild";
import { isBuiltin } from "module";
import { pathToFileURL } from "url";
import { fs, encode as toBuffer } from "../utils/index.js";
import resolver from "./resolver.js";
import css from "./extensions/css.js";
import html from "./extensions/html.js";
import json from "./extensions/json.js";
import file from "./extensions/file.js";
class Bundler {
cache = {};
config = {
bundle: true,
write: false,
outdir: "out",
legalComments: "none",
keepNames: true,
treeShaking: true,
incremental: true,
define: (() => {
const define = { "process.argv": JSON.stringify(process.argv) };
const keys = Object.keys(process.env);
for (let i = 0, len = keys.length; i < len; i++) {
define[`process.env.${keys[i]}`] = JSON.stringify(process.env[keys[i]]);
}
define[`process.env`] = JSON.stringify({});
return define;
})(),
};
constructor() {
this.cache = {};
}
init(filename, module, mode = process.env.NODE_ENV) {
const files = {};
const resources = {};
const config = Object.assign({}, this.config, {
entryPoints: [filename],
minify: mode === "production",
format: module ? "esm" : "iife",
plugins: [
{
name: "vision",
setup: (build) => {
const filter = /.*/;
build.onResolve({ filter }, (args) => this.resolver(args, files));
build.onLoad({ filter, namespace: "ignore" }, () => ({
contents: "",
}));
build.onLoad({ filter }, (args) => this.loader(args, resources));
},
},
],
});
return { config, resources, files };
}
async run(filename, { module = true, mode, encode = false, rebuild } = {}) {
console.time(filename);
const { config, resources, files } = this.init(filename, module, mode);
const { outputFiles, metafile } = await build(config);
if (rebuild) delete this.cache[rebuild];
let code = outputFiles?.[0]?.text || "";
if (encode && code != "") code = `data:text/javascript;base64,${toBuffer(code)}`;
console.timeEnd(filename, `Page ${filename} compiled and ready for connection`);
return { code, resources, files: Object.values(files).map((c) => c?.path) };
}
resolver(args, cache) {
switch (args.path) {
case "@vision/visionjs":
return { path: "window.vision", external: true };
case "@app":
return { path: "app", external: true };
case "@socket":
return { path: "socket", external: true };
default:
break;
}
if (!cache[args.path])
cache[args.path] = ((path) => {
if (fs.isAbsolute(path)) return { path: path };
if (isBuiltin(path)) return { path: path, namespace: "ignore" };
return {};
})(resolver(args.path, { cwd: args.resolveDir }));
return cache[args.path];
}
loader(args, bundleResources) {
const extension = fs.extname(args.path).slice(1);
if (["js", "mjs", "cjs"].includes(extension)) return { loader: "js" };
if (["jsx"].includes(extension)) return { loader: "jsx" };
if (["tsx", "ts", "mts", "cts"].includes(extension)) return { loader: "tsx" };
if (!this.cache[args.path])
this.cache[args.path] = ((source, transformer) =>
transformer(source, {
url: pathToFileURL(args.path),
extension,
isBundler: true,
}))(
...(() => {
if (["css", "sass", "scss"].includes(extension)) return [fs.readFileSync(args.path, "utf8"), css];
else if ("html" === extension) return [fs.readFileSync(args.path, "utf8"), html];
else if ("json" === extension) return [fs.readFileSync(args.path, "utf8"), json];
return [args.path, file];
})()
);
const { code, resources } = this.cache[args.path];
resources?.forEach(({ path, source, hash }) => (bundleResources[hash] = path || source));
return { contents: code, loader: "js" };
}
formatter(code, module) {
if (module)
return code.replace(/import[^;]*from\s?"window\.\w*";/g, (importer) => {
importer = importer.replace(/^import/, "const");
importer = importer.replace(/from\s?"window\./, this.mode === "production" ? "=window." : "= window.");
importer = importer.replace(/";$/, ";");
importer = importer.replace(/\bas\b/g, ":");
return importer;
});
return code.replace(/\w*\("window\.\w*"\)/g, (r) => r.match(/"(.*?)"/)?.[1] || "window");
}
}
export const bundle = ((b) => b.run.bind(b))(new Bundler());
export default Bundler; Yeah, the output is custom made |
You're going to have to debug this for yourself, sorry. One guess could be that node's single main thread remains blocked until the end of the build so the callbacks that run at the end of the build can only be run when the main thread becomes free. You'd have to debug that hypothesis on your end though. |
I'm closing this issue because this question was answered. |
Hey,
Quick summary I'm a senior Nodejs Developer/Architect, and currently, for my own entertainment I'm building a kind of Framework for React with Typescript support, I was using webpack for bundling, but since I was using esbuild transform API for the typescript and jsx, I thought of giving esbuild build API a shot.
First, one thing that I cannot find and do in esbuild, without using regex on the output code, is transforming imports to window references, this was something that I was able to configure in webpack without having a post-processor, it would be great if this was an option for the resolver plugin, like you have currently for the external option, something like global.
And finally, my last "issue" is performance when I'm running two different instances of Build API for different files, at basically the same time, this is required by my project since I want an active file watch system. What I am observing is that the different builds wait for each other, they all end at the same time...
The text was updated successfully, but these errors were encountered: