diff options
-rw-r--r-- | .changeset/cold-rats-swim.md | 52 | ||||
-rw-r--r-- | packages/astro/package.json | 2 | ||||
-rw-r--r-- | packages/astro/src/core/compile/compile.ts | 1 | ||||
-rw-r--r-- | packages/astro/src/core/config/schema.ts | 2 | ||||
-rw-r--r-- | packages/astro/src/types/public/config.ts | 42 | ||||
-rw-r--r-- | packages/astro/test/css-order.test.js | 22 | ||||
-rw-r--r-- | packages/astro/test/fixtures/css-order-transparent/astro.config.mjs | 7 | ||||
-rw-r--r-- | packages/astro/test/fixtures/css-order-transparent/package.json | 7 | ||||
-rw-r--r-- | packages/astro/test/fixtures/css-order-transparent/src/components/Item.astro | 17 | ||||
-rw-r--r-- | packages/astro/test/fixtures/css-order-transparent/src/pages/index.astro | 17 | ||||
-rw-r--r-- | pnpm-lock.yaml | 21 |
11 files changed, 181 insertions, 9 deletions
diff --git a/.changeset/cold-rats-swim.md b/.changeset/cold-rats-swim.md new file mode 100644 index 000000000..62b428712 --- /dev/null +++ b/.changeset/cold-rats-swim.md @@ -0,0 +1,52 @@ +--- +'astro': minor +--- + +Adds a new experimental flag called `experimental.preserveScriptOrder` that renders `<script>` and `<style>` tags in the same order as they are defined. + +When rendering multiple `<style>` and `<script>` tags on the same page, Astro currently reverses their order in your generated HTML output. This can give unexpected results, for example CSS styles being overridden by earlier defined style tags when your site is built. + +With the new `preserveScriptOrder` flag enabled, Astro will generate the styles in the order they are defined: + +```js title="astro.config.mjs" +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + experimental: { + preserveScriptOrder: true, + }, +}); +``` +For example, the following component has two `<style>` tags, and both define the same style for the `body` tag: + +```html +<p>I am a component</p> +<style> + body { + background: red; + } +</style> +<style> + body { + background: yellow; + } +</style> +``` + +Once the project is compiled, Astro will create an inline style where `yellow` appears first, and then `red`. Ultimately, the `red` background is applied: + +```css +body {background:#ff0} body {background:red} +``` + +When `experimental.preserveScriptOrder` is set to `true`, the order of the two styles is kept as it is, and in the style generated `red` appears first, and then `yellow`: + +```css +body {background:red} body {background:#ff0} +``` + +This is a breaking change to how Astro renders project code that contains multiple `<style>` and `<script>` tags in the same component. If you were previously compensating for Astro's behavior by writing these out of order, you will need to update your code. + +This will eventually become the new default Astro behavior, so we encourage you to add this experimental style and script ordering as soon as you are able! This will help us test the new behavior and ensure your code is ready when this becomes the new normal. + +For more information as this feature develops, please see the [experimental script order docs](https://docs.astro.build/en/reference/experimental-flags/preserve-script-order/). diff --git a/packages/astro/package.json b/packages/astro/package.json index 241af7675..4a0470142 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -118,7 +118,7 @@ "test:integration": "astro-scripts test \"test/*.test.js\"" }, "dependencies": { - "@astrojs/compiler": "^2.10.4", + "@astrojs/compiler": "^2.11.0", "@astrojs/internal-helpers": "workspace:*", "@astrojs/markdown-remark": "workspace:*", "@astrojs/telemetry": "workspace:*", diff --git a/packages/astro/src/core/compile/compile.ts b/packages/astro/src/core/compile/compile.ts index 5cfe92e1b..eb79c666e 100644 --- a/packages/astro/src/core/compile/compile.ts +++ b/packages/astro/src/core/compile/compile.ts @@ -65,6 +65,7 @@ export async function compile({ cssPartialCompileResults, cssTransformErrors, }), + experimentalScriptOrder: astroConfig.experimental.preserveScriptOrder ?? false, async resolvePath(specifier) { return resolvePath(specifier, filename); }, diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 15729f399..690e57c99 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -102,6 +102,7 @@ export const ASTRO_CONFIG_DEFAULTS = { serializeConfig: false, session: false, headingIdCompat: false, + preserveScriptOrder: false }, } satisfies AstroUserConfig & { server: { open: boolean } }; @@ -621,6 +622,7 @@ export const AstroConfigSchema = z.object({ .boolean() .optional() .default(ASTRO_CONFIG_DEFAULTS.experimental.headingIdCompat), + preserveScriptOrder: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.preserveScriptOrder), }) .strict( `Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/experimental-flags/ for a list of all current experiments.`, diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts index 6238dc688..1fed0eb29 100644 --- a/packages/astro/src/types/public/config.ts +++ b/packages/astro/src/types/public/config.ts @@ -2180,6 +2180,48 @@ export interface ViteUserConfig extends OriginalViteUserConfig { * include a trailing `-`, matching standard behavior in other Markdown tooling. */ headingIdCompat?: boolean; + + /** + * @name experimental.preserveScriptOrder + * @type {boolean} + * @default `false` + * @version 5.5 + * @description + * + * When enabled, `<script>` and `<style>` tags are rendered in the same order as they are defined. + * + * ## Example + * + * Consider the following component: + * + * ```html + * <p>I am a component</p> + * <style> + * body { + * background: red; + * } + * </style> + * <style> + * body { + * background: yellow; + * } + * </style> + * ``` + * + * By default, it will generate a CSS style where `red` will be applied: + * + * ```css + * body {background:#ff0} body {background:red} + * ``` + * + * When this new option is set to `true`, the generated CSS style will apply `yellow`: + * + * ```css + * body {background:red} body {background:#ff0} + * ``` + * + */ + preserveScriptOrder: boolean; }; } diff --git a/packages/astro/test/css-order.test.js b/packages/astro/test/css-order.test.js index 70fd44c39..74e58b34e 100644 --- a/packages/astro/test/css-order.test.js +++ b/packages/astro/test/css-order.test.js @@ -111,4 +111,26 @@ describe('CSS production ordering', () => { } }); }); + + + describe("Changes order when transparentScriptOrder is enabled", () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + root: './fixtures/css-order-transparent/', + }); + await fixture.build(); + }); + + + it('should compile styles in the same order as they are found', async () => { + const html = await fixture.readFile('/index.html'); + + // The component declares red background first, then yellow + assert.match(html, /body\{background:red\}body\{background:#ff0/); + }); + + }) }); diff --git a/packages/astro/test/fixtures/css-order-transparent/astro.config.mjs b/packages/astro/test/fixtures/css-order-transparent/astro.config.mjs new file mode 100644 index 000000000..5ce5a4089 --- /dev/null +++ b/packages/astro/test/fixtures/css-order-transparent/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + experimental: { + preserveScriptOrder: true, + } +}); diff --git a/packages/astro/test/fixtures/css-order-transparent/package.json b/packages/astro/test/fixtures/css-order-transparent/package.json new file mode 100644 index 000000000..9edc472a0 --- /dev/null +++ b/packages/astro/test/fixtures/css-order-transparent/package.json @@ -0,0 +1,7 @@ +{ + "name": "@test/css-order-transparent", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/css-order-transparent/src/components/Item.astro b/packages/astro/test/fixtures/css-order-transparent/src/components/Item.astro new file mode 100644 index 000000000..9bbc24e05 --- /dev/null +++ b/packages/astro/test/fixtures/css-order-transparent/src/components/Item.astro @@ -0,0 +1,17 @@ + + +<p> + I am a component +</p> + +<style> + body { + background: red; + } +</style> + +<style> + body { + background: yellow; + } +</style> diff --git a/packages/astro/test/fixtures/css-order-transparent/src/pages/index.astro b/packages/astro/test/fixtures/css-order-transparent/src/pages/index.astro new file mode 100644 index 000000000..52d4e1039 --- /dev/null +++ b/packages/astro/test/fixtures/css-order-transparent/src/pages/index.astro @@ -0,0 +1,17 @@ +--- +import Item from "../components/Item.astro"; +--- +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Basic HTML</title> +</head> + <body> + <h1>Welcome to Basic HTML Page</h1> + <Item /> + </body> +</html> + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 644a84bc0..36a7f6d6a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -461,8 +461,8 @@ importers: packages/astro: dependencies: '@astrojs/compiler': - specifier: ^2.10.4 - version: 2.10.4 + specifier: ^2.11.0 + version: 2.11.0 '@astrojs/internal-helpers': specifier: workspace:* version: link:../internal-helpers @@ -2876,6 +2876,12 @@ importers: specifier: workspace:* version: link:../../.. + packages/astro/test/fixtures/css-order-transparent: + dependencies: + astro: + specifier: workspace:* + version: link:../../.. + packages/astro/test/fixtures/custom-404-html: dependencies: astro: @@ -6333,8 +6339,8 @@ packages: resolution: {integrity: sha512-bVzyKzEpIwqjihBU/aUzt1LQckJuHK0agd3/ITdXhPUYculrc6K1/K7H+XG4rwjXtg+ikT3PM05V1MVYWiIvQw==} engines: {node: '>=18.14.1'} - '@astrojs/compiler@2.10.4': - resolution: {integrity: sha512-86B3QGagP99MvSNwuJGiYSBHnh8nLvm2Q1IFI15wIUJJsPeQTO3eb2uwBmrqRsXykeR/mBzH8XCgz5AAt1BJrQ==} + '@astrojs/compiler@2.11.0': + resolution: {integrity: sha512-zZOO7i+JhojO8qmlyR/URui6LyfHJY6m+L9nwyX5GiKD78YoRaZ5tzz6X0fkl+5bD3uwlDHayf6Oe8Fu36RKNg==} '@astrojs/language-server@2.15.0': resolution: {integrity: sha512-wJHSjGApm5X8Rg1GvkevoatZBfvaFizY4kCPvuSYgs3jGCobuY3KstJGKC1yNLsRJlDweHruP+J54iKn9vEKoA==} @@ -10197,7 +10203,6 @@ packages: libsql@0.4.5: resolution: {integrity: sha512-sorTJV6PNt94Wap27Sai5gtVLIea4Otb2LUiAUyr3p6BPOScGMKGt5F1b5X/XgkNtcsDKeX5qfeBDj+PdShclQ==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.1: @@ -12882,11 +12887,11 @@ snapshots: log-update: 5.0.1 sisteransi: 1.0.5 - '@astrojs/compiler@2.10.4': {} + '@astrojs/compiler@2.11.0': {} '@astrojs/language-server@2.15.0(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.2)': dependencies: - '@astrojs/compiler': 2.10.4 + '@astrojs/compiler': 2.11.0 '@astrojs/yaml2ts': 0.2.1 '@jridgewell/sourcemap-codec': 1.5.0 '@volar/kit': 2.4.6(typescript@5.8.2) @@ -18194,7 +18199,7 @@ snapshots: prettier-plugin-astro@0.14.1: dependencies: - '@astrojs/compiler': 2.10.4 + '@astrojs/compiler': 2.11.0 prettier: 3.5.3 sass-formatter: 0.7.9 |