-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
idea: bundle embed or static file inside a single file. #3612
Comments
You are welcome to write a plugin to do that: https://esbuild.github.io/plugins/ |
Ok, let me try, this works, but I don't know how to filter by with type:embed, workaround by force a prefix import fs from 'node:fs/promises';
import path from 'node:path';
import * as esbuild from 'esbuild';
import type { Plugin } from 'esbuild';
let embedPlugin: Plugin = {
name: 'embed',
setup(build) {
build.onResolve({ filter: /^embed:.*/, namespace: 'file' }, (args) => {
switch (args.kind) {
case 'import-statement':
case 'dynamic-import':
break;
default:
return null;
}
let p = args.path.slice('embed:'.length);
if (p.startsWith('.')) {
p = path.resolve(args.resolveDir, p);
}
return {
path: p,
namespace: 'embed',
pluginData: {
resolveDir: args.resolveDir,
},
};
});
build.onLoad({ filter: /.*/, namespace: 'embed' }, async (args) => {
const resolveDir = args.pluginData.resolveDir;
if (args.with?.type !== 'embed') {
return null;
}
const cwd = args.with.cwd || '/app';
console.log(`embed ${path.relative(resolveDir, args.path)} to ${cwd}`);
const stat = await fs.stat(args.path);
if (!stat.isDirectory()) {
throw new Error(`Embed need a directory: ${args.path}`);
}
async function readDirectory(dir: string, basePath = dir, result: Record<string, any> = {}) {
const files = await fs.readdir(dir, { withFileTypes: true });
for (const file of files) {
const filePath = path.join(dir, file.name);
const relativePath = path.relative(basePath, filePath);
if (file.isDirectory()) {
readDirectory(filePath, basePath, result);
} else {
result[path.resolve(cwd, relativePath)] = await fs.readFile(filePath, 'utf8');
}
}
return result;
}
const o = await readDirectory(args.path);
return {
contents: `
import { memfs } from 'memfs';
const {fs:lfs,vol} = memfs(${JSON.stringify(o)}, '/app/');
const fs = lfs.promises
export {
fs,vol,lfs
}
`,
loader: 'js',
resolveDir: resolveDir,
};
});
},
};
await esbuild.build({
entryPoints: ['app.ts'],
bundle: true,
outfile: 'out.mjs',
plugins: [embedPlugin],
format: 'esm',
platform: 'node',
target: 'node20',
banner: {
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);var __filename;var __dirname;{const {fileURLToPath} = await import('url');const {dirname} = await import('path');var __filename = fileURLToPath(import.meta.url); __dirname = dirname(__filename)};`,
},
}); types.d.ts declare module 'embed:*' {
const fs: typeof import('node:fs/promises');
export { fs };
} app.ts import { fs } from './src/utils' with { type: 'embed', cwd: '/app/' };
console.log(`FS`, await fs.readdir('/app'));
console.log(`Content`, await fs.readFile('/app/Closer.ts', 'utf-8')); |
It's not just you. There isn't a way to declaratively filter by |
I want do where to ask about this feature, but I do think this is possible for esbuild.
I want to deliver a single file which can run as a server, that serve the static or dynamic ssr content.
I already use esbuild to bundle everything into a single
cli.mjs
, but esbuild left other content behind.I know I can do this by file loader like
import content from './index.html'
, but I think maybeIf this can return a streamich/memfs, maybe a hono server can accept a fs object to use the embeded files, do we can deliver a single file that can provide a functional web app.
Just like
//go:embed
for golang or include_dir for Rust.The text was updated successfully, but these errors were encountered: