esbuild bundle html css js into a single file

368 Views Asked by At

i have a directory named src with 3 files:

  • index.html
  • index.js
  • index.css

this is how my html file looks like what esbuild recommends

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="index.css" />
  </head>

  <body>
    <script src="./index.js"></script>
  </body>
</html>

i would like to bundle all of them into a single html file, such as

<!doctype html>
<html>
  <head>
    <style>
      /* the content of index.css */
    </style>
  </head>

  <body>
    <script>
       // the content of index.js
    </script>
  </body>
</html>

but i failed to do it with esbuild even after digging heavily into esbuild loaders. would appreciate your help.

1

There are 1 best solutions below

2
On

I also saw no direct way of doing this with esbuild, but this is how I achieved the same goal (simplified for brevity);


// build.mjs

import mustache from "mustache";
import * as esbuild from "esbuild";

const htmlTemplate = `<!doctype html>
<html>
  <head>
    <style>
      /* the content of index.css */
      {{{ styling }}}
    </style>
  </head>

  <body>
    <script>
       // the content of index.js
       {{{ script }}}
    </script>
  </body>
</html>
`;

const scriptInput = `
const x = 1;
window.alert(x);
`;

const stylingInput = `
p {
    color: red;
}
`;

const transformOptions = {
    minify: true
};

const scriptTransformResult = await esbuild.transform(scriptInput, {
  ...transformOptions,
  loader: "js",
});
const script = scriptTransformResult.code;

const stylingTransformResult = await esbuild.transform(stylingInput, {
  ...transformOptions,
  loader: "css",
});
const styling = stylingTransformResult.code;

const model = {
  script,
  styling,
};

const htmlView = mustache.render(htmlTemplate, model);
console.log(htmlView);

And the output looks like so;

$ node build.mjs
<!doctype html>
<html>
  <head>
    <style>
      /* the content of index.css */
      p{color:red}

    </style>
  </head>

  <body>
    <script>
       // the content of index.js
       const x=1;window.alert(x);

    </script>
    <p>red</p>
  </body>
</html>

The dependencies I used were [email protected] and [email protected].

You could modify the above to read/write the scripts to and from disk using the node:fs module or to an S3 bucket or whatever. I removed that logic from the example above to show the core idea.

You could also swap out mustache with whatever is trending nowadays if you want.

Having said that, this approach has some disadvantages like lack of bundling and plugin support. Maybe one could use temporary files and a templating engine if you want these features.

Thanks.