From 4475b428c2214bbd4d4cddf8c5cdb728842579aa Mon Sep 17 00:00:00 2001 From: lilnasy <69170106+lilnasy@users.noreply.github.com> Date: Sun, 26 Mar 2023 02:33:28 +0000 Subject: [PATCH] feat: add `inlineStylesheets` configuration --- .changeset/friendly-fishes-sing.md | 5 ++++ packages/astro/src/core/app/index.ts | 3 +++ packages/astro/src/core/app/types.ts | 1 + packages/astro/src/core/build/generate.ts | 21 ++++++++++++++-- packages/astro/src/core/build/page-data.ts | 2 ++ .../src/core/build/plugins/plugin-css.ts | 24 +++++++++++++++++++ .../src/core/build/plugins/plugin-ssr.ts | 2 ++ packages/astro/src/core/build/types.ts | 1 + packages/astro/src/core/config/schema.ts | 9 +++++++ packages/astro/src/core/render/ssr-element.ts | 13 ++++++++++ 10 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 .changeset/friendly-fishes-sing.md diff --git a/.changeset/friendly-fishes-sing.md b/.changeset/friendly-fishes-sing.md new file mode 100644 index 0000000000000..21d1f9c7cf42a --- /dev/null +++ b/.changeset/friendly-fishes-sing.md @@ -0,0 +1,5 @@ +--- +'astro': minor +--- + +add a configuration option (build.inlineStylsheets) to let the user include small stylsheets in the html diff --git a/packages/astro/src/core/app/index.ts b/packages/astro/src/core/app/index.ts index e43e9a8ff73c6..d8e95b89bb080 100644 --- a/packages/astro/src/core/app/index.ts +++ b/packages/astro/src/core/app/index.ts @@ -21,6 +21,7 @@ import { } from '../render/index.js'; import { RouteCache } from '../render/route-cache.js'; import { + createInlineStyleElementSet, createLinkStylesheetElementSet, createModuleScriptElement, } from '../render/ssr-element.js'; @@ -173,6 +174,7 @@ export class App { const pathname = '/' + this.removeBase(url.pathname); const info = this.#routeDataToRouteInfo.get(routeData!)!; const links = createLinkStylesheetElementSet(info.links); + const styles = createInlineStyleElementSet(info.styles); let scripts = new Set(); for (const script of info.scripts) { @@ -195,6 +197,7 @@ export class App { pathname, componentMetadata: this.#manifest.componentMetadata, scripts, + styles, links, route: routeData, status, diff --git a/packages/astro/src/core/app/types.ts b/packages/astro/src/core/app/types.ts index b7b5fa45a9f85..3937e98280351 100644 --- a/packages/astro/src/core/app/types.ts +++ b/packages/astro/src/core/app/types.ts @@ -20,6 +20,7 @@ export interface RouteInfo { // Hoisted | { type: 'inline' | 'external'; value: string } )[]; + styles: string[]; } export type SerializedRouteInfo = Omit & { diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 52e4204a999d2..c9c161fce802f 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -31,7 +31,11 @@ import { AstroError } from '../errors/index.js'; import { debug, info } from '../logger/core.js'; import { createEnvironment, createRenderContext, renderPage } from '../render/index.js'; import { callGetStaticPaths } from '../render/route-cache.js'; -import { createLinkStylesheetElementSet, createModuleScriptsSet } from '../render/ssr-element.js'; +import { + createLinkStylesheetElementSet, + createInlineStyleElementSet, + createModuleScriptsSet, +} from '../render/ssr-element.js'; import { createRequest } from '../request.js'; import { matchRoute } from '../routing/match.js'; import { getOutputFilename } from '../util.js'; @@ -155,6 +159,7 @@ async function generatePage( const pageInfo = getPageDataByComponent(internals, pageData.route.component); const linkIds: string[] = sortedCSS(pageData); const scripts = pageInfo?.hoistedScript ?? null; + const styles = pageInfo?.inlineStyles ?? null; const pageModule = ssrEntry.pageMap?.get(pageData.component); @@ -174,6 +179,7 @@ async function generatePage( internals, linkIds, scripts, + styles, mod: pageModule, renderers, }; @@ -264,6 +270,7 @@ interface GeneratePathOptions { internals: BuildInternals; linkIds: string[]; scripts: { type: 'inline' | 'external'; value: string } | null; + styles: string[] | null; mod: ComponentInstance; renderers: SSRLoadedRenderer[]; } @@ -331,7 +338,15 @@ async function generatePath( gopts: GeneratePathOptions ) { const { settings, logging, origin, routeCache } = opts; - const { mod, internals, linkIds, scripts: hoistedScripts, pageData, renderers } = gopts; + const { + mod, + internals, + linkIds, + scripts: hoistedScripts, + styles: _styles, + pageData, + renderers, + } = gopts; // This adds the page name to the array so it can be shown as part of stats. if (pageData.route.type === 'page') { @@ -345,6 +360,7 @@ async function generatePath( hoistedScripts ? [hoistedScripts] : [], settings.config.base ); + const styles = createInlineStyleElementSet(_styles ?? []); if (settings.scripts.some((script) => script.stage === 'page')) { const hashedFilePath = internals.entrySpecifierToBundleMap.get(PAGE_SCRIPT_ID); @@ -407,6 +423,7 @@ async function generatePath( request: createRequest({ url, headers: new Headers(), logging, ssr }), componentMetadata: internals.componentMetadata, scripts, + styles, links, route: pageData.route, }); diff --git a/packages/astro/src/core/build/page-data.ts b/packages/astro/src/core/build/page-data.ts index 71de5da4b91da..2409e118da3d8 100644 --- a/packages/astro/src/core/build/page-data.ts +++ b/packages/astro/src/core/build/page-data.ts @@ -57,6 +57,7 @@ export async function collectPagesData( propagatedStyles: new Map(), propagatedScripts: new Map(), hoistedScript: undefined, + inlineStyles: [], }; clearInterval(routeCollectionLogTimeout); @@ -80,6 +81,7 @@ export async function collectPagesData( propagatedStyles: new Map(), propagatedScripts: new Map(), hoistedScript: undefined, + inlineStyles: [], }; } diff --git a/packages/astro/src/core/build/plugins/plugin-css.ts b/packages/astro/src/core/build/plugins/plugin-css.ts index 826058b4e4b21..a88afb82fdafd 100644 --- a/packages/astro/src/core/build/plugins/plugin-css.ts +++ b/packages/astro/src/core/build/plugins/plugin-css.ts @@ -262,6 +262,30 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] } }, }, + { + name: 'astro:rollup-plugin-inline-stylesheets', + // enforce: 'post', + async generateBundle(_outputOptions, bundle) { + if (settings.config.build.inlineStylesheets !== true) return; + const assetInlineLimit = settings.config.vite?.build?.assetsInlineLimit ?? 4096; + for (const [id, stylesheet] of Object.entries(bundle)) { + if ( + stylesheet.type === 'asset' && + stylesheet.name?.endsWith('.css') && + typeof stylesheet.source === 'string' && + Buffer.byteLength(stylesheet.source) <= assetInlineLimit + ) { + for (const pageData of eachPageData(internals)) { + if (pageData.css.has(stylesheet.fileName)) { + pageData.inlineStyles.push(stylesheet.source); + pageData.css.delete(stylesheet.fileName); + delete bundle[id]; + } + } + } + } + }, + }, ]; } diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts index 78a1217e045c6..044c66cd3b469 100644 --- a/packages/astro/src/core/build/plugins/plugin-ssr.ts +++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts @@ -156,6 +156,7 @@ function buildManifest( file, links: [], scripts: [], + styles: [], routeData: serializeRouteData(pageData.route, settings.config.trailingSlash), }); staticFiles.push(file); @@ -192,6 +193,7 @@ function buildManifest( .filter((script) => script.stage === 'head-inline') .map(({ stage, content }) => ({ stage, children: content })), ], + styles: pageData.inlineStyles, routeData: serializeRouteData(pageData.route, settings.config.trailingSlash), }); } diff --git a/packages/astro/src/core/build/types.ts b/packages/astro/src/core/build/types.ts index 02f5618d87762..1661ce1eb82db 100644 --- a/packages/astro/src/core/build/types.ts +++ b/packages/astro/src/core/build/types.ts @@ -24,6 +24,7 @@ export interface PageBuildData { propagatedStyles: Map>; propagatedScripts: Map>; hoistedScript: { type: 'inline' | 'external'; value: string } | undefined; + inlineStyles: string[]; } export type AllPagesData = Record; diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 5b374ce33ec37..f3144cf0be8ba 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -21,6 +21,7 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = { server: './dist/server/', assets: '_astro', serverEntry: 'entry.mjs', + inlineStylesheets: false, }, server: { host: false, @@ -98,6 +99,10 @@ export const AstroConfigSchema = z.object({ .transform((val) => new URL(val)), assets: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.build.assets), serverEntry: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.build.serverEntry), + inlineStylesheets: z + .boolean() + .optional() + .default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets), }) .optional() .default({}), @@ -223,6 +228,10 @@ export function createRelativeSchema(cmd: string, fileProtocolRoot: URL) { .transform((val) => new URL(val, fileProtocolRoot)), assets: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.build.assets), serverEntry: z.string().optional().default(ASTRO_CONFIG_DEFAULTS.build.serverEntry), + inlineStylesheets: z + .boolean() + .optional() + .default(ASTRO_CONFIG_DEFAULTS.build.inlineStylesheets), }) .optional() .default({}), diff --git a/packages/astro/src/core/render/ssr-element.ts b/packages/astro/src/core/render/ssr-element.ts index 36fbca9e8572a..0cc128f7b532f 100644 --- a/packages/astro/src/core/render/ssr-element.ts +++ b/packages/astro/src/core/render/ssr-element.ts @@ -26,6 +26,19 @@ export function createLinkStylesheetElementSet(hrefs: string[], base?: string) { return new Set(hrefs.map((href) => createLinkStylesheetElement(href, base))); } +export function createInlineStyleElement(text: string): SSRElement { + return { + props: { + type: 'text/css', + }, + children: text, + }; +} + +export function createInlineStyleElementSet(texts: string[]) { + return new Set(texts.map(createInlineStyleElement)); +} + export function createModuleScriptElement( script: { type: 'inline' | 'external'; value: string }, base?: string