From 7b32255c295f6a5b0cbdbd76b74fa272840d4c70 Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Mon, 6 Sep 2021 18:11:37 +0300 Subject: [PATCH] docs: example of multiple themes --- README.md | 144 ++++++++++++++++++ package-lock.json | 85 +++++++++++ package.json | 2 + .../expected/dark.css | 3 + .../expected/main.css | 3 + .../public/index.html | 12 ++ .../src/dark-theme/_vars.scss | 1 + .../src/index.js | 50 ++++++ .../src/light-theme/_vars.scss | 1 + .../src/style.scss | 3 + .../webpack.config.js | 47 ++++++ .../expected/dark.css | 3 + .../expected/light.css | 3 + .../public/index.html | 11 ++ .../src/dark-theme/_vars.scss | 1 + .../src/index.js | 58 +++++++ .../src/light-theme/_vars.scss | 1 + .../src/style.scss | 3 + .../webpack.config.js | 47 ++++++ 19 files changed, 478 insertions(+) create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/expected/dark.css create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/expected/main.css create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/public/index.html create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/src/dark-theme/_vars.scss create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/src/index.js create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/src/light-theme/_vars.scss create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/src/style.scss create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/webpack.config.js create mode 100644 test/cases/multiple-themes-async-loading/expected/dark.css create mode 100644 test/cases/multiple-themes-async-loading/expected/light.css create mode 100644 test/cases/multiple-themes-async-loading/public/index.html create mode 100644 test/cases/multiple-themes-async-loading/src/dark-theme/_vars.scss create mode 100644 test/cases/multiple-themes-async-loading/src/index.js create mode 100644 test/cases/multiple-themes-async-loading/src/light-theme/_vars.scss create mode 100644 test/cases/multiple-themes-async-loading/src/style.scss create mode 100644 test/cases/multiple-themes-async-loading/webpack.config.js diff --git a/README.md b/README.md index 1c0905b0..bf483fab 100644 --- a/README.md +++ b/README.md @@ -911,6 +911,150 @@ module.exports = { }; ``` +### Multiple Themes + +**webpack.config.js** + +```js +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); + +module.exports = { + entry: "./src/index.js", + module: { + rules: [ + { + test: /\.s[ac]ss$/i, + oneOf: [ + { + resourceQuery: "?dark", + use: [ + Self.loader, + "css-loader", + { + loader: "sass-loader", + options: { + additionalData: `@use 'dark-theme/vars' as vars;`, + }, + }, + ], + }, + { + use: [ + Self.loader, + "css-loader", + { + loader: "sass-loader", + options: { + additionalData: `@use 'light-theme/vars' as vars;`, + }, + }, + ], + }, + ], + }, + ], + }, + plugins: [ + new Self({ + filename: "[name].css", + attributes: { + id: "theme", + }, + }), + ], +}; +``` + +**src/index.js** + +```js +import "./style.scss"; + +let theme = "light"; +const themes = {}; + +themes[theme] = document.querySelector("#theme"); + +async function loadTheme(newTheme) { + // eslint-disable-next-line no-console + console.log(`CHANGE THEME - ${newTheme}`); + + const themeElement = document.querySelector("#theme"); + + if (themeElement) { + themeElement.remove(); + } + + if (themes[newTheme]) { + // eslint-disable-next-line no-console + console.log(`THEME ALREADY LOADED - ${newTheme}`); + + document.head.appendChild(themes[newTheme]); + + return; + } + + if (newTheme === "dark") { + // eslint-disable-next-line no-console + console.log(`LOADING THEME - ${newTheme}`); + + import(/* webpackChunkName: "dark" */ "./style.scss?dark").then(() => { + themes[newTheme] = document.querySelector("#theme"); + + // eslint-disable-next-line no-console + console.log(`LOADED - ${newTheme}`); + }); + } +} + +document.onclick = () => { + if (theme === "light") { + theme = "dark"; + } else { + theme = "light"; + } + + loadTheme(theme); +}; +``` + +**src/dark-theme/\_vars.scss** + +```scss +$background: black; +``` + +**src/light-theme/\_vars.scss** + +```scss +$background: white; +``` + +**src/styles.scss** + +```scss +body { + background-color: vars.$background; +} +``` + +**public/index.html** + +```html + + + + + + Document + + + + + + +``` + ### Media Query Plugin If you'd like to extract the media queries from the extracted CSS (so mobile users don't need to load desktop or tablet specific CSS anymore) you should use one of the following plugins: diff --git a/package-lock.json b/package-lock.json index 25ab70db..6a8cb0cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,8 @@ "memfs": "^3.0.2", "npm-run-all": "^4.1.5", "prettier": "^2.3.2", + "sass": "^1.39.0", + "sass-loader": "^12.1.0", "standard-version": "^9.3.0", "webpack": "^5.48.0", "webpack-cli": "^4.7.2", @@ -11633,6 +11635,15 @@ "node": ">=6" } }, + "node_modules/klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -14776,6 +14787,55 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "node_modules/sass": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.39.0.tgz", + "integrity": "sha512-F4o+RhJkNOIG0b6QudYU8c78ZADKZjKDk5cyrf8XTKWfrgbtyVVXImFstJrc+1pkQDCggyidIOytq6gS4gCCZg==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/sass-loader": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.1.0.tgz", + "integrity": "sha512-FVJZ9kxVRYNZTIe2xhw93n3xJNYZADr+q69/s98l9nTCrWASo+DR2Ot0s5xTKQDDEosUkatsGeHxcH4QBp5bSg==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0", + "sass": "^1.3.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, "node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -26188,6 +26248,12 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "klona": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", + "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "dev": true + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -28557,6 +28623,25 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "sass": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.39.0.tgz", + "integrity": "sha512-F4o+RhJkNOIG0b6QudYU8c78ZADKZjKDk5cyrf8XTKWfrgbtyVVXImFstJrc+1pkQDCggyidIOytq6gS4gCCZg==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.1.0.tgz", + "integrity": "sha512-FVJZ9kxVRYNZTIe2xhw93n3xJNYZADr+q69/s98l9nTCrWASo+DR2Ot0s5xTKQDDEosUkatsGeHxcH4QBp5bSg==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", diff --git a/package.json b/package.json index 947fc76a..a6715cb9 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,8 @@ "memfs": "^3.0.2", "npm-run-all": "^4.1.5", "prettier": "^2.3.2", + "sass": "^1.39.0", + "sass-loader": "^12.1.0", "standard-version": "^9.3.0", "webpack": "^5.48.0", "webpack-cli": "^4.7.2", diff --git a/test/cases/multiple-themes-async-loading-with-default-light/expected/dark.css b/test/cases/multiple-themes-async-loading-with-default-light/expected/dark.css new file mode 100644 index 00000000..c4d554e0 --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/expected/dark.css @@ -0,0 +1,3 @@ +body { + background-color: black; +} diff --git a/test/cases/multiple-themes-async-loading-with-default-light/expected/main.css b/test/cases/multiple-themes-async-loading-with-default-light/expected/main.css new file mode 100644 index 00000000..cdf802a3 --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/expected/main.css @@ -0,0 +1,3 @@ +body { + background-color: white; +} diff --git a/test/cases/multiple-themes-async-loading-with-default-light/public/index.html b/test/cases/multiple-themes-async-loading-with-default-light/public/index.html new file mode 100644 index 00000000..061216f2 --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/public/index.html @@ -0,0 +1,12 @@ + + + + + + Document + + + + + + \ No newline at end of file diff --git a/test/cases/multiple-themes-async-loading-with-default-light/src/dark-theme/_vars.scss b/test/cases/multiple-themes-async-loading-with-default-light/src/dark-theme/_vars.scss new file mode 100644 index 00000000..2abe50c6 --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/src/dark-theme/_vars.scss @@ -0,0 +1 @@ +$background: black; diff --git a/test/cases/multiple-themes-async-loading-with-default-light/src/index.js b/test/cases/multiple-themes-async-loading-with-default-light/src/index.js new file mode 100644 index 00000000..cce9cc7c --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/src/index.js @@ -0,0 +1,50 @@ +/* eslint-env browser */ +import "./style.scss"; + +let theme = "light"; +const themes = {}; + +themes[theme] = document.querySelector("#theme"); + +async function loadTheme(newTheme) { + // eslint-disable-next-line no-console + console.log(`CHANGE THEME - ${newTheme}`); + + const themeElement = document.querySelector("#theme"); + + if (themeElement) { + themeElement.remove(); + } + + if (themes[newTheme]) { + // eslint-disable-next-line no-console + console.log(`THEME ALREADY LOADED - ${newTheme}`); + + document.head.appendChild(themes[newTheme]); + + return; + } + + if (newTheme === "dark") { + // eslint-disable-next-line no-console + console.log(`LOADING THEME - ${newTheme}`); + + // eslint-disable-next-line import/no-unresolved + import(/* webpackChunkName: "dark" */ "./style.scss?dark").then(() => { + themes[newTheme] = document.querySelector("#theme"); + + // eslint-disable-next-line no-console + console.log(`LOADED - ${newTheme}`); + }); + } +} + +document.onclick = () => { + if (theme === "light") { + theme = "dark"; + } else { + theme = "light"; + } + + loadTheme(theme); +}; diff --git a/test/cases/multiple-themes-async-loading-with-default-light/src/light-theme/_vars.scss b/test/cases/multiple-themes-async-loading-with-default-light/src/light-theme/_vars.scss new file mode 100644 index 00000000..6a1fb84b --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/src/light-theme/_vars.scss @@ -0,0 +1 @@ +$background: white; diff --git a/test/cases/multiple-themes-async-loading-with-default-light/src/style.scss b/test/cases/multiple-themes-async-loading-with-default-light/src/style.scss new file mode 100644 index 00000000..fb281175 --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/src/style.scss @@ -0,0 +1,3 @@ +body { + background-color: vars.$background; +} diff --git a/test/cases/multiple-themes-async-loading-with-default-light/webpack.config.js b/test/cases/multiple-themes-async-loading-with-default-light/webpack.config.js new file mode 100644 index 00000000..58c979cd --- /dev/null +++ b/test/cases/multiple-themes-async-loading-with-default-light/webpack.config.js @@ -0,0 +1,47 @@ +import Self from "../../../src"; + +module.exports = { + entry: "./src/index.js", + module: { + rules: [ + { + test: /\.s[ac]ss$/i, + oneOf: [ + { + resourceQuery: "?dark", + use: [ + Self.loader, + "css-loader", + { + loader: "sass-loader", + options: { + additionalData: `@use 'dark-theme/vars' as vars;`, + }, + }, + ], + }, + { + use: [ + Self.loader, + "css-loader", + { + loader: "sass-loader", + options: { + additionalData: `@use 'light-theme/vars' as vars;`, + }, + }, + ], + }, + ], + }, + ], + }, + plugins: [ + new Self({ + filename: "[name].css", + attributes: { + id: "theme", + }, + }), + ], +}; diff --git a/test/cases/multiple-themes-async-loading/expected/dark.css b/test/cases/multiple-themes-async-loading/expected/dark.css new file mode 100644 index 00000000..c4d554e0 --- /dev/null +++ b/test/cases/multiple-themes-async-loading/expected/dark.css @@ -0,0 +1,3 @@ +body { + background-color: black; +} diff --git a/test/cases/multiple-themes-async-loading/expected/light.css b/test/cases/multiple-themes-async-loading/expected/light.css new file mode 100644 index 00000000..cdf802a3 --- /dev/null +++ b/test/cases/multiple-themes-async-loading/expected/light.css @@ -0,0 +1,3 @@ +body { + background-color: white; +} diff --git a/test/cases/multiple-themes-async-loading/public/index.html b/test/cases/multiple-themes-async-loading/public/index.html new file mode 100644 index 00000000..c51cce96 --- /dev/null +++ b/test/cases/multiple-themes-async-loading/public/index.html @@ -0,0 +1,11 @@ + + + + + + Document + + + + + \ No newline at end of file diff --git a/test/cases/multiple-themes-async-loading/src/dark-theme/_vars.scss b/test/cases/multiple-themes-async-loading/src/dark-theme/_vars.scss new file mode 100644 index 00000000..2abe50c6 --- /dev/null +++ b/test/cases/multiple-themes-async-loading/src/dark-theme/_vars.scss @@ -0,0 +1 @@ +$background: black; diff --git a/test/cases/multiple-themes-async-loading/src/index.js b/test/cases/multiple-themes-async-loading/src/index.js new file mode 100644 index 00000000..8c016077 --- /dev/null +++ b/test/cases/multiple-themes-async-loading/src/index.js @@ -0,0 +1,58 @@ +/* eslint-env browser */ + +let theme = "light"; + +const themes = {}; + +async function loadTheme(newTheme) { + // eslint-disable-next-line no-console + console.log(`CHANGE THEME - ${newTheme}`); + + const themeElement = document.querySelector("#theme"); + + if (themeElement) { + themeElement.remove(); + } + + if (themes[newTheme]) { + // eslint-disable-next-line no-console + // eslint-disable-next-line no-console + console.log(`THEME ALREADY LOADED - ${newTheme}`); + + document.head.appendChild(themes[newTheme]); + + return; + } + + // eslint-disable-next-line no-console + console.log(`LOADING THEME - ${newTheme}`); + + if (newTheme === "light") { + import(/* webpackChunkName: "light" */ "./style.scss").then(() => { + themes[newTheme] = document.querySelector("#theme"); + + // eslint-disable-next-line no-console + console.log(`LOADED - ${newTheme}`); + }); + } else { + // eslint-disable-next-line import/no-unresolved + import(/* webpackChunkName: "dark" */ "./style.scss?dark").then(() => { + themes[newTheme] = document.querySelector("#theme"); + + // eslint-disable-next-line no-console + console.log(`LOADED - ${newTheme}`); + }); + } +} + +document.onclick = () => { + if (theme === "light") { + theme = "dark"; + } else { + theme = "light"; + } + + loadTheme(theme); +}; + +loadTheme(theme); diff --git a/test/cases/multiple-themes-async-loading/src/light-theme/_vars.scss b/test/cases/multiple-themes-async-loading/src/light-theme/_vars.scss new file mode 100644 index 00000000..6a1fb84b --- /dev/null +++ b/test/cases/multiple-themes-async-loading/src/light-theme/_vars.scss @@ -0,0 +1 @@ +$background: white; diff --git a/test/cases/multiple-themes-async-loading/src/style.scss b/test/cases/multiple-themes-async-loading/src/style.scss new file mode 100644 index 00000000..fb281175 --- /dev/null +++ b/test/cases/multiple-themes-async-loading/src/style.scss @@ -0,0 +1,3 @@ +body { + background-color: vars.$background; +} diff --git a/test/cases/multiple-themes-async-loading/webpack.config.js b/test/cases/multiple-themes-async-loading/webpack.config.js new file mode 100644 index 00000000..58c979cd --- /dev/null +++ b/test/cases/multiple-themes-async-loading/webpack.config.js @@ -0,0 +1,47 @@ +import Self from "../../../src"; + +module.exports = { + entry: "./src/index.js", + module: { + rules: [ + { + test: /\.s[ac]ss$/i, + oneOf: [ + { + resourceQuery: "?dark", + use: [ + Self.loader, + "css-loader", + { + loader: "sass-loader", + options: { + additionalData: `@use 'dark-theme/vars' as vars;`, + }, + }, + ], + }, + { + use: [ + Self.loader, + "css-loader", + { + loader: "sass-loader", + options: { + additionalData: `@use 'light-theme/vars' as vars;`, + }, + }, + ], + }, + ], + }, + ], + }, + plugins: [ + new Self({ + filename: "[name].css", + attributes: { + id: "theme", + }, + }), + ], +};