summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2022-06-16 09:54:09 -0400
committerGravatar GitHub <noreply@github.com> 2022-06-16 09:54:09 -0400
commit4916b733c2b8265ab46762bbbc85aa4171296515 (patch)
treefe21dbd12bf5dcc01223b68375ff8b56d4767c7b
parent816e9635095ca6914b281b137f1c0e98b1ea7b37 (diff)
downloadastro-4916b733c2b8265ab46762bbbc85aa4171296515.tar.gz
astro-4916b733c2b8265ab46762bbbc85aa4171296515.tar.zst
astro-4916b733c2b8265ab46762bbbc85aa4171296515.zip
Inline hydration directive scripts (#3605)
* Inline hydration scripts * Adds a changeset * Update directiveAstroKeys type
-rw-r--r--.changeset/many-seas-notice.md5
-rw-r--r--.gitignore1
-rw-r--r--packages/astro/package.json8
-rw-r--r--packages/astro/src/core/build/static-build.ts2
-rw-r--r--packages/astro/src/runtime/client/hydration-directives.d.ts17
-rw-r--r--packages/astro/src/runtime/client/idle.ts33
-rw-r--r--packages/astro/src/runtime/client/load.ts22
-rw-r--r--packages/astro/src/runtime/client/media.ts39
-rw-r--r--packages/astro/src/runtime/client/only.ts20
-rw-r--r--packages/astro/src/runtime/client/visible.ts26
-rw-r--r--packages/astro/src/runtime/server/astro-island.prebuilt.ts7
-rw-r--r--packages/astro/src/runtime/server/astro-island.ts22
-rw-r--r--packages/astro/src/runtime/server/hydration.ts3
-rw-r--r--packages/astro/src/runtime/server/index.ts40
-rw-r--r--packages/astro/src/runtime/server/metadata.ts17
-rw-r--r--packages/astro/src/runtime/server/scripts.ts80
-rw-r--r--packages/astro/src/runtime/server/util.ts9
-rw-r--r--scripts/cmd/build.js18
-rw-r--r--scripts/cmd/prebuild.js8
19 files changed, 203 insertions, 174 deletions
diff --git a/.changeset/many-seas-notice.md b/.changeset/many-seas-notice.md
new file mode 100644
index 000000000..88035d9e3
--- /dev/null
+++ b/.changeset/many-seas-notice.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Inlines hydration scripts
diff --git a/.gitignore b/.gitignore
index 8967dc4b0..a6fb80905 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ package-lock.json
# do not commit .env files or any files that end with `.env`
*.env
+packages/astro/src/**/*.prebuilt.ts
!packages/astro/vendor/vite/dist
packages/integrations/**/.netlify/
diff --git a/packages/astro/package.json b/packages/astro/package.json
index add575e1f..1c1e48c3f 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -66,10 +66,10 @@
"vendor"
],
"scripts": {
- "prebuild": "astro-scripts prebuild --to-string \"src/runtime/server/astro-island.ts\"",
- "build": "astro-scripts build \"src/**/*.ts\" && tsc",
- "build:ci": "astro-scripts build \"src/**/*.ts\"",
- "dev": "astro-scripts dev \"src/**/*.ts\"",
+ "prebuild": "astro-scripts prebuild --to-string \"src/runtime/server/astro-island.ts\" \"src/runtime/client/{idle,load,media,only,visible}.ts\"",
+ "build": "pnpm run prebuild && astro-scripts build \"src/**/*.ts\" && tsc",
+ "build:ci": "pnpm run prebuild && astro-scripts build \"src/**/*.ts\"",
+ "dev": "astro-scripts dev --prebuild \"src/runtime/server/astro-island.ts\" --prebuild \"src/runtime/client/{idle,load,media,only,visible}.ts\" \"src/**/*.ts\"",
"postbuild": "astro-scripts copy \"src/**/*.astro\"",
"benchmark": "node test/benchmark/dev.bench.js && node test/benchmark/build.bench.js",
"test": "mocha --exit --timeout 20000 --ignore **/lit-element.test.js --ignore **/errors.test.js && mocha --timeout 20000 **/lit-element.test.js && mocha --timeout 20000 **/errors.test.js",
diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts
index a88b3593e..c242c98b3 100644
--- a/packages/astro/src/core/build/static-build.ts
+++ b/packages/astro/src/core/build/static-build.ts
@@ -68,8 +68,6 @@ export async function staticBuild(opts: StaticBuildOptions) {
...metadata.hydratedComponentPaths(),
// Client-only components
...clientOnlys,
- // Any hydration directive like astro/client/idle.js
- ...metadata.hydrationDirectiveSpecifiers(),
// The client path for each renderer
...renderers
.filter((renderer) => !!renderer.clientEntrypoint)
diff --git a/packages/astro/src/runtime/client/hydration-directives.d.ts b/packages/astro/src/runtime/client/hydration-directives.d.ts
new file mode 100644
index 000000000..512b5c39a
--- /dev/null
+++ b/packages/astro/src/runtime/client/hydration-directives.d.ts
@@ -0,0 +1,17 @@
+import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
+
+type DirectiveLoader = (get: GetHydrateCallback, opts: HydrateOptions, root: HTMLElement) => void;
+
+declare global {
+ interface Window {
+ Astro: {
+ idle: DirectiveLoader;
+ load: DirectiveLoader;
+ media: DirectiveLoader;
+ only: DirectiveLoader;
+ visible: DirectiveLoader;
+ }
+ }
+}
+
+export {};
diff --git a/packages/astro/src/runtime/client/idle.ts b/packages/astro/src/runtime/client/idle.ts
index a719cd7a7..a5564fc5a 100644
--- a/packages/astro/src/runtime/client/idle.ts
+++ b/packages/astro/src/runtime/client/idle.ts
@@ -1,27 +1,12 @@
-import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
-import { notify } from './events';
+(self.Astro = self.Astro || {}).idle = (getHydrateCallback) => {
+ const cb = async () => {
+ let hydrate = await getHydrateCallback();
+ await hydrate();
+ };
-/**
- * Hydrate this component as soon as the main thread is free
- * (or after a short delay, if `requestIdleCallback`) isn't supported
- */
-export default async function onIdle(
- root: HTMLElement,
- options: HydrateOptions,
- getHydrateCallback: GetHydrateCallback
-) {
- async function idle() {
- const cb = async () => {
- let hydrate = await getHydrateCallback();
- await hydrate();
- notify();
- };
-
- if ('requestIdleCallback' in window) {
- (window as any).requestIdleCallback(cb);
- } else {
- setTimeout(cb, 200);
- }
+ if ('requestIdleCallback' in window) {
+ (window as any).requestIdleCallback(cb);
+ } else {
+ setTimeout(cb, 200);
}
- idle();
}
diff --git a/packages/astro/src/runtime/client/load.ts b/packages/astro/src/runtime/client/load.ts
index 0301aba1c..77f74eaaf 100644
--- a/packages/astro/src/runtime/client/load.ts
+++ b/packages/astro/src/runtime/client/load.ts
@@ -1,18 +1,8 @@
-import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
-import { notify } from './events';
-
-/**
- * Hydrate this component immediately
- */
-export default async function onLoad(
- root: HTMLElement,
- options: HydrateOptions,
- getHydrateCallback: GetHydrateCallback
-) {
- async function load() {
+(self.Astro = self.Astro || {}).load = (getHydrateCallback) => {
+ (async () => {
let hydrate = await getHydrateCallback();
await hydrate();
- notify();
- }
- load();
-}
+ })();
+};
+
+
diff --git a/packages/astro/src/runtime/client/media.ts b/packages/astro/src/runtime/client/media.ts
index 22fbd641e..09985ebeb 100644
--- a/packages/astro/src/runtime/client/media.ts
+++ b/packages/astro/src/runtime/client/media.ts
@@ -1,29 +1,22 @@
-import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
-import { notify } from './events';
-
/**
* Hydrate this component when a matching media query is found
*/
-export default async function onMedia(
- root: HTMLElement,
- options: HydrateOptions,
- getHydrateCallback: GetHydrateCallback
-) {
- async function media() {
- const cb = async () => {
- let hydrate = await getHydrateCallback();
- await hydrate();
- notify();
- };
+ (self.Astro = self.Astro || {}).media = (getHydrateCallback, options) => {
+ const cb = async () => {
+ let hydrate = await getHydrateCallback();
+ await hydrate();
+ };
- if (options.value) {
- const mql = matchMedia(options.value);
- if (mql.matches) {
- cb();
- } else {
- mql.addEventListener('change', cb, { once: true });
- }
+ if (options.value) {
+ const mql = matchMedia(options.value);
+ if (mql.matches) {
+ cb();
+ } else {
+ mql.addEventListener('change', cb, { once: true });
}
}
- media();
-}
+ };
+
+
+
+
diff --git a/packages/astro/src/runtime/client/only.ts b/packages/astro/src/runtime/client/only.ts
index 2fa5a5893..8cc5f42aa 100644
--- a/packages/astro/src/runtime/client/only.ts
+++ b/packages/astro/src/runtime/client/only.ts
@@ -1,18 +1,12 @@
-import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
-import { notify } from './events';
-
/**
* Hydrate this component only on the client
*/
-export default async function onOnly(
- root: HTMLElement,
- options: HydrateOptions,
- getHydrateCallback: GetHydrateCallback
-) {
- async function only() {
+ (self.Astro = self.Astro || {}).only = (getHydrateCallback) => {
+ (async () => {
let hydrate = await getHydrateCallback();
await hydrate();
- notify();
- }
- only();
-}
+ })();
+ };
+
+
+ \ No newline at end of file
diff --git a/packages/astro/src/runtime/client/visible.ts b/packages/astro/src/runtime/client/visible.ts
index 2d1a8f70a..e3cbbfa7d 100644
--- a/packages/astro/src/runtime/client/visible.ts
+++ b/packages/astro/src/runtime/client/visible.ts
@@ -1,30 +1,15 @@
-import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
-import { notify } from './events';
-
/**
* Hydrate this component when one of it's children becomes visible
* We target the children because `astro-island` is set to `display: contents`
* which doesn't work with IntersectionObserver
*/
-export default async function onVisible(
- root: HTMLElement,
- options: HydrateOptions,
- getHydrateCallback: GetHydrateCallback
-) {
- let io: IntersectionObserver;
-
- async function visible() {
- const cb = async () => {
+(self.Astro = self.Astro || {}).visible = (getHydrateCallback, _opts, root) => {
+ const cb = async () => {
let hydrate = await getHydrateCallback();
await hydrate();
- notify();
};
- if (io) {
- io.disconnect();
- }
-
- io = new IntersectionObserver((entries) => {
+ let io = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue;
// As soon as we hydrate, disconnect this IntersectionObserver for every `astro-island`
@@ -38,7 +23,4 @@ export default async function onVisible(
const child = root.children[i];
io.observe(child);
}
- }
-
- visible();
-}
+};
diff --git a/packages/astro/src/runtime/server/astro-island.prebuilt.ts b/packages/astro/src/runtime/server/astro-island.prebuilt.ts
deleted file mode 100644
index d7204bbe8..000000000
--- a/packages/astro/src/runtime/server/astro-island.prebuilt.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * This file is prebuilt from packages/astro/src/runtime/server/astro-island.ts
- * Do not edit this directly, but instead edit that file and rerun the prebuild
- * to generate this file.
- */
-
-export default `var a;{const o={0:t=>t,1:t=>JSON.parse(t,n),2:t=>new RegExp(t),3:t=>new Date(t),4:t=>new Map(JSON.parse(t,n)),5:t=>new Set(JSON.parse(t,n)),6:t=>BigInt(t),7:t=>new URL(t)},n=(t,e)=>{if(t===""||!Array.isArray(e))return e;const[r,s]=e;return r in o?o[r](s):void 0};customElements.get("astro-island")||customElements.define("astro-island",(a=class extends HTMLElement{constructor(){super(...arguments);this.hydrate=()=>{if(!this.hydrator||this.parentElement?.closest("astro-island[ssr]"))return;let e=null,r=this.querySelector("astro-fragment");if(r==null&&this.hasAttribute("tmpl")){let i=this.querySelector("template[data-astro-template]");i&&(e=i.innerHTML,i.remove())}else r&&(e=r.innerHTML);const s=this.hasAttribute("props")?JSON.parse(this.getAttribute("props"),n):{};this.hydrator(this)(this.Component,s,e,{client:this.getAttribute("client")}),this.removeAttribute("ssr"),window.removeEventListener("astro:hydrate",this.hydrate),window.dispatchEvent(new CustomEvent("astro:hydrate"))}}async connectedCallback(){const[{default:e}]=await Promise.all([import(this.getAttribute("directive-url")),import(this.getAttribute("before-hydration-url"))]);window.addEventListener("astro:hydrate",this.hydrate);const r=JSON.parse(this.getAttribute("opts"));e(this,r,async()=>{const s=this.getAttribute("renderer-url"),[i,{default:l}]=await Promise.all([import(this.getAttribute("component-url")),s?import(s):()=>()=>{}]);return this.Component=i[this.getAttribute("component-export")||"default"],this.hydrator=l,this.hydrate})}attributeChangedCallback(){this.hydrator&&this.hydrate()}},a.observedAttributes=["props"],a))}`;
diff --git a/packages/astro/src/runtime/server/astro-island.ts b/packages/astro/src/runtime/server/astro-island.ts
index 365da6ae3..92168f728 100644
--- a/packages/astro/src/runtime/server/astro-island.ts
+++ b/packages/astro/src/runtime/server/astro-island.ts
@@ -2,6 +2,16 @@
// Do not import this file directly, instead import the prebuilt one instead.
// pnpm --filter astro run prebuild
+type directiveAstroKeys = 'load' | 'idle' | 'visible' | 'media' | 'only';
+
+declare const Astro: {
+ [k in directiveAstroKeys]: (
+ fn: () => Promise<() => void>,
+ opts: Record<string, any>,
+ root: HTMLElement
+ ) => void;
+}
+
{
interface PropTypeSelector {
[k: string]: (value: any) => any;
@@ -32,14 +42,10 @@
public hydrator: any;
static observedAttributes = ['props'];
async connectedCallback() {
- const [{ default: setup }] = await Promise.all([
- import(this.getAttribute('directive-url')!),
- import(this.getAttribute('before-hydration-url')!),
- ]);
window.addEventListener('astro:hydrate', this.hydrate);
-
- const opts = JSON.parse(this.getAttribute('opts')!);
- setup(this, opts, async () => {
+ await import(this.getAttribute('before-hydration-url')!);
+ const opts = JSON.parse(this.getAttribute('opts')!) as Record<string, any>;
+ Astro[this.getAttribute('client') as directiveAstroKeys](async () => {
const rendererUrl = this.getAttribute('renderer-url');
const [componentModule, { default: hydrator }] = await Promise.all([
import(this.getAttribute('component-url')!),
@@ -48,7 +54,7 @@
this.Component = componentModule[this.getAttribute('component-export') || 'default'];
this.hydrator = hydrator;
return this.hydrate;
- });
+ }, opts, this);
}
hydrate = () => {
if (!this.hydrator || this.parentElement?.closest('astro-island[ssr]')) {
diff --git a/packages/astro/src/runtime/server/hydration.ts b/packages/astro/src/runtime/server/hydration.ts
index 9f05152b8..ef677c8b8 100644
--- a/packages/astro/src/runtime/server/hydration.ts
+++ b/packages/astro/src/runtime/server/hydration.ts
@@ -6,7 +6,7 @@ import type {
} from '../../@types/astro';
import { escapeHTML } from './escape.js';
import { serializeProps } from './serialize.js';
-import { hydrationSpecifier, serializeListValue } from './util.js';
+import { serializeListValue } from './util.js';
const HydrationDirectives = ['load', 'idle', 'media', 'visible', 'only'];
@@ -129,7 +129,6 @@ export async function generateHydrateScript(
island.props['ssr'] = '';
island.props['client'] = hydrate;
- island.props['directive-url'] = await result.resolve(hydrationSpecifier(hydrate));
island.props['before-hydration-url'] = await result.resolve('astro:scripts/before-hydration.js');
island.props['opts'] = escapeHTML(
JSON.stringify({
diff --git a/packages/astro/src/runtime/server/index.ts b/packages/astro/src/runtime/server/index.ts
index 7bd60aba4..88a4f1cd3 100644
--- a/packages/astro/src/runtime/server/index.ts
+++ b/packages/astro/src/runtime/server/index.ts
@@ -8,11 +8,17 @@ import type {
SSRLoadedRenderer,
SSRResult,
} from '../../@types/astro';
-import islandScript from './astro-island.prebuilt.js';
+
import { escapeHTML, HTMLString, markHTMLString } from './escape.js';
import { extractDirectives, generateHydrateScript } from './hydration.js';
import { serializeProps } from './serialize.js';
import { shorthash } from './shorthash.js';
+import {
+ determineIfNeedsHydrationScript,
+ determinesIfNeedsDirectiveScript,
+ PrescriptType,
+ getPrescripts
+} from './scripts.js';
import { serializeListValue } from './util.js';
export { markHTMLString, markHTMLString as unescapeHTML } from './escape.js';
@@ -27,18 +33,6 @@ const htmlEnumAttributes = /^(contenteditable|draggable|spellcheck|value)$/i;
// Note: SVG is case-sensitive!
const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|preserveAlpha)$/i;
-// This is used to keep track of which requests (pages) have had the hydration script
-// appended. We only add the hydration script once per page, and since the SSRResult
-// object corresponds to one page request, we are using it as a key to know.
-const resultsWithHydrationScript = new WeakSet<SSRResult>();
-
-function determineIfNeedsHydrationScript(result: SSRResult): boolean {
- if (resultsWithHydrationScript.has(result)) {
- return false;
- }
- resultsWithHydrationScript.add(result);
- return true;
-}
// INVESTIGATE:
// 2. Less anys when possible and make it well known when they are needed.
@@ -158,6 +152,7 @@ function formatList(values: string[]): string {
return `${values.slice(0, -1).join(', ')} or ${values[values.length - 1]}`;
}
+
export async function renderComponent(
result: SSRResult,
displayName: string,
@@ -191,6 +186,7 @@ export async function renderComponent(
const { hydration, props } = extractDirectives(_props);
let html = '';
let needsHydrationScript = hydration && determineIfNeedsHydrationScript(result);
+ let needsDirectiveScript = hydration && determinesIfNeedsDirectiveScript(result, hydration.directive);
if (hydration) {
metadata.hydrate = hydration.directive as AstroComponentMetadata['hydrate'];
@@ -348,19 +344,11 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
island.children = `${html ?? ''}${template}`;
- // Add the astro-island definition only once. Since the SSRResult object
- // is scoped to a page renderer we can use it as a key to know if the script
- // has been rendered or not.
- let script = '';
- if (needsHydrationScript) {
- // Note that this is a class script, not a module script.
- // This is so that it executes immediate, and when the browser encounters
- // an astro-island element the callbacks will fire immediately, causing the JS
- // deps to be loaded immediately.
- script = `<script>${islandScript}</script>`;
- }
-
- return markHTMLString(script + renderElement('astro-island', island, false));
+ let prescriptType: PrescriptType = needsHydrationScript ? 'both' : needsDirectiveScript ?
+ 'directive' : null;
+ let prescripts = getPrescripts(prescriptType, hydration.directive);
+
+ return markHTMLString(prescripts + renderElement('astro-island', island, false));
}
/** Create the Astro.fetchContent() runtime function. */
diff --git a/packages/astro/src/runtime/server/metadata.ts b/packages/astro/src/runtime/server/metadata.ts
index 9379cc3ff..548d2bb7d 100644
--- a/packages/astro/src/runtime/server/metadata.ts
+++ b/packages/astro/src/runtime/server/metadata.ts
@@ -1,5 +1,3 @@
-import { hydrationSpecifier } from './util.js';
-
interface ModuleInfo {
module: Record<string, any>;
specifier: string;
@@ -82,21 +80,6 @@ export class Metadata {
}
}
- /**
- * Gets all of the hydration specifiers used within this component.
- */
- *hydrationDirectiveSpecifiers() {
- const found = new Set<string>();
- for (const metadata of this.deepMetadata()) {
- for (const directive of metadata.hydrationDirectives) {
- if (!found.has(directive)) {
- found.add(directive);
- yield hydrationSpecifier(directive);
- }
- }
- }
- }
-
*hoistedScriptPaths() {
for (const metadata of this.deepMetadata()) {
let i = 0,
diff --git a/packages/astro/src/runtime/server/scripts.ts b/packages/astro/src/runtime/server/scripts.ts
new file mode 100644
index 000000000..85efa795a
--- /dev/null
+++ b/packages/astro/src/runtime/server/scripts.ts
@@ -0,0 +1,80 @@
+import type {
+ APIContext,
+ AstroComponentMetadata,
+ AstroGlobalPartial,
+ EndpointHandler,
+ Params,
+ SSRElement,
+ SSRLoadedRenderer,
+ SSRResult,
+} from '../../@types/astro';
+
+import islandScript from './astro-island.prebuilt.js';
+import idlePrebuilt from '../client/idle.prebuilt.js';
+import loadPrebuilt from '../client/load.prebuilt.js';
+import onlyPrebuilt from '../client/only.prebuilt.js';
+import visiblePrebuilt from '../client/visible.prebuilt.js';
+import mediaPrebuilt from '../client/media.prebuilt.js';
+
+
+// This is used to keep track of which requests (pages) have had the hydration script
+// appended. We only add the hydration script once per page, and since the SSRResult
+// object corresponds to one page request, we are using it as a key to know.
+const resultsWithHydrationScript = new WeakSet<SSRResult>();
+
+export function determineIfNeedsHydrationScript(result: SSRResult): boolean {
+ if (resultsWithHydrationScript.has(result)) {
+ return false;
+ }
+ resultsWithHydrationScript.add(result);
+ return true;
+}
+
+export const hydrationScripts: Record<string, string> = {
+ idle: idlePrebuilt,
+ load: loadPrebuilt,
+ only: onlyPrebuilt,
+ media: mediaPrebuilt,
+ visible: visiblePrebuilt
+};
+
+const resultsWithDirectiveScript = new Map<string, WeakSet<SSRResult>>();
+
+export function determinesIfNeedsDirectiveScript(result: SSRResult, directive: string): boolean {
+ if(!resultsWithDirectiveScript.has(directive)) {
+ resultsWithDirectiveScript.set(directive, new WeakSet());
+ }
+ const set = resultsWithDirectiveScript.get(directive)!;
+ if(set.has(result)) {
+ return false;
+ }
+ set.add(result);
+ return true;
+}
+
+
+
+export type PrescriptType = null | 'both' | 'directive';
+
+function getDirectiveScriptText(directive: string): string {
+ if(!(directive in hydrationScripts)) {
+ throw new Error(`Unknown directive: ${directive}`);
+ }
+ const directiveScriptText = hydrationScripts[directive];
+ return directiveScriptText;
+}
+
+export function getPrescripts(type: PrescriptType, directive: string): string {
+ // Note that this is a classic script, not a module script.
+ // This is so that it executes immediate, and when the browser encounters
+ // an astro-island element the callbacks will fire immediately, causing the JS
+ // deps to be loaded immediately.
+ switch(type) {
+ case 'both':
+
+ return `<script>${getDirectiveScriptText(directive) + islandScript}</script>`;
+ case 'directive':
+ return `<script>${getDirectiveScriptText(directive)}</script>`;
+ }
+ return '';
+}
diff --git a/packages/astro/src/runtime/server/util.ts b/packages/astro/src/runtime/server/util.ts
index 22f38f970..0fe36a860 100644
--- a/packages/astro/src/runtime/server/util.ts
+++ b/packages/astro/src/runtime/server/util.ts
@@ -34,12 +34,3 @@ export function serializeListValue(value: any) {
}
}
}
-
-/**
- * Get the import specifier for a given hydration directive.
- * @param hydrate The hydration directive such as `idle` or `visible`
- * @returns
- */
-export function hydrationSpecifier(hydrate: string) {
- return `astro/client/${hydrate}.js`;
-}
diff --git a/scripts/cmd/build.js b/scripts/cmd/build.js
index b2d402890..a95a5b8e3 100644
--- a/scripts/cmd/build.js
+++ b/scripts/cmd/build.js
@@ -4,6 +4,7 @@ import del from 'del';
import { promises as fs } from 'fs';
import { dim, green, red, yellow } from 'kleur/colors';
import glob from 'tiny-glob';
+import prebuild from './prebuild.js';
/** @type {import('esbuild').BuildOptions} */
const defaultConfig = {
@@ -20,9 +21,23 @@ const dt = new Intl.DateTimeFormat('en-us', {
minute: '2-digit',
});
+function getPrebuilds(isDev, args) {
+ let prebuilds = [];
+ while(args.includes('--prebuild')) {
+ let idx = args.indexOf('--prebuild');
+ prebuilds.push(args[idx + 1]);
+ args.splice(idx, 2);
+ }
+ if(prebuilds.length && isDev) {
+ prebuilds.unshift('--no-minify');
+ }
+ return prebuilds;
+}
+
export default async function build(...args) {
const config = Object.assign({}, defaultConfig);
const isDev = args.slice(-1)[0] === 'IS_DEV';
+ const prebuilds = getPrebuilds(isDev, args);
const patterns = args
.filter((f) => !!f) // remove empty args
.map((f) => f.replace(/^'/, '').replace(/'$/, '')); // Needed for Windows: glob strings contain surrounding string chars??? remove these
@@ -59,6 +74,9 @@ export default async function build(...args) {
...config,
watch: {
onRebuild(error, result) {
+ if(prebuilds.length) {
+ prebuild(...prebuilds);
+ }
const date = dt.format(new Date());
if (error || (result && result.errors.length)) {
console.error(dim(`[${date}] `) + red(error || result.errors.join('\n')));
diff --git a/scripts/cmd/prebuild.js b/scripts/cmd/prebuild.js
index 4a67babe2..0d14e63f1 100644
--- a/scripts/cmd/prebuild.js
+++ b/scripts/cmd/prebuild.js
@@ -11,6 +11,12 @@ export default async function prebuild(...args) {
args.splice(buildToString, 1);
buildToString = true;
}
+ let minify = true;
+ let minifyIdx = args.indexOf('--no-minify');
+ if(minifyIdx !== -1) {
+ minify = false;
+ args.splice(minifyIdx, 1);
+ }
let patterns = args;
let entryPoints = [].concat(
@@ -33,7 +39,7 @@ export default async function prebuild(...args) {
const tscode = await fs.promises.readFile(filepath, 'utf-8');
const esbuildresult = await esbuild.transform(tscode, {
loader: 'ts',
- minify: true,
+ minify,
});
const rootURL = new URL('../../', import.meta.url);
const rel = path.relative(fileURLToPath(rootURL), filepath);