From d2f13814eac43c82465a9c9c72c184cde3615001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=A0=20/=20green?= Date: Thu, 26 Jan 2023 05:34:36 +0900 Subject: [PATCH] fix(css): insert styles in the same position (#11763) --- packages/vite/src/client/client.ts | 17 ++++++++++++++++- .../__tests__/css-codesplit.spec.ts | 6 ++++++ playground/css-codesplit/index.html | 5 +++++ playground/css-codesplit/main.js | 1 + playground/css-codesplit/order/base.css | 3 +++ playground/css-codesplit/order/dynamic.css | 3 +++ playground/css-codesplit/order/index.js | 6 ++++++ playground/css-codesplit/order/insert.js | 3 +++ 8 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 playground/css-codesplit/order/base.css create mode 100644 playground/css-codesplit/order/dynamic.css create mode 100644 playground/css-codesplit/order/index.js create mode 100644 playground/css-codesplit/order/insert.js diff --git a/packages/vite/src/client/client.ts b/packages/vite/src/client/client.ts index 6e63c4fa526072..500207e7723442 100644 --- a/packages/vite/src/client/client.ts +++ b/packages/vite/src/client/client.ts @@ -347,6 +347,9 @@ const sheetsMap = new Map< string, HTMLStyleElement | CSSStyleSheet | undefined >() +// all css imports should be inserted at the same position +// because after build it will be a single css file +let lastInsertedStyle: HTMLStyleElement | undefined export function updateStyle(id: string, content: string): void { let style = sheetsMap.get(id) @@ -374,7 +377,19 @@ export function updateStyle(id: string, content: string): void { style.setAttribute('type', 'text/css') style.setAttribute('data-vite-dev-id', id) style.textContent = content - document.head.appendChild(style) + + if (!lastInsertedStyle) { + document.head.appendChild(style) + + // reset lastInsertedStyle after async + // because dynamically imported css will be splitted into a different file + setTimeout(() => { + lastInsertedStyle = undefined + }, 0) + } else { + lastInsertedStyle.insertAdjacentElement('afterend', style) + } + lastInsertedStyle = style } else { style.textContent = content } diff --git a/playground/css-codesplit/__tests__/css-codesplit.spec.ts b/playground/css-codesplit/__tests__/css-codesplit.spec.ts index 203316c7565932..e1d34784117fbb 100644 --- a/playground/css-codesplit/__tests__/css-codesplit.spec.ts +++ b/playground/css-codesplit/__tests__/css-codesplit.spec.ts @@ -21,6 +21,12 @@ test('should load dynamic import with module', async () => { expect(await getColor('.mod')).toBe('yellow') }) +test('style order should be consistent when style tag is inserted by JS', async () => { + expect(await getColor('.order-bulk')).toBe('orange') + await page.click('.order-bulk-update') + expect(await getColor('.order-bulk')).toBe('green') +}) + describe.runIf(isBuild)('build', () => { test('should remove empty chunk', async () => { expect(findAssetFile(/style.*\.js$/)).toBe('') diff --git a/playground/css-codesplit/index.html b/playground/css-codesplit/index.html index 63bdb59e11dc6b..37baa5dd37a848 100644 --- a/playground/css-codesplit/index.html +++ b/playground/css-codesplit/index.html @@ -7,5 +7,10 @@

This should be blue

This should be yellow

+

+ This should be orange + +

+
diff --git a/playground/css-codesplit/main.js b/playground/css-codesplit/main.js index 6b9e3344c15033..e128734112ee5a 100644 --- a/playground/css-codesplit/main.js +++ b/playground/css-codesplit/main.js @@ -1,5 +1,6 @@ import './style.css' import './main.css' +import './order' import('./async.css') diff --git a/playground/css-codesplit/order/base.css b/playground/css-codesplit/order/base.css new file mode 100644 index 00000000000000..a08c84388f2079 --- /dev/null +++ b/playground/css-codesplit/order/base.css @@ -0,0 +1,3 @@ +.order-bulk { + color: blue; +} diff --git a/playground/css-codesplit/order/dynamic.css b/playground/css-codesplit/order/dynamic.css new file mode 100644 index 00000000000000..f460d283759a88 --- /dev/null +++ b/playground/css-codesplit/order/dynamic.css @@ -0,0 +1,3 @@ +.order-bulk { + color: green; +} diff --git a/playground/css-codesplit/order/index.js b/playground/css-codesplit/order/index.js new file mode 100644 index 00000000000000..dab4e8e5962b11 --- /dev/null +++ b/playground/css-codesplit/order/index.js @@ -0,0 +1,6 @@ +import './insert' // inserts "color: orange" +import './base.css' // includes "color: blue" + +document.querySelector('.order-bulk-update').addEventListener('click', () => { + import('./dynamic.css') // includes "color: green" +}) diff --git a/playground/css-codesplit/order/insert.js b/playground/css-codesplit/order/insert.js new file mode 100644 index 00000000000000..2ccda105650412 --- /dev/null +++ b/playground/css-codesplit/order/insert.js @@ -0,0 +1,3 @@ +const style = document.createElement('style') +style.textContent = '.order-bulk { color: orange; }' +document.head.appendChild(style)