parcel: Index.html can not be omitted when serving multiple files

πŸ› bug report

When bundling and serve multiple entry files, / index.html can not be accessed with localhost:1234/

However, you can access it with localhost: 1234 / index.html

πŸŽ› Configuration (.babelrc, package.json, cli command)

//- src/index.pug
h1 hello world!
//- src/sub.pug
h1 sub page!
$ parcel 'src/**/*.pug'

πŸ€” Expected Behavior

When accessing localhost:1234/, β€œhello world!” is displayed

😯 Current Behavior

Accessing localhost:1234/ will display empty HTML

<html>
  <head></head>
  <body></body>
</html>

However, accessing localhost: 1234 / index.html will display the page correctly

πŸ’ Possible Solution

I do not know, but when accessed with / we have to make sure to check the existence of / index.html

🌍 Your Environment

Software Version(s)
Parcel v1.8.1
Node v8.11.1
npm/Yarn v6.0.0/v1.5.1
Operating System MacBook Pro (High Sierra)

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 16
  • Comments: 16 (3 by maintainers)

Commits related to this issue

Most upvoted comments

In the meantime, I have this workaround set up:

// run-parcel.js
const Bundler = require('parcel-bundler');
const express = require('express');

const bundler = new Bundler(['src/index.html', 'src/login.html', 'src/logout.html']);
const app = express();

app.get('/', (req, res, next) => {
  req.url = '/index.html';
  app._router.handle(req, res, next);
});

app.use(bundler.middleware());

const port = Number(process.env.PORT || 1234);
app.listen(port);
console.log(`listening at http://localhost:${port}`);

then run node run-parcel.js instead of parcel src/*.html.

Looks like lots of people requesting this feature, any word on whether there’s even a workaround to solve this?

Is there any news on this issue?

Same here, just ran into this, with the whole team confused as to what happened, when the second entry point was first added.

Same here. Any updates?

I’ve got a working solution for this (as explained in #1778) and can PR if this is agreeable.

Essentially, it enhances the respond method by looking for indexes (with a method replacing sendIndex called findIndex), looking for the main bundle as it does now, failing that looking for an HTML file called index.html.

 function respond() {
      let {pathname} = url.parse(req.url);
      if (bundler.error) {
        return send500(bundler.error);
      } else if (
        !pathname.startsWith(bundler.options.publicURL) ||
        path.extname(pathname) === ''
      ) {
        const index = findIndex(pathname)
        if (index) {
          req.url = `/${path.basename(index)}`;
          serve(req, res, send404);
        }
        else {
          send404();
        }
      } else {
        // Otherwise, serve the file from the dist folder
        req.url = pathname.slice(bundler.options.publicURL.length);
        return serve(req, res, send404);
      }
    }

    function findIndex(pathname) {
     // If the bundle is HTML, send that
      if (bundler.mainBundle.type === 'html') {
        return bundler.mainBundle.name;
      }
      else if (pathname === bundler.options.publicURL) {
        // if the pathname is empty, look for files named index.html in the bundle and send back the first one. If there's nothing, return null;
        const indexes = Array.from(bundler.mainBundle.childBundles).filter((asset) => path.basename(asset.name) === 'index.html');
        return indexes[0].name;
      }
      return null;
    }

Same happened here when parcel *.html.

That actually confused my colleague and thought the computer was under the weather lol It would be nice to solve this issue. It would avoid any confusion in the future.

I ended up writing a local plugin as a bandaid, until we get a legit fix. It uses the same modules included in Parcel v1. Only gotcha is you have to use the watch command to trigger it. Here’s an example of what it looks like - ymmv:

Running

parcel watch [entries] --serve
parcel watch [entries] --serve --open

Plugin Code

const serveStatic = require("serve-static"); // included in parcel v1
const { createServer } = require("http");

module.exports = (bundler) => {
  let server = null; // prevent from restarting on rebundle
  const openBrowser = process.argv.includes("--open");
  const useServer = process.argv.includes("--serve");

  bundler.on("bundled", () => {
    if (useServer && !server && bundler.options.watch) {      
      server = startServer(bundler.options.outDir, 8080, openBrowser);
    }
  });
}

function startServer(outDir, port, openBrowser) {
  const serve = serveStatic(outDir, { extensions: ["html"] });

  // 404 handler
  const redirect = (res) => {
    res.writeHead(302, { Location: "/404" });
    res.end();
  };

  // request handler
  const handler = (req, res) => {
    serve(req, res, () => redirect(res));
  };

  // start server
  return createServer(handler).listen(port, () => {
    // optional if you want to open the browser (included in parcel v1)
    if (openBrowser) require("opn")(`http://localhost:${port}`);
  });
}

Looking forward to this feature!