tooling.report

feature

Inlining scripts

Can processed scripts be inlined into HTML?

Person in shorts with blue hair walking left

Introduction

There are a number of cases where small amounts of JavaScript are most effectively delivered inline in an HTML page. Some common examples are analytics code that needs to run early on during page loading, or hashed URL mappings that can't be cached. In these cases, it's often useful or even required that the JavaScript is generated by a build tool, which means that tool must also provide a way to inline the code into HTML documents.

The Test

This test emulates a minimal two-page website, with "index" and "profile" pages. Each page has its own script, but the two depend on a common library and also each lazily import a second shared module, creating a split point. Building the pages should bundle and inline the scripts for index.html, but preserve the scripts from profile.html as well as the lazy-loaded module.

index.js

import { logCaps } from './utils.js';
import { exclaim } from './exclaim.js';
logCaps(exclaim('This is index'));
import('./lazy.js');

exclaim.js

export function exclaim(msg) {
  return msg + '!';
}

profile.js

import { logCaps } from './utils.js';
logCaps('This is profile');
import('./lazy.js');

utils.js

export function logCaps(msg) {
  console.log(msg.toUpperCase());
}

lazy.js

console.log('Totally lazy');

The build result should be include two HTML files. index.html should contain inlinined bundle for index.js and its dependencies. profile.html should reference the bundle for profile.js as an external script. Both pages should reference the same lazy-loaded bundle for lazy.js.

Conclusion

browserify

Although Browserify has the factor-bundle plug-in, it is not built for complex dependency splitting.

Issues

  • N/A
parcel

Parcel has an undocumented way to do this:

<!DOCTYPE html>
<script src="whatever.js"></script>

The above will result in a separate resource for the script. However:

<!DOCTYPE html>
<script>
  import './whatever.js';
</script>

The above will inline the script into the page.

However, this creates inline sourcemaps in your code, which will inflate the size of your JavaScript in production. The only way to avoid this is to disable sourcemaps altogether.

Issues

rollup

It's possible with some hacking. It involves creating a separate sub-build for each inline entry point. It works in this case, but it feels fragile.

Issues

webpack

The standard plugin for handling HTML in Webpack's ecosystem is html-webpack-plugin. Rather than the HTML-first approach shown in the HTML test, html-webpack-plugin allows templating of HTML files based on Webpack's output modules and assets. Each HtmlWebpackPlugin instance creates a single HTML file as its output, which means this test requires instantiating multiple plugins that each spawn their own child compiler.