diff --git a/.changeset/moody-boats-pull.md b/.changeset/moody-boats-pull.md new file mode 100644 index 000000000..d81fd2430 --- /dev/null +++ b/.changeset/moody-boats-pull.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes shared CSS within the static build diff --git a/examples/portfolio/src/components/MainHead.astro b/examples/portfolio/src/components/MainHead.astro index 0597b178f..978c1d245 100644 --- a/examples/portfolio/src/components/MainHead.astro +++ b/examples/portfolio/src/components/MainHead.astro @@ -1,4 +1,5 @@ --- +import '../styles/global.scss'; const { title = 'Jeanine White: Personal Site', description = 'The personal site of Jeanine White' } = Astro.props; --- @@ -8,6 +9,5 @@ const { title = 'Jeanine White: Personal Site', description = 'The personal site {title} - diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index c5230b86a..40afe728e 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -189,6 +189,7 @@ async function generatePage(output: OutputChunk, opts: StaticBuildOptions, inter } let linkIds = internals.facadeIdToAssetsMap.get(facadeId) || []; + let compiledModule = await import(url.toString()); let Component = compiledModule.default; @@ -242,6 +243,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G children: '', })) ); + // Override the `resolve` method so that hydrated components are given the // hashed filepath to the component. result.resolve = async (specifier: string) => { diff --git a/packages/astro/src/vite-plugin-build-css/index.ts b/packages/astro/src/vite-plugin-build-css/index.ts index 444ac5049..5a4d4be20 100644 --- a/packages/astro/src/vite-plugin-build-css/index.ts +++ b/packages/astro/src/vite-plugin-build-css/index.ts @@ -13,7 +13,8 @@ const ASTRO_STYLE_PREFIX = '@astro-inline-style'; const ASTRO_PAGE_STYLE_PREFIX = '@astro-page-all-styles'; -const isCSSRequest = (request: string) => STYLE_EXTENSIONS.has(path.extname(request)); +const cssRe = new RegExp(`\\.(${Array.from(STYLE_EXTENSIONS).map(s => s.slice(1)).join('|')})($|\\?)`); +const isCSSRequest = (request: string): boolean => cssRe.test(request); export function getAstroPageStyleId(pathname: string) { let styleId = ASTRO_PAGE_STYLE_PREFIX + pathname; @@ -109,6 +110,8 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin { return null; }, + + async renderChunk(_code, chunk) { let chunkCSS = ''; let isPureCSS = true; @@ -121,7 +124,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin { } } - // if (!chunkCSS) return null; // don’t output empty .css files + if (!chunkCSS) return null; // don’t output empty .css files if (isPureCSS) { internals.pureCSSChunks.add(chunk); @@ -139,11 +142,14 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin { internals.chunkToReferenceIdMap.set(chunk.fileName, referenceId); if (chunk.type === 'chunk') { - const facadeId = chunk.facadeModuleId!; - if (!internals.facadeIdToAssetsMap.has(facadeId)) { - internals.facadeIdToAssetsMap.set(facadeId, []); + const fileName = this.getFileName(referenceId); + if(chunk.facadeModuleId) { + const facadeId = chunk.facadeModuleId!; + if (!internals.facadeIdToAssetsMap.has(facadeId)) { + internals.facadeIdToAssetsMap.set(facadeId, []); + } + internals.facadeIdToAssetsMap.get(facadeId)!.push(fileName); } - internals.facadeIdToAssetsMap.get(facadeId)!.push(this.getFileName(referenceId)); } return null; @@ -151,16 +157,39 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin { // Delete CSS chunks so JS is not produced for them. generateBundle(opts, bundle) { - if (internals.pureCSSChunks.size) { - const pureChunkFilenames = new Set([...internals.pureCSSChunks].map((chunk) => chunk.fileName)); - const emptyChunkFiles = [...pureChunkFilenames] - .map((file) => path.basename(file)) - .join('|') - .replace(/\./g, '\\.'); - const emptyChunkRE = new RegExp(opts.format === 'es' ? `\\bimport\\s*"[^"]*(?:${emptyChunkFiles})";\n?` : `\\brequire\\(\\s*"[^"]*(?:${emptyChunkFiles})"\\);\n?`, 'g'); + const hasPureCSSChunks = internals.pureCSSChunks.size; + const pureChunkFilenames = new Set([...internals.pureCSSChunks].map((chunk) => chunk.fileName)); + const emptyChunkFiles = [...pureChunkFilenames] + .map((file) => path.basename(file)) + .join('|') + .replace(/\./g, '\\.'); + const emptyChunkRE = new RegExp(opts.format === 'es' ? `\\bimport\\s*"[^"]*(?:${emptyChunkFiles})";\n?` : `\\brequire\\(\\s*"[^"]*(?:${emptyChunkFiles})"\\);\n?`, 'g'); - for (const [chunkId, chunk] of Object.entries(bundle)) { - if (chunk.type === 'chunk') { + for (const [chunkId, chunk] of Object.entries(bundle)) { + if (chunk.type === 'chunk') { + // If the chunk has a facadeModuleId it is an entrypoint chunk. + // This find shared chunks of CSS and adds them to the main CSS chunks, + // so that shared CSS is added to the page. + if(chunk.facadeModuleId) { + if(!internals.facadeIdToAssetsMap.has(chunk.facadeModuleId)) { + internals.facadeIdToAssetsMap.set(chunk.facadeModuleId, []); + } + const assets = internals.facadeIdToAssetsMap.get(chunk.facadeModuleId)!; + const assetSet = new Set(assets); + for(const imp of chunk.imports) { + if(internals.chunkToReferenceIdMap.has(imp) && !pureChunkFilenames.has(imp)) { + const referenceId = internals.chunkToReferenceIdMap.get(imp)!; + const fileName = this.getFileName(referenceId); + if(!assetSet.has(fileName)) { + assetSet.add(fileName); + assets.push(fileName); + } + } + } + } + + // Removes imports for pure CSS chunks. + if(hasPureCSSChunks) { if (internals.pureCSSChunks.has(chunk)) { // Delete pure CSS chunks, these are JavaScript chunks that only import // other CSS files, so are empty at the end of bundling. diff --git a/packages/astro/test/fixtures/static-build/src/components/MainHead.astro b/packages/astro/test/fixtures/static-build/src/components/MainHead.astro new file mode 100644 index 000000000..532d99299 --- /dev/null +++ b/packages/astro/test/fixtures/static-build/src/components/MainHead.astro @@ -0,0 +1,11 @@ +--- +import '../styles/main.scss'; +const { title = 'Static Build', description = 'This is a demo of the static build' } = Astro.props; +--- + + + + +{title} + + diff --git a/packages/astro/test/fixtures/static-build/src/components/Nav/index.jsx b/packages/astro/test/fixtures/static-build/src/components/Nav/index.jsx new file mode 100644 index 000000000..d74961d6d --- /dev/null +++ b/packages/astro/test/fixtures/static-build/src/components/Nav/index.jsx @@ -0,0 +1,35 @@ +import { h } from 'preact'; +import Styles from './styles.module.scss'; + +function Nav() { + return ( + + ); +} +export default Nav; diff --git a/packages/astro/test/fixtures/static-build/src/components/Nav/styles.module.scss b/packages/astro/test/fixtures/static-build/src/components/Nav/styles.module.scss new file mode 100644 index 000000000..ecbe5585e --- /dev/null +++ b/packages/astro/test/fixtures/static-build/src/components/Nav/styles.module.scss @@ -0,0 +1,65 @@ +.nav { + display: flex; + align-items: center; + padding-top: 1rem; + padding-right: 2rem; + padding-bottom: 1rem; + padding-left: 2rem; +} + +.logolink { + display: block; + color: var(--t-fg); + text-decoration: none; +} + +.link { + color: var(--t-subdue); + display: block; + margin-left: 1rem; + text-decoration: none; + font-size: var(--f-d1); + text-transform: uppercase; + padding-top: 0.75em; + padding-bottom: 0.75em; + + &:focus, + &:hover { + color: var(--t-active); + } +} + +.monogram { + display: flex; + align-items: center; + justify-content: center; + width: 2em; + height: 2em; + margin-right: 0.5rem; + color: var(--c-black); + font-weight: 900; + letter-spacing: -0.125rem; + border: 3px solid currentColor; + border-radius: 50%; +} + +.social { + display: block; + margin-left: auto; + + + .social { + margin-left: 0.75rem; + } +} + +.socialicon { + display: block; + width: 1.25rem; + height: 1.25rem; + fill: var(--t-subdue); + transition: fill linear 150ms; + + &:hover { + fill: var(--t-active); + } +} diff --git a/packages/astro/test/fixtures/static-build/src/layouts/Main.astro b/packages/astro/test/fixtures/static-build/src/layouts/Main.astro index b6af3a4fe..26f817711 100644 --- a/packages/astro/test/fixtures/static-build/src/layouts/Main.astro +++ b/packages/astro/test/fixtures/static-build/src/layouts/Main.astro @@ -1,6 +1,21 @@ +--- +import MainHead from '../components/MainHead.astro'; +--- -Testing + + diff --git a/packages/astro/test/fixtures/static-build/src/pages/index.astro b/packages/astro/test/fixtures/static-build/src/pages/index.astro index e22975e58..3cfed9ad6 100644 --- a/packages/astro/test/fixtures/static-build/src/pages/index.astro +++ b/packages/astro/test/fixtures/static-build/src/pages/index.astro @@ -1,6 +1,25 @@ +--- +import MainHead from '../components/MainHead.astro'; +import Nav from '../components/Nav/index.jsx'; +--- -Testing + + -

Testing

+ +