Handle script module resolution (#438)

Fixes #104
This commit is contained in:
Drew Powers 2021-06-15 15:06:29 -06:00 committed by GitHub
parent 272769d723
commit 54c291efa0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 3 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix <script type="module"> resolution

View file

@ -110,6 +110,9 @@ export async function build(astroConfig: AstroConfig, logging: LogOptions = defa
scanPromises.push( scanPromises.push(
runtime.load(url).then((result) => { runtime.load(url).then((result) => {
if (result.statusCode !== 200) { if (result.statusCode !== 200) {
if (result.statusCode === 404) {
throw new Error(`${buildState[id].srcPath.href}: could not find "${path.basename(url)}"`);
}
// there shouldnt be a build error here // there shouldnt be a build error here
throw (result as any).error || new Error(`unexpected status ${result.statusCode} when loading ${url}`); throw (result as any).error || new Error(`unexpected status ${result.statusCode} when loading ${url}`);
} }

View file

@ -24,10 +24,25 @@ export default function ({ compileOptions, filename }: { compileOptions: Compile
} }
let src = getAttrValue(node.attributes, 'src'); let src = getAttrValue(node.attributes, 'src');
if (!src || !src.startsWith('.')) {
// scenario 1: if missing "src", ignore
if (!src) {
return; return;
} }
// scenario 2: if absolute path, ignore
if (src.startsWith('/')) {
return;
}
// scenario 3: if remote URL, ignore
try {
new URL(src); // if this succeeds, this is a complete, valid URL
return;
} catch (err) {
// do nothing
}
const srcUrl = new URL(src, fileUrl); const srcUrl = new URL(src, fileUrl);
const absoluteUrl = `/_astro/${srcUrl.href.replace(astroConfig.projectRoot.href, '')}`; const absoluteUrl = `/_astro/${srcUrl.href.replace(astroConfig.projectRoot.href, '')}`;
setAttrValue(node.attributes, 'src', absoluteUrl); setAttrValue(node.attributes, 'src', absoluteUrl);

View file

@ -1,5 +1,6 @@
import { suite } from 'uvu'; import { suite } from 'uvu';
import * as assert from 'uvu/assert'; import * as assert from 'uvu/assert';
import { doc } from './test-utils.js';
import { setupBuild } from './helpers.js'; import { setupBuild } from './helpers.js';
const Resolution = suite('Astro Resolution'); const Resolution = suite('Astro Resolution');
@ -9,11 +10,30 @@ setupBuild(Resolution, './fixtures/astro-resolve');
Resolution('Assets', async (context) => { Resolution('Assets', async (context) => {
await context.build(); await context.build();
// public/ asset resolved // test 1: public/ asset resolved
assert.ok(await context.readFile('/svg.svg')); assert.ok(await context.readFile('/svg.svg'));
// asset in src/pages resolved (and didnt overwrite /svg.svg) // test 2: asset in src/pages resolved (and didnt overwrite /svg.svg)
assert.ok(await context.readFile('/_astro/src/pages/svg.svg')); assert.ok(await context.readFile('/_astro/src/pages/svg.svg'));
}); });
Resolution('<script type="module">', async (context) => {
await context.build();
// public/ asset resolved
const $ = doc(await context.readFile('/scripts/index.html'));
// test 1: not `type="module"` left alone
assert.equal($('script[src="./relative.js"]').attr('type'), undefined);
// test 2: inline script left alone
assert.equal($('script:not([type]):not([src])').length, 1);
// test 3: relative script resolved
assert.equal($('script[type="module"][src="/_astro/src/pages/relative.js"]').length, 2); // we have 2 of these!
// test 4: absolute script left alone
assert.equal($('script[type="module"][src="/absolute.js"]').length, 1);
});
Resolution.run(); Resolution.run();

View file

@ -0,0 +1 @@
console.log('Im absolute');

View file

@ -0,0 +1 @@
console.log('Im relative');

View file

@ -0,0 +1,20 @@
<html>
<head></head>
<body>
<!-- not `type="module"` -->
<script src="./relative.js"></script>
<!-- no `src` -->
<script></script>
<!-- type="module" with NO "./" -->
<script type="module" src="relative.js"></script>
<!-- type="module" WITH leading "./" -->
<script type="module" src="./relative.js"></script>
<!-- absolute URL -->
<script type="module" src="/absolute.js"></script>
</body>
</html>