summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@matthewphillips.info> 2021-11-17 15:57:47 -0500
committerGravatar GitHub <noreply@github.com> 2021-11-17 15:57:47 -0500
commit0ce86dfdf3468a45e3f0a083ed41a5191e75f914 (patch)
treefb2de263bf1d27a2e0c0a84aedaf568d6f7c93cc
parent6b598b24018af5ea569fa6447d9c6e3593c5e3c9 (diff)
downloadastro-0ce86dfdf3468a45e3f0a083ed41a5191e75f914.tar.gz
astro-0ce86dfdf3468a45e3f0a083ed41a5191e75f914.tar.zst
astro-0ce86dfdf3468a45e3f0a083ed41a5191e75f914.zip
Fix for built scoped Vue styles (#1868)
* Fixes #1844 * Adds a changeset * Remove all special casing * Add a clarifying comment
-rw-r--r--.changeset/serious-knives-hug.md5
-rw-r--r--packages/astro/src/vite-plugin-build-css/index.ts73
-rw-r--r--packages/astro/test/astro-styles-ssr.test.js39
3 files changed, 76 insertions, 41 deletions
diff --git a/.changeset/serious-knives-hug.md b/.changeset/serious-knives-hug.md
new file mode 100644
index 000000000..338be0974
--- /dev/null
+++ b/.changeset/serious-knives-hug.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes Vue scoped styles when built
diff --git a/packages/astro/src/vite-plugin-build-css/index.ts b/packages/astro/src/vite-plugin-build-css/index.ts
index 4c96167fa..1f560b130 100644
--- a/packages/astro/src/vite-plugin-build-css/index.ts
+++ b/packages/astro/src/vite-plugin-build-css/index.ts
@@ -1,8 +1,7 @@
import type { RenderedChunk } from 'rollup';
-import type { Plugin as VitePlugin } from '../core/vite';
+import { Plugin as VitePlugin } from '../core/vite';
import { STYLE_EXTENSIONS } from '../core/ssr/css.js';
-import { getViteTransform, TransformHook } from '../vite-plugin-astro/styles.js';
import * as path from 'path';
import esbuild from 'esbuild';
@@ -56,22 +55,30 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
const { astroPageStyleMap, astroStyleMap, chunkToReferenceIdMap, pureCSSChunks } = options;
const styleSourceMap = new Map<string, string>();
- let viteTransform: TransformHook;
-
return {
name: PLUGIN_NAME,
- enforce: 'pre',
-
configResolved(resolvedConfig) {
- viteTransform = getViteTransform(resolvedConfig);
-
- const viteCSSPost = resolvedConfig.plugins.find((p) => p.name === 'vite:css-post');
- if (viteCSSPost) {
+ // Our plugin needs to run before `vite:css-post` which does a lot of what we do
+ // for bundling CSS, but since we need to control CSS we should go first.
+ // We move to right before the vite:css-post plugin so that things like the
+ // Vue plugin go before us.
+ const plugins = resolvedConfig.plugins as VitePlugin[];
+ const viteCSSPostIndex = resolvedConfig.plugins.findIndex((p) => p.name === 'vite:css-post');
+ if (viteCSSPostIndex !== -1) {
+ const viteCSSPost = plugins[viteCSSPostIndex];
// Prevent this plugin's bundling behavior from running since we need to
// do that ourselves in order to handle updating the HTML.
delete viteCSSPost.renderChunk;
delete viteCSSPost.generateBundle;
+
+ // Move our plugin to be right before this one.
+ const ourIndex = plugins.findIndex(p => p.name === PLUGIN_NAME);
+ const ourPlugin = plugins[ourIndex];
+
+ // Remove us from where we are now and place us right before the viteCSSPost plugin
+ plugins.splice(ourIndex, 1);
+ plugins.splice(viteCSSPostIndex - 1, 0, ourPlugin);
}
},
@@ -101,15 +108,9 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
styleSourceMap.set(id, value);
return null;
}
- if (isCSSRequest(id)) {
- let result = await viteTransform(value, id);
- if (result) {
- styleSourceMap.set(id, result.code);
- } else {
- styleSourceMap.set(id, value);
- }
- return result;
+ if (isCSSRequest(id)) {
+ styleSourceMap.set(id, value);
}
return null;
@@ -145,12 +146,40 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
},
// Delete CSS chunks so JS is not produced for them.
- generateBundle(_options, bundle) {
- for (const [chunkId, chunk] of Object.entries(bundle)) {
- if (chunk.type === 'chunk' && pureCSSChunks.has(chunk)) {
- delete bundle[chunkId];
+ generateBundle(opts, bundle) {
+ if(pureCSSChunks.size) {
+ const pureChunkFilenames = new Set([...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') {
+ if(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.
+ delete bundle[chunkId];
+ } else {
+ // Remove any pure css chunk imports from JavaScript.
+ // Note that this code comes from Vite's CSS build plugin.
+ chunk.code = chunk.code.replace(
+ emptyChunkRE,
+ // remove css import while preserving source map location
+ (m) => `/* empty css ${''.padEnd(m.length - 15)}*/`
+ );
+ }
+ }
}
}
+
+
},
};
}
diff --git a/packages/astro/test/astro-styles-ssr.test.js b/packages/astro/test/astro-styles-ssr.test.js
index 7241d4095..0b7fba6c7 100644
--- a/packages/astro/test/astro-styles-ssr.test.js
+++ b/packages/astro/test/astro-styles-ssr.test.js
@@ -2,25 +2,27 @@ import { expect } from 'chai';
import cheerio from 'cheerio';
import { loadFixture } from './test-utils.js';
-let fixture;
-let index$;
-let bundledCSS;
-
-before(async () => {
- fixture = await loadFixture({
- projectRoot: './fixtures/astro-styles-ssr/',
- renderers: ['@astrojs/renderer-react', '@astrojs/renderer-svelte', '@astrojs/renderer-vue'],
- });
- await fixture.build();
+describe('Styles SSR', function() {
+ this.timeout(5000);
- // get bundled CSS (will be hashed, hence DOM query)
- const html = await fixture.readFile('/index.html');
- index$ = cheerio.load(html);
- const bundledCSSHREF = index$('link[rel=stylesheet][href^=assets/]').attr('href');
- bundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/'));
-});
+ let fixture;
+ let index$;
+ let bundledCSS;
+
+ before(async () => {
+ fixture = await loadFixture({
+ projectRoot: './fixtures/astro-styles-ssr/',
+ renderers: ['@astrojs/renderer-react', '@astrojs/renderer-svelte', '@astrojs/renderer-vue'],
+ });
+ await fixture.build();
+
+ // get bundled CSS (will be hashed, hence DOM query)
+ const html = await fixture.readFile('/index.html');
+ index$ = cheerio.load(html);
+ const bundledCSSHREF = index$('link[rel=stylesheet][href^=assets/]').attr('href');
+ bundledCSS = await fixture.readFile(bundledCSSHREF.replace(/^\/?/, '/'));
+ });
-describe('Styles SSR', () => {
describe('Astro styles', () => {
it('HTML and CSS scoped correctly', async () => {
const $ = index$;
@@ -94,8 +96,7 @@ describe('Styles SSR', () => {
expect(bundledCSS).to.include('.vue-title{');
});
- // TODO: fix Vue scoped styles in build bug
- it.skip('Scoped styles', async () => {
+ it('Scoped styles', async () => {
const $ = index$;
const el = $('#vue-scoped');