fix(docs-infra): configure Firebase to strip off the `.html` extension (#25999)

Firebase used to do it automatically (with `cleanUrls: true`), but it
stopped doing it unless the resulting URL corresponds to an existing
file (which is not always the case in angular.io; e.g. the resulting URL
might be matched by a new redirect rule).
This change in Firebase hosting behavior resulted in some URLs not being
correctly redirected (e.g. URLs to the archived v2 site, or `.html`
suffixed URLs from 3rd-party sites).

This commit fixes it, by configuring Firebase hosting to strip off the
`.html` extension and redirect (if no other redirect rule matched).

PR Close #25999
This commit is contained in:
George Kalpakas 2018-09-18 15:22:25 +03:00 committed by Kara Erickson
parent 3fb0da2de5
commit df5999a739
2 changed files with 29 additions and 10 deletions

View File

@ -104,7 +104,12 @@
{"type": 301, "source": "/guide/ngmodule", "destination": "/guide/ngmodules"},
{"type": 301, "source": "/guide/learning-angular*", "destination": "/guide/quickstart"},
{"type": 301, "source": "/testing", "destination": "/guide/testing"},
{"type": 301, "source": "/testing/**", "destination": "/guide/testing"}
{"type": 301, "source": "/testing/**", "destination": "/guide/testing"},
// Strip off the `.html` extension, because Firebase will not do this automatically any more
// (unless the new URL points to an existing file, which is not necessarily the case here).
{"type": 301, "source": "/:somePath*/:file.html", "destination": "/:somePath*/:file"},
{"type": 301, "source": "/:topLevelFile.html", "destination": "/:topLevelFile"}
],
"rewrites": [
{

View File

@ -13,11 +13,11 @@ describe(browser.baseUrl, () => {
afterEach(() => browser.waitForAngularEnabled(true));
describe('(with sitemap URLs)', () => {
page.sitemapUrls.forEach((url, i) => {
it(`should not redirect '${url}' (${i + 1}/${page.sitemapUrls.length})`, async () => {
await page.goTo(url);
page.sitemapUrls.forEach((path, i) => {
it(`should not redirect '${path}' (${i + 1}/${page.sitemapUrls.length})`, async () => {
await page.goTo(path);
const expectedUrl = stripTrailingSlash(page.baseUrl + url);
const expectedUrl = stripTrailingSlash(page.baseUrl + path);
const actualUrl = await getCurrentUrl();
expect(actualUrl).toBe(expectedUrl);
@ -38,14 +38,28 @@ describe(browser.baseUrl, () => {
});
});
describe('(with `.html` URLs)', () => {
['/path/to/file.html', '/top-level-file.html'].forEach(fromPath => {
const toPath = fromPath.replace(/\.html$/, '');
it(`should redirect '${fromPath}' to '${toPath}'`, async () => {
await page.goTo(fromPath);
const expectedUrl = page.baseUrl + toPath;
const actualUrl = await getCurrentUrl();
expect(actualUrl).toBe(expectedUrl);
});
});
});
describe('(with unknown URLs)', () => {
const unknownPageUrl = '/unknown/page';
const unknownResourceUrl = '/unknown/resource.ext';
const unknownPagePath = '/unknown/page';
const unknownResourcePath = '/unknown/resource.ext';
it('should serve `index.html` for unknown pages', async () => {
const aioShell = element(by.css('aio-shell'));
const heading = aioShell.element(by.css('h1'));
await page.goTo(unknownPageUrl);
await page.goTo(unknownPagePath);
expect(aioShell.isPresent()).toBe(true);
expect(heading.getText()).toMatch(/page not found/i);
@ -54,7 +68,7 @@ describe(browser.baseUrl, () => {
it('should serve a custom 404 page for unknown resources', async () => {
const aioShell = element(by.css('aio-shell'));
const heading = aioShell.element(by.css('h1'));
await page.goTo(unknownResourceUrl);
await page.goTo(unknownResourcePath);
expect(aioShell.isPresent()).toBe(true);
expect(heading.getText()).toMatch(/resource not found/i);
@ -62,7 +76,7 @@ describe(browser.baseUrl, () => {
it('should include a link to the home page in custom 404 page', async () => {
const homeNavLink = element(by.css('.nav-link.home'));
await page.goTo(unknownResourceUrl);
await page.goTo(unknownResourcePath);
expect(homeNavLink.isPresent()).toBe(true);