Code Study: How index.html Gets Built in Github Desktop

‘index.html’ sits between the main process and the renderer process. The main process triggers the load of the renderer process source code via ‘index.html’.

this.window.loadURL(encodePathAsUrl(__dirname, 'index.html'))

When ‘index.html’ gets loaded into the BrowserWindow, it further loads the renderer.js in the renderer process thanks to the <script> tag at the end of the html.

Here is the index.html file content in the production build.

<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
  <link href="renderer.css" rel="stylesheet"></head>
  <body>
    <div id='desktop-app-container'></div>
  <script type="text/javascript" src="renderer.js"></script></body>
</html>

The index.html file in the development build is slightly different.

<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
  </head>
  <body>
    <div id='desktop-app-container'></div>
  <script type="text/javascript" src="http://localhost:3000/build/renderer.js"></script></body>
</html>

However, if you look at the app/static/index.html file, the file does not have the <script> tag at the end. So you may wonder how the script gets injected into the final index.html.

<!DOCTYPE html>
<html>
  <head>
    <meta charset='UTF-8'>
  </head>
  <body>
    <div id='desktop-app-container'></div>
  </body>
</html>

The magic is done by webpack’s HtmlWebpackPlugin. See webpack.common.ts.

export const renderer = merge({}, commonConfig, {
  entry: { renderer: path.resolve(__dirname, 'src/ui/index') },
  target: 'electron-renderer',
  module: {
    rules: [
      {
        test: /\.(jpe?g|png|gif|ico)$/,
        use: ['file?name=[path][name].[ext]'],
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'static', 'index.html'),
      chunks: ['renderer'],
    }),
    new webpack.DefinePlugin(
      Object.assign({}, replacements, {
        __PROCESS_KIND__: JSON.stringify('ui'),
      })
    ),
  ],
})

HtmlWebpackPlugin is a webpack plugin that generates an HTML5 file for you that includes all your webpack bundles in the body using script tags. Here we use app/static/index.html as a template for the final index.html. The chunks property allows you to add only some chunks e.g only the ‘renderer’ chunk in the above case. The ‘renderer’ chunk was defined by the entry point entry: { renderer: path.resolve(__dirname, 'src/ui/index') },. If you are unfamiliar with webpack’s code splitting, you may want to read this stackoverflow thread. Defining an entry point will result in creating a chunk.

tags: GitHub Desktop - Electron