Allow TypeScript in hoisted scripts (#3665)

* Allow TypeScript in hoisted scripts

* Pass skipSelf

* Fix linting
This commit is contained in:
Matthew Phillips 2022-06-22 12:47:52 -04:00 committed by GitHub
parent c2dffc1c38
commit 9a813268db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 76 additions and 19 deletions

View file

@ -0,0 +1,23 @@
---
'astro': patch
---
Allow TypeScript inside script tags
This makes it so that you can use TypeScript inside of script tags like so:
```html
<script>
interface Person {
name: string;
}
const person: Person = {
name: 'Astro'
};
console.log(person);
</script>
```
Note that the the VSCode extension does not currently support this, however.

View file

@ -21,7 +21,7 @@ export function vitePluginAnalyzer(
scan(this: PluginContext, scripts: AstroPluginMetadata['astro']['scripts'], from: string) { scan(this: PluginContext, scripts: AstroPluginMetadata['astro']['scripts'], from: string) {
const hoistedScripts = new Set<string>(); const hoistedScripts = new Set<string>();
for (let i = 0; i < scripts.length; i++) { for (let i = 0; i < scripts.length; i++) {
const hid = `${from.replace('/@fs', '')}?astro&type=script&index=${i}`; const hid = `${from.replace('/@fs', '')}?astro&type=script&index=${i}&lang.ts`;
hoistedScripts.add(hid); hoistedScripts.add(hid);
} }

View file

@ -65,7 +65,7 @@ export class Metadata {
while (i < metadata.hoisted.length) { while (i < metadata.hoisted.length) {
// Strip off the leading "/@fs" added during compilation. // Strip off the leading "/@fs" added during compilation.
yield `${pathname.replace('/@fs', '')}?astro&type=script&index=${i}`; yield `${pathname.replace('/@fs', '')}?astro&type=script&index=${i}&lang.ts`;
i++; i++;
} }
} }

View file

@ -15,7 +15,7 @@ import { PAGE_SCRIPT_ID, PAGE_SSR_SCRIPT_ID } from '../vite-plugin-scripts/index
import { getFileInfo } from '../vite-plugin-utils/index.js'; import { getFileInfo } from '../vite-plugin-utils/index.js';
import { cachedCompilation, CompileProps } from './compile.js'; import { cachedCompilation, CompileProps } from './compile.js';
import { handleHotUpdate, trackCSSDependencies } from './hmr.js'; import { handleHotUpdate, trackCSSDependencies } from './hmr.js';
import { parseAstroRequest } from './query.js'; import { parseAstroRequest, ParsedRequestResult } from './query.js';
import { getViteTransform, TransformHook } from './styles.js'; import { getViteTransform, TransformHook } from './styles.js';
const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms; const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms;
@ -48,6 +48,16 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
const srcRootWeb = config.srcDir.pathname.slice(config.root.pathname.length - 1); const srcRootWeb = config.srcDir.pathname.slice(config.root.pathname.length - 1);
const isBrowserPath = (path: string) => path.startsWith(srcRootWeb); const isBrowserPath = (path: string) => path.startsWith(srcRootWeb);
function resolveRelativeFromAstroParent(id: string, parsedFrom: ParsedRequestResult): string {
const filename = normalizeFilename(parsedFrom.filename);
const resolvedURL = new URL(id, `file://${filename}`);
const resolved = resolvedURL.pathname;
if (isBrowserPath(resolved)) {
return relativeToRoot(resolved + resolvedURL.search);
}
return slash(fileURLToPath(resolvedURL)) + resolvedURL.search;
}
return { return {
name: 'astro:build', name: 'astro:build',
enforce: 'pre', // run transforms before other plugins can enforce: 'pre', // run transforms before other plugins can
@ -59,19 +69,17 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
viteDevServer = server; viteDevServer = server;
}, },
// note: dont claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.) // note: dont claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.)
async resolveId(id, from) { async resolveId(id, from, opts) {
// If resolving from an astro subresource such as a hoisted script, // If resolving from an astro subresource such as a hoisted script,
// we need to resolve relative paths ourselves. // we need to resolve relative paths ourselves.
if (from) { if (from) {
const parsedFrom = parseAstroRequest(from); const parsedFrom = parseAstroRequest(from);
if (parsedFrom.query.astro && isRelativePath(id) && parsedFrom.query.type === 'script') { const isAstroScript = parsedFrom.query.astro && parsedFrom.query.type === 'script';
const filename = normalizeFilename(parsedFrom.filename); if (isAstroScript && isRelativePath(id)) {
const resolvedURL = new URL(id, `file://${filename}`); return this.resolve(resolveRelativeFromAstroParent(id, parsedFrom), from, {
const resolved = resolvedURL.pathname; custom: opts.custom,
if (isBrowserPath(resolved)) { skipSelf: true,
return relativeToRoot(resolved + resolvedURL.search); });
}
return slash(fileURLToPath(resolvedURL)) + resolvedURL.search;
} }
} }
@ -170,6 +178,11 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
hoistedScript.type === 'inline' hoistedScript.type === 'inline'
? hoistedScript.code! ? hoistedScript.code!
: `import "${hoistedScript.src!}";`, : `import "${hoistedScript.src!}";`,
meta: {
vite: {
lang: 'ts',
},
}
}; };
} }
} }
@ -205,8 +218,8 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
let i = 0; let i = 0;
while (i < transformResult.scripts.length) { while (i < transformResult.scripts.length) {
deps.add(`${id}?astro&type=script&index=${i}`); deps.add(`${id}?astro&type=script&index=${i}&lang.ts`);
SUFFIX += `import "${id}?astro&type=script&index=${i}";`; SUFFIX += `import "${id}?astro&type=script&index=${i}&lang.ts";`;
i++; i++;
} }

