summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/fast-oranges-collect.md5
-rw-r--r--packages/astro/src/core/build/graph.ts11
-rw-r--r--packages/astro/src/core/build/internal.ts28
-rw-r--r--packages/astro/src/core/build/vite-plugin-css.ts45
-rw-r--r--packages/astro/test/astro-scripts.test.js7
-rw-r--r--packages/astro/test/fixtures/astro-scripts/src/pages/with-styles.astro15
-rw-r--r--packages/astro/test/fixtures/astro-scripts/src/styles/one.css3
7 files changed, 87 insertions, 27 deletions
diff --git a/.changeset/fast-oranges-collect.md b/.changeset/fast-oranges-collect.md
new file mode 100644
index 000000000..a24e8f54a
--- /dev/null
+++ b/.changeset/fast-oranges-collect.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Include styles imported by hoisted scripts
diff --git a/packages/astro/src/core/build/graph.ts b/packages/astro/src/core/build/graph.ts
index beef79563..b911253d5 100644
--- a/packages/astro/src/core/build/graph.ts
+++ b/packages/astro/src/core/build/graph.ts
@@ -1,4 +1,5 @@
import type { GetModuleInfo, ModuleInfo } from 'rollup';
+
import { resolvedPagesVirtualModuleId } from '../app/index.js';
// This walks up the dependency graph and yields out each ModuleInfo object.
@@ -22,14 +23,20 @@ export function* walkParentInfos(
}
}
+// Returns true if a module is a top-level page. We determine this based on whether
+// it is imported by the top-level virtual module.
+export function moduleIsTopLevelPage(info: ModuleInfo): boolean {
+ return info.importers[0] === resolvedPagesVirtualModuleId;
+}
+
// This function walks the dependency graph, going up until it finds a page component.
// This could be a .astro page or a .md page.
export function* getTopLevelPages(
id: string,
- ctx: { getModuleInfo: GetModuleInfo }
+ ctx: { getModuleInfo: GetModuleInfo },
): Generator<[ModuleInfo, number], void, unknown> {
for (const res of walkParentInfos(id, ctx)) {
- if (res[0]?.importers[0] === resolvedPagesVirtualModuleId) {
+ if (moduleIsTopLevelPage(res[0])) {
yield res;
}
}
diff --git a/packages/astro/src/core/build/internal.ts b/packages/astro/src/core/build/internal.ts
index e8704a282..dfebc3052 100644
--- a/packages/astro/src/core/build/internal.ts
+++ b/packages/astro/src/core/build/internal.ts
@@ -1,4 +1,4 @@
-import type { OutputChunk, RenderedChunk } from 'rollup';
+import type { OutputChunk, RenderedChunk, ModuleInfo, GetModuleInfo } from 'rollup';
import type { PageBuildData, ViteID } from './types';
import { prependForwardSlash } from '../path.js';
@@ -62,13 +62,6 @@ export function createBuildInternals(): BuildInternals {
// Pure CSS chunks are chunks that only contain CSS.
// This is all of them, and chunkToReferenceIdMap maps them to a hash id used to find the final file.
const pureCSSChunks = new Set<RenderedChunk>();
- const chunkToReferenceIdMap = new Map<string, string>();
-
- // This is a mapping of pathname to the string source of all collected
- // inline <style> for a page.
- const astroStyleMap = new Map<string, string>();
- // This is a virtual JS module that imports all dependent styles for a page.
- const astroPageStyleMap = new Map<string, string>();
// These are for tracking hoisted script bundling
const hoistedScriptIdToHoistedMap = new Map<string, Set<string>>();
@@ -204,3 +197,22 @@ export function sortedCSS(pageData: PageBuildData) {
})
.map(([id]) => id);
}
+
+export function isHoistedScript(internals: BuildInternals, id: string): boolean {
+ return internals.hoistedScriptIdToPagesMap.has(id);
+}
+
+export function* getPageDatasByHoistedScriptId(
+ internals: BuildInternals,
+ id: string
+): Generator<PageBuildData, void, unknown> {
+ const set = internals.hoistedScriptIdToPagesMap.get(id);
+ if(set) {
+ for(const pageId of set) {
+ const pageData = getPageDataByComponent(internals, pageId.slice(1));
+ if(pageData) {
+ yield pageData;
+ }
+ }
+ }
+}
diff --git a/packages/astro/src/core/build/vite-plugin-css.ts b/packages/astro/src/core/build/vite-plugin-css.ts
index b01868034..f6ae3f5a2 100644
--- a/packages/astro/src/core/build/vite-plugin-css.ts
+++ b/packages/astro/src/core/build/vite-plugin-css.ts
@@ -9,8 +9,8 @@ import npath from 'path';
import { Plugin as VitePlugin, ResolvedConfig } from 'vite';
import { isCSSRequest } from '../render/util.js';
import { relativeToSrcDir } from '../util.js';
-import { getTopLevelPages, walkParentInfos } from './graph.js';
-import { eachPageData, getPageDataByViteID, getPageDatasByClientOnlyID } from './internal.js';
+import { getTopLevelPages, walkParentInfos, moduleIsTopLevelPage } from './graph.js';
+import { eachPageData, getPageDataByViteID, getPageDatasByClientOnlyID, getPageDatasByHoistedScriptId, isHoistedScript } from './internal.js';
interface PluginOptions {
internals: BuildInternals;
@@ -104,6 +104,22 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
importedCss: Set<string>;
};
+ const appendCSSToPage = (pageData: PageBuildData, meta: ViteMetadata, depth: number) => {
+ for (const importedCssImport of meta.importedCss) {
+ // CSS is prioritized based on depth. Shared CSS has a higher depth due to being imported by multiple pages.
+ // Depth info is used when sorting the links on the page.
+ if (pageData?.css.has(importedCssImport)) {
+ // eslint-disable-next-line
+ const cssInfo = pageData?.css.get(importedCssImport)!;
+ if (depth < cssInfo.depth) {
+ cssInfo.depth = depth;
+ }
+ } else {
+ pageData?.css.set(importedCssImport, { depth });
+ }
+ }
+ }
+
for (const [_, chunk] of Object.entries(bundle)) {
if (chunk.type === 'chunk') {
const c = chunk;
@@ -127,21 +143,16 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
// For this CSS chunk, walk parents until you find a page. Add the CSS to that page.
for (const [id] of Object.entries(c.modules)) {
- for (const [pageInfo, depth] of getTopLevelPages(id, this)) {
- const pageViteID = pageInfo.id;
- const pageData = getPageDataByViteID(internals, pageViteID);
-
- for (const importedCssImport of meta.importedCss) {
- // CSS is prioritized based on depth. Shared CSS has a higher depth due to being imported by multiple pages.
- // Depth info is used when sorting the links on the page.
- if (pageData?.css.has(importedCssImport)) {
- // eslint-disable-next-line
- const cssInfo = pageData?.css.get(importedCssImport)!;
- if (depth < cssInfo.depth) {
- cssInfo.depth = depth;
- }
- } else {
- pageData?.css.set(importedCssImport, { depth });
+ for (const [pageInfo, depth] of walkParentInfos(id, this)) {
+ if(moduleIsTopLevelPage(pageInfo)) {
+ const pageViteID = pageInfo.id;
+ const pageData = getPageDataByViteID(internals, pageViteID);
+ if(pageData) {
+ appendCSSToPage(pageData, meta, depth);
+ }
+ } else if(options.target === 'client' && isHoistedScript(internals, pageInfo.id)) {
+ for(const pageData of getPageDatasByHoistedScriptId(internals, pageInfo.id)) {
+ appendCSSToPage(pageData, meta, -1);
}
}
}
diff --git a/packages/astro/test/astro-scripts.test.js b/packages/astro/test/astro-scripts.test.js
index f182dee20..1229de5f5 100644
--- a/packages/astro/test/astro-scripts.test.js
+++ b/packages/astro/test/astro-scripts.test.js
@@ -114,6 +114,13 @@ describe('Scripts (hoisted and not)', () => {
expect($('script[type="module"]').length).to.be.greaterThan(0);
});
+
+ it('Styles imported by hoisted scripts are included on the page', async () => {
+ let html = await fixture.readFile('/with-styles/index.html');
+ let $ = cheerio.load(html);
+
+ expect($('link[rel=stylesheet]')).to.have.a.lengthOf(1);
+ });
});
describe('Dev', () => {
diff --git a/packages/astro/test/fixtures/astro-scripts/src/pages/with-styles.astro b/packages/astro/test/fixtures/astro-scripts/src/pages/with-styles.astro
new file mode 100644
index 000000000..af984e7b3
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-scripts/src/pages/with-styles.astro
@@ -0,0 +1,15 @@
+
+<html>
+ <head>
+ <title>Testing</title>
+ </head>
+ <body>
+ <h1>Testing</h1>
+ <script>
+ import "../styles/one.css";
+ console.log("This component imports styles.");
+ </script>
+ </body>
+</html>
+
+
diff --git a/packages/astro/test/fixtures/astro-scripts/src/styles/one.css b/packages/astro/test/fixtures/astro-scripts/src/styles/one.css
new file mode 100644
index 000000000..fb68e0f63
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-scripts/src/styles/one.css
@@ -0,0 +1,3 @@
+body {
+ background: rebeccapurple;
+}