diff --git a/src/runtime/injectStylesIntoStyleTag.js b/src/runtime/injectStylesIntoStyleTag.js index cb3b2a42..4addaf95 100644 --- a/src/runtime/injectStylesIntoStyleTag.js +++ b/src/runtime/injectStylesIntoStyleTag.js @@ -30,6 +30,8 @@ function modulesToDom(list, options) { css: item[1], media: item[2], sourceMap: item[3], + supports: item[4], + layer: item[5], }; if (index !== -1) { @@ -59,7 +61,9 @@ function addStyle(obj, options) { if ( newObj.css === obj.css && newObj.media === obj.media && - newObj.sourceMap === obj.sourceMap + newObj.sourceMap === obj.sourceMap && + newObj.supports === obj.supports && + newObj.layer === obj.layer ) { return; } diff --git a/src/runtime/singletonStyleDomAPI.js b/src/runtime/singletonStyleDomAPI.js index 136896fe..e7360b28 100644 --- a/src/runtime/singletonStyleDomAPI.js +++ b/src/runtime/singletonStyleDomAPI.js @@ -11,11 +11,41 @@ const replaceText = (function replaceText() { /* istanbul ignore next */ function apply(style, index, remove, obj) { - const css = remove - ? "" - : obj.media - ? `@media ${obj.media} {${obj.css}}` - : obj.css; + let css; + + if (remove) { + css = ""; + } else { + css = ""; + + if (obj.supports) { + css += `@supports (${obj.supports}) {`; + } + + if (obj.media) { + css += `@media ${obj.media} {`; + } + + const needLayer = typeof obj.layer !== "undefined"; + + if (needLayer) { + css += `@layer${obj.layer.length > 0 ? ` ${obj.layer}` : ""} {`; + } + + css += obj.css; + + if (needLayer) { + css += "}"; + } + + if (obj.media) { + css += "}"; + } + + if (obj.supports) { + css += "}"; + } + } // For old IE /* istanbul ignore if */ diff --git a/src/runtime/styleDomAPI.js b/src/runtime/styleDomAPI.js index f48b38e3..8f0ee4e9 100644 --- a/src/runtime/styleDomAPI.js +++ b/src/runtime/styleDomAPI.js @@ -1,15 +1,37 @@ /* istanbul ignore next */ function apply(style, options, obj) { - let css = obj.css; - const media = obj.media; - const sourceMap = obj.sourceMap; + let css = ""; + + if (obj.supports) { + css += `@supports (${obj.supports}) {`; + } + + if (obj.media) { + css += `@media ${obj.media} {`; + } + + const needLayer = typeof obj.layer !== "undefined"; - if (media) { - style.setAttribute("media", media); - } else { - style.removeAttribute("media"); + if (needLayer) { + css += `@layer${obj.layer.length > 0 ? ` ${obj.layer}` : ""} {`; } + css += obj.css; + + if (needLayer) { + css += "}"; + } + + if (obj.media) { + css += "}"; + } + + if (obj.supports) { + css += "}"; + } + + const sourceMap = obj.sourceMap; + if (sourceMap && typeof btoa !== "undefined") { css += `\n/*# sourceMappingURL=data:application/json;base64,${btoa( unescape(encodeURIComponent(JSON.stringify(sourceMap))) diff --git a/test/loader.test.js b/test/loader.test.js index fe9e7695..9e8e30fb 100644 --- a/test/loader.test.js +++ b/test/loader.test.js @@ -14,6 +14,8 @@ import { runInJsDom, } from "./helpers/index"; +jest.setTimeout(10000); + describe("loader", () => { const injectTypes = [ "styleTag", diff --git a/test/manual/index.html b/test/manual/index.html index 7d218ccf..4334545e 100644 --- a/test/manual/index.html +++ b/test/manual/index.html @@ -91,6 +91,14 @@

Modules

Toggle

+
+

Media and Supports

+
BLUE
+
GREEN
+
RED
+
RED
+
+

Custom element

diff --git a/test/manual/src/bottom.css b/test/manual/src/bottom.css new file mode 100644 index 00000000..fae640d0 --- /dev/null +++ b/test/manual/src/bottom.css @@ -0,0 +1,7 @@ +.bottom { + color: blue; +} + +.media-and-supports { + color: blue; +} diff --git a/test/manual/src/index.js b/test/manual/src/index.js index b65b4a98..b4560797 100644 --- a/test/manual/src/index.js +++ b/test/manual/src/index.js @@ -29,6 +29,7 @@ import api2, { namedExportLazyBlue, namedExportLazyBackground, } from "./style.named-export.lazy.module.css"; +import "./top.css"; console.log("___LOCALS___"); console.log(component); diff --git a/test/manual/src/middle.css b/test/manual/src/middle.css new file mode 100644 index 00000000..106d8aee --- /dev/null +++ b/test/manual/src/middle.css @@ -0,0 +1,10 @@ +@import url("./bottom.css") supports(display: grid) screen and + (max-width: 2400px); + +.middle { + color: green; +} + +.media-and-supports { + color: green; +} diff --git a/test/manual/src/style.css b/test/manual/src/style.css index 36d48fef..cada6943 100644 --- a/test/manual/src/style.css +++ b/test/manual/src/style.css @@ -9,8 +9,3 @@ .blue { color: blue; } - -.background { - height: 1200px; - background: url("./logo.png") center no-repeat; -} diff --git a/test/manual/src/top.css b/test/manual/src/top.css new file mode 100644 index 00000000..bb3becb0 --- /dev/null +++ b/test/manual/src/top.css @@ -0,0 +1,10 @@ +@import url("./middle.css") supports(display: flex) screen and + (min-width: 400px); + +.top { + color: red; +} + +.media-and-supports { + color: red; +} diff --git a/test/manual/webpack.config.js b/test/manual/webpack.config.js index 24d0374d..c4c665ea 100644 --- a/test/manual/webpack.config.js +++ b/test/manual/webpack.config.js @@ -246,6 +246,7 @@ module.exports = { }, devServer: { hot: true, + liveReload: false, static: __dirname, }, }; diff --git a/test/runtime/__snapshots__/injectStylesIntoStyleTag.test.js.snap b/test/runtime/__snapshots__/injectStylesIntoStyleTag.test.js.snap index ab8f4ac0..19cc157a 100644 --- a/test/runtime/__snapshots__/injectStylesIntoStyleTag.test.js.snap +++ b/test/runtime/__snapshots__/injectStylesIntoStyleTag.test.js.snap @@ -38,6 +38,8 @@ exports[`addStyle should work with "insert" option 1`] = `"Title</t exports[`addStyle should work with "nonce" attribute and "__webpack_nonce__" variable 1`] = `"<head><title>Title

Hello world

"`; +exports[`addStyle should work with empty layer 1`] = `"Title

Hello world

"`; + exports[`addStyle should work with empty modules list #2 1`] = `"Title

Hello world

"`; exports[`addStyle should work with empty modules list #2 2`] = `"Title

Hello world

"`; @@ -56,7 +58,9 @@ exports[`addStyle should work with empty modules list 1`] = `"Title exports[`addStyle should work with empty modules list 2`] = `"<head><title>Title

Hello world

"`; -exports[`addStyle should work with media 1`] = `"Title

Hello world

"`; +exports[`addStyle should work with layer 1`] = `"Title

Hello world

"`; + +exports[`addStyle should work with media 1`] = `"Title

Hello world

"`; exports[`addStyle should work with multiple styles 1`] = `"Title

Hello world

"`; @@ -67,6 +71,8 @@ exports[`addStyle should work with source maps 1`] = ` /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLTUuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQXFCLGVBQWUsRUFBRSIsImZpbGUiOiJzdHlsZS01LmNzcyIsInNvdXJjZXNDb250ZW50IjpbIi5mb28geyBjb2xvcjogcmVkIH0iXX0= */

Hello world

" `; +exports[`addStyle should work with supports 1`] = `"Title

Hello world

"`; + exports[`addStyle should work with updates #2 1`] = `"Title

Hello world

"`; exports[`addStyle should work with updates #2 2`] = `"Title

Hello world

"`; @@ -79,9 +85,9 @@ exports[`addStyle should work with updates #4 1`] = `"Title exports[`addStyle should work with updates #4 2`] = `"Title

Hello world

"`; -exports[`addStyle should work with updates #5 1`] = `"Title

Hello world

"`; +exports[`addStyle should work with updates #5 1`] = `"Title

Hello world

"`; -exports[`addStyle should work with updates #5 2`] = `"Title

Hello world

"`; +exports[`addStyle should work with updates #5 2`] = `"Title

Hello world

"`; exports[`addStyle should work with updates #6 1`] = `"Title

Hello world

"`; @@ -102,14 +108,14 @@ exports[`addStyle should work with updates #7 1`] = `"Title exports[`addStyle should work with updates #7 2`] = `"Title

Hello world

"`; exports[`addStyle should work with updates #8 1`] = ` -"Title

Hello world

" `; exports[`addStyle should work with updates #8 2`] = ` -"Title

Hello world

" `; @@ -127,9 +133,9 @@ exports[`addStyle should work with updates #11 1`] = `"TitleTitle

Hello world

"`; -exports[`addStyle should work with updates #12 1`] = `"Title

Hello world

"`; +exports[`addStyle should work with updates #12 1`] = `"Title

Hello world

"`; -exports[`addStyle should work with updates #12 2`] = `"Title

Hello world

"`; +exports[`addStyle should work with updates #12 2`] = `"Title

Hello world

"`; exports[`addStyle should work with updates #12 3`] = `"Title

Hello world

"`; diff --git a/test/runtime/injectStylesIntoStyleTag.test.js b/test/runtime/injectStylesIntoStyleTag.test.js index f16ea707..9c1450bf 100644 --- a/test/runtime/injectStylesIntoStyleTag.test.js +++ b/test/runtime/injectStylesIntoStyleTag.test.js @@ -143,6 +143,44 @@ describe("addStyle", () => { expect(document.documentElement.innerHTML).toMatchSnapshot(); }); + it("should work with supports", () => { + injectStylesIntoStyleTag( + [ + [ + "./style-4.css", + ".foo { color: red }", + "", + // eslint-disable-next-line no-undefined + undefined, + "display: flex", + ], + ], + defaultOptions + ); + + expect(document.documentElement.innerHTML).toMatchSnapshot(); + }); + + it("should work with layer", () => { + injectStylesIntoStyleTag( + // eslint-disable-next-line no-undefined + [["./style-4.css", ".foo { color: red }", "", undefined, "", "default"]], + defaultOptions + ); + + expect(document.documentElement.innerHTML).toMatchSnapshot(); + }); + + it("should work with empty layer", () => { + injectStylesIntoStyleTag( + // eslint-disable-next-line no-undefined + [["./style-4.css", ".foo { color: red }", "", undefined, "", ""]], + defaultOptions + ); + + expect(document.documentElement.innerHTML).toMatchSnapshot(); + }); + it("should work with source maps", () => { injectStylesIntoStyleTag( [