Updates hydration scripts to use absolute paths (#3422)

* WIP: proof of concept fix to use absolute paths

* correct fix to handle absolute paths and config.base

* adding tests for hydration scripts with config.base

* chore: add changeset

* fix: ensure posix paths are used for Windows compat
This commit is contained in:
Tony Sullivan 2022-05-23 20:52:48 +00:00 committed by GitHub
parent 28ede84a88
commit 0209d6276c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 7 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Updates component hydration scripts to use absolute paths for script imports

View file

@ -18,7 +18,7 @@ import {
createLinkStylesheetElementSet,
createModuleScriptElementWithSrcSet,
} from '../render/ssr-element.js';
import { prependForwardSlash } from '../path.js';
import { joinPaths, prependForwardSlash } from '../path.js';
export const pagesVirtualModuleId = '@astrojs-pages-virtual-entry';
export const resolvedPagesVirtualModuleId = '\0' + pagesVirtualModuleId;
@ -108,7 +108,7 @@ export class App {
throw new Error(`Unable to resolve [${specifier}]`);
}
const bundlePath = manifest.entryModules[specifier];
return bundlePath.startsWith('data:') ? bundlePath : prependForwardSlash(bundlePath);
return bundlePath.startsWith('data:') ? bundlePath : prependForwardSlash(joinPaths(manifest.base, bundlePath));
},
route: routeData,
routeCache: this.#routeCache,

View file

@ -22,6 +22,7 @@ export type SerializedRouteInfo = Omit<RouteInfo, 'routeData'> & {
export interface SSRManifest {
routes: RouteInfo[];
site?: string;
base?: string;
markdown: MarkdownRenderingOptions;
pageMap: Map<ComponentPath, ComponentInstance>;
renderers: SSRLoadedRenderer[];

View file

@ -219,9 +219,7 @@ async function generatePath(
}
throw new Error(`Cannot find the built path for ${specifier}`);
}
const relPath = npath.posix.relative(pathname, '/' + hashedFilePath);
const fullyRelativePath = relPath[0] === '.' ? relPath : './' + relPath;
return fullyRelativePath;
return prependForwardSlash(npath.posix.join(astroConfig.base, hashedFilePath));
},
request: createRequest({ url, headers: new Headers(), logging, ssr }),
route: pageData.route,

View file

@ -136,6 +136,7 @@ function buildManifest(
const ssrManifest: SerializedSSRManifest = {
routes,
site: astroConfig.site,
base: astroConfig.base,
markdown: astroConfig.markdown,
pageMap: null as any,
renderers: [],

View file

@ -22,7 +22,39 @@ describe('Client only components', () => {
const script = $script.html();
// test 2: svelte renderer is on the page
expect(/import\(".\/entry.*/g.test(script)).to.be.ok;
expect(/import\("\/entry.*/g.test(script)).to.be.ok;
});
it('Adds the CSS to the page', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerioLoad(html);
expect($('link[rel=stylesheet]')).to.have.lengthOf(2);
});
});
describe('Client only components subpath', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
site: 'https://site.com',
base: '/blog',
root: './fixtures/astro-client-only/',
});
await fixture.build();
});
it('Loads pages using client:only hydrator', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerioLoad(html);
// test 1: <astro-root> is empty
expect($('astro-root').html()).to.equal('');
const $script = $('script');
const script = $script.html();
// test 2: svelte renderer is on the page
expect(/import\("\/blog\/entry.*/g.test(script)).to.be.ok;
});
it('Adds the CSS to the page', async () => {

View file

@ -37,6 +37,47 @@ describe('Dynamic components', () => {
// test 2: correct script is being loaded.
// because of bundling, we don't have access to the source import,
// only the bundled import.
expect($('script').html()).to.include(`import setup from '../entry`);
expect($('script').html()).to.include(`import setup from '/entry`);
});
});
describe('Dynamic components subpath', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
site: 'https://site.com',
base: '/blog',
root: './fixtures/astro-dynamic/',
});
await fixture.build();
});
it('Loads packages that only run code in client', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
expect($('script').length).to.eq(2);
});
it('Loads pages using client:media hydrator', async () => {
const root = new URL('http://example.com/media/index.html');
const html = await fixture.readFile('/media/index.html');
const $ = cheerio.load(html);
// test 1: static value rendered
expect($('script').length).to.equal(2); // One for each
});
it('Loads pages using client:only hydrator', async () => {
const html = await fixture.readFile('/client-only/index.html');
const $ = cheerio.load(html);
// test 1: <astro-root> is empty.
expect($('<astro-root>').html()).to.equal('');
// test 2: correct script is being loaded.
// because of bundling, we don't have access to the source import,
// only the bundled import.
expect($('script').html()).to.include(`import setup from '/blog/entry`);
});
});