Skip to content
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

Improve server index file matching #8957

Merged
merged 4 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 16 additions & 8 deletions packages/core/integration-tests/test/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,33 +36,41 @@ describe('html', function () {
assets: ['index.html'],
},
{
// index.html
name: 'index.html',
assets: ['index.html'],
},
{
// foo/index.html
name: 'index.html',
assets: ['index.html'],
},
{
type: 'png',
assets: ['100x100.png'],
// other.html
name: 'other.html',
assets: ['other.html'],
},
{
type: 'svg',
assets: ['icons.svg'],
// foo/other.html
name: 'other.html',
assets: ['other.html'],
},
{
type: 'css',
assets: ['index.css'],
type: 'svg',
assets: ['icons.svg'],
},
{
type: 'html',
assets: ['other.html'],
type: 'png',
assets: ['100x100.png'],
},
{
type: 'js',
assets: ['index.js'],
},
{
type: 'css',
assets: ['index.css'],
},
]);

let files = await outputFS.readdir(distDir);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Other foo page</title>
</head>
<body>
<div>Some other foo page...</div>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@

<body>
<h1>Hello world</h1>
<p>Linking to <a href="other.html">another page</a> and <a href="foo/index.html">another page</a></p>
<p>
Linking to <a href="other.html">another page</a> and <a href="foo/index.html">another page</a>
and <a href="foo/other.html">another page</a>
</p>
<a href="#hash_link">Hash link</a>
<a href="mailto:someone@acme.com">Mailto link</a>
<a href="tel:+33636757575">Tel link</a>
Expand Down
62 changes: 34 additions & 28 deletions packages/core/integration-tests/test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,48 +141,48 @@ describe('server', function () {

it('should serve a default page if the main bundle is an HTML asset', async function () {
let port = await getPort();
let b = bundler(
[
path.join(__dirname, '/integration/html/other.html'),
path.join(__dirname, '/integration/html/index.html'),
],
{
defaultTargetOptions: {
distDir,
},
config,
serveOptions: {
https: false,
port: port,
host: 'localhost',
},
let b = bundler(path.join(__dirname, '/integration/html/index.html'), {
defaultTargetOptions: {
distDir,
},
);
config,
serveOptions: {
https: false,
port: port,
host: 'localhost',
},
});

subscription = await b.watch();
await getNextBuild(b);

let rootIndexFile = await outputFS.readFile(
let rootIndex = await outputFS.readFile(
path.join(distDir, 'index.html'),
'utf8',
);

let data = await get('/', port);
assert.equal(data, rootIndexFile);

let fooIndexFile = await outputFS.readFile(
let other = await outputFS.readFile(
path.join(distDir, 'other.html'),
'utf8',
);
let fooIndex = await outputFS.readFile(
path.join(distDir, 'foo/index.html'),
'utf8',
);
let fooOther = await outputFS.readFile(
path.join(distDir, 'foo/other.html'),
'utf8',
);

data = await get('/foo', port);
assert.equal(data, fooIndexFile);

data = await get('/foo/bar', port);
assert.equal(data, fooIndexFile);
assert.equal(await get('/', port), rootIndex);
assert.equal(await get('/something', port), rootIndex);
assert.equal(await get('/other', port), other);
assert.equal(await get('/foo', port), rootIndex);
assert.equal(await get('/foo/', port), fooIndex);
assert.equal(await get('/foo/bar', port), fooIndex);
assert.equal(await get('/foo/other', port), fooOther);
});

it('should serve a default page if the main bundle is an HTML asset even if it is not called index', async function () {
it('should serve a default page if the single HTML bundle is not called index', async function () {
let port = await getPort();
let inputPath = path.join(__dirname, '/integration/html/other.html');
let b = bundler(inputPath, {
Expand Down Expand Up @@ -499,6 +499,12 @@ describe('server', function () {
assets: ['index.html'],
},
{
// other.html
name: 'other.html',
assets: ['other.html'],
},
{
// foo/other.html
name: 'other.html',
assets: ['other.html'],
},
Expand Down
46 changes: 34 additions & 12 deletions packages/reporters/dev-server/src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ export function setHeaders(res: Response) {
res.setHeader('Cache-Control', 'max-age=0, must-revalidate');
}

const SLASH_REGEX = /\//g;

export const SOURCES_ENDPOINT = '/__parcel_source_root';
const EDITOR_ENDPOINT = '/__parcel_launch_editor';
const TEMPLATE_404 = fs.readFileSync(
Expand Down Expand Up @@ -197,18 +199,38 @@ export default class Server {
if (htmlBundleFilePaths.length === 1) {
indexFilePath = htmlBundleFilePaths[0];
} else {
indexFilePath = htmlBundleFilePaths
.filter(v => {
let dir = path.posix.dirname(v);
let withoutExtension = path.posix.basename(
v,
path.posix.extname(v),
);
return withoutExtension === 'index' && req.url.startsWith(dir);
})
.sort((a, b) => {
return b.length - a.length;
})[0];
let bestMatch = null;
for (let bundle of htmlBundleFilePaths) {
let bundleDir = path.posix.dirname(bundle);
let bundleDirSubdir = bundleDir === '/' ? bundleDir : bundleDir + '/';
let withoutExtension = path.posix.basename(
bundle,
path.posix.extname(bundle),
);
let isIndex = withoutExtension === 'index';

let matchesIsIndex = null;
if (isIndex && req.url.startsWith(bundleDirSubdir)) {
// bundle is /bar/index.html and something inside of /bar/** was requested
matchesIsIndex = true;
} else if (req.url == path.posix.join(bundleDir, withoutExtension)) {
// bundle is /bar/foo.html and /bar/foo was requested
matchesIsIndex = false;
}
if (matchesIsIndex != null) {
let depth = bundle.match(SLASH_REGEX)?.length ?? 0;
if (
bestMatch == null ||
// This one is more specific (deeper)
bestMatch.depth < depth ||
// This one is just as deep, but the bundle name matches and not just index.html
(bestMatch.depth === depth && bestMatch.isIndex)
) {
bestMatch = {bundle, depth, isIndex: matchesIsIndex};
}
}
}
indexFilePath = bestMatch?.['bundle'] ?? htmlBundleFilePaths[0];
}

if (indexFilePath) {
Expand Down