View file

@ -7,13 +7,15 @@ export interface AstroQuery {
raw?: boolean; raw?: boolean;
} }
export interface ParsedRequestResult {
filename: string;
query: AstroQuery;
};
// Parses an id to check if its an Astro request. // Parses an id to check if its an Astro request.
// CSS is imported like `import '/src/pages/index.astro?astro&type=style&index=0&lang.css'; // CSS is imported like `import '/src/pages/index.astro?astro&type=style&index=0&lang.css';
// This parses those ids and returns an object representing what it found. // This parses those ids and returns an object representing what it found.
export function parseAstroRequest(id: string): { export function parseAstroRequest(id: string): ParsedRequestResult {
filename: string;
query: AstroQuery;
} {
const [filename, rawQuery] = id.split(`?`, 2); const [filename, rawQuery] = id.split(`?`, 2);
const query = Object.fromEntries(new URLSearchParams(rawQuery).entries()) as AstroQuery; const query = Object.fromEntries(new URLSearchParams(rawQuery).entries()) as AstroQuery;
if (query.astro != null) { if (query.astro != null) {

View file

@ -1,3 +1,11 @@
<script> <script>
console.log('some content here.'); import '../scripts/some-files/one';
import '../scripts/some-files/two.js';
interface Props {
name: string;
}
const props: Props = { name: 'some string' };
console.log('some content here.', props);
</script> </script>

View file

@ -0,0 +1 @@
console.log('some-files/one');

View file

@ -0,0 +1 @@
console.log('some-files/two');

9
pnpm-lock.yaml generated
View file

@ -8258,6 +8258,11 @@ packages:
/debug/3.2.7: /debug/3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
dev: false dev: false
@ -11179,6 +11184,8 @@ packages:
debug: 3.2.7 debug: 3.2.7
iconv-lite: 0.4.24 iconv-lite: 0.4.24
sax: 1.2.4 sax: 1.2.4
transitivePeerDependencies:
- supports-color
dev: false dev: false
/netmask/2.0.2: /netmask/2.0.2:
@ -11262,6 +11269,8 @@ packages:
rimraf: 2.7.1 rimraf: 2.7.1
semver: 5.7.1 semver: 5.7.1
tar: 4.4.19 tar: 4.4.19
transitivePeerDependencies:
- supports-color
dev: false dev: false
/node-releases/2.0.5: /node-releases/2.0.5: