From 6f92568a72c69bf186984de1b77dccaf9c064c23 Mon Sep 17 00:00:00 2001
From: evilebottnawi
Date: Mon, 6 Sep 2021 16:59:54 +0300
Subject: [PATCH 1/4] test: multiple themes based on entries
---
README.md | 128 ++++++++++++++++++
package-lock.json | 85 ++++++++++++
package.json | 2 +
.../expected/dark-theme.css | 3 +
.../expected/light-theme.css | 3 +
.../public/index.html | 15 ++
.../src/dark-theme/_vars.scss | 1 +
.../multi-theme-based-on-entries/src/index.js | 28 ++++
.../src/light-theme/_vars.scss | 1 +
.../src/style.scss | 3 +
.../webpack.config.js | 57 ++++++++
11 files changed, 326 insertions(+)
create mode 100644 test/cases/multi-theme-based-on-entries/expected/dark-theme.css
create mode 100644 test/cases/multi-theme-based-on-entries/expected/light-theme.css
create mode 100644 test/cases/multi-theme-based-on-entries/public/index.html
create mode 100644 test/cases/multi-theme-based-on-entries/src/dark-theme/_vars.scss
create mode 100644 test/cases/multi-theme-based-on-entries/src/index.js
create mode 100644 test/cases/multi-theme-based-on-entries/src/light-theme/_vars.scss
create mode 100644 test/cases/multi-theme-based-on-entries/src/style.scss
create mode 100644 test/cases/multi-theme-based-on-entries/webpack.config.js
diff --git a/README.md b/README.md
index 1c0905b0..adca50eb 100644
--- a/README.md
+++ b/README.md
@@ -911,6 +911,134 @@ module.exports = {
};
```
+### Multiple Themes
+
+**webpack.config.js**
+
+```js
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+
+module.exports = {
+ entry: {
+ "light-theme": {
+ import: ["./src/index.js", "./src/style.scss"],
+ },
+ "dark-theme": {
+ import: ["./src/index.js", "./src/style.scss?dark"],
+ },
+ },
+ // For better runtime code caching
+ optimization: {
+ runtimeChunk: {
+ name: "runtime",
+ },
+ },
+ 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 MiniCssExtractPlugin({
+ filename: "[name].css",
+ }),
+ ],
+};
+```
+
+**src/index.js**
+
+```js
+let theme = "light";
+
+document.onclick = () => {
+ console.log("CHANGING THEME...");
+
+ if (theme === "light") {
+ theme = "dark";
+ } else {
+ theme = "light";
+ }
+
+ const themeElement = document.querySelector("#theme");
+
+ if (themeElement) {
+ themeElement.remove();
+ }
+
+ const linkElement = document.createElement("link");
+
+ linkElement.type = "text/css";
+ linkElement.rel = "stylesheet";
+ linkElement.href = `${theme}-theme.css`;
+
+ document.getElementsByTagName("head")[0].appendChild(linkElement);
+
+ console.log("THEME WAS CHANGED");
+};
+```
+
+**src/dark-theme/\_vars**
+
+```scss
+$background: black;
+```
+
+**src/light-theme/\_vars**
+
+```scss
+$background: white;
+```
+
+**public/index.html**
+
+```html
+
+
+
+
+
+
+ Multiple Themes
+
+
+
+
+
+
+
+
+```
+
### 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/multi-theme-based-on-entries/expected/dark-theme.css b/test/cases/multi-theme-based-on-entries/expected/dark-theme.css
new file mode 100644
index 00000000..c4d554e0
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/expected/dark-theme.css
@@ -0,0 +1,3 @@
+body {
+ background-color: black;
+}
diff --git a/test/cases/multi-theme-based-on-entries/expected/light-theme.css b/test/cases/multi-theme-based-on-entries/expected/light-theme.css
new file mode 100644
index 00000000..cdf802a3
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/expected/light-theme.css
@@ -0,0 +1,3 @@
+body {
+ background-color: white;
+}
diff --git a/test/cases/multi-theme-based-on-entries/public/index.html b/test/cases/multi-theme-based-on-entries/public/index.html
new file mode 100644
index 00000000..60bc9273
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/public/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/cases/multi-theme-based-on-entries/src/dark-theme/_vars.scss b/test/cases/multi-theme-based-on-entries/src/dark-theme/_vars.scss
new file mode 100644
index 00000000..2abe50c6
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/src/dark-theme/_vars.scss
@@ -0,0 +1 @@
+$background: black;
diff --git a/test/cases/multi-theme-based-on-entries/src/index.js b/test/cases/multi-theme-based-on-entries/src/index.js
new file mode 100644
index 00000000..5656faba
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/src/index.js
@@ -0,0 +1,28 @@
+/* eslint-env browser */
+
+let theme = "light";
+
+document.onclick = () => {
+ // eslint-disable-next-line no-console
+ console.log("CHANGE THEME");
+
+ if (theme === "light") {
+ theme = "dark";
+ } else {
+ theme = "light";
+ }
+
+ const themeElement = document.querySelector("#theme");
+
+ if (themeElement) {
+ themeElement.remove();
+ }
+
+ const linkElement = document.createElement("link");
+
+ linkElement.type = "text/css";
+ linkElement.rel = "stylesheet";
+ linkElement.href = `${theme}-theme.css`;
+
+ document.getElementsByTagName("head")[0].appendChild(linkElement);
+};
diff --git a/test/cases/multi-theme-based-on-entries/src/light-theme/_vars.scss b/test/cases/multi-theme-based-on-entries/src/light-theme/_vars.scss
new file mode 100644
index 00000000..6a1fb84b
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/src/light-theme/_vars.scss
@@ -0,0 +1 @@
+$background: white;
diff --git a/test/cases/multi-theme-based-on-entries/src/style.scss b/test/cases/multi-theme-based-on-entries/src/style.scss
new file mode 100644
index 00000000..fb281175
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/src/style.scss
@@ -0,0 +1,3 @@
+body {
+ background-color: vars.$background;
+}
diff --git a/test/cases/multi-theme-based-on-entries/webpack.config.js b/test/cases/multi-theme-based-on-entries/webpack.config.js
new file mode 100644
index 00000000..fd4f2b56
--- /dev/null
+++ b/test/cases/multi-theme-based-on-entries/webpack.config.js
@@ -0,0 +1,57 @@
+import Self from "../../../src";
+
+module.exports = {
+ entry: {
+ "light-theme": {
+ import: ["./src/index.js", "./src/style.scss"],
+ },
+ "dark-theme": {
+ import: ["./src/index.js", "./src/style.scss?dark"],
+ },
+ },
+ // For better runtime code caching
+ optimization: {
+ runtimeChunk: {
+ name: "runtime",
+ },
+ },
+ 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",
+ }),
+ ],
+};
From 4ca4630fff4ceaae8be85f5f426d6721d0a2faa4 Mon Sep 17 00:00:00 2001
From: evilebottnawi
Date: Mon, 6 Sep 2021 17:54:26 +0300
Subject: [PATCH 2/4] test: more tests
---
README.md | 76 ++++++++++---------
.../public/index.html | 15 ----
.../multi-theme-based-on-entries/src/index.js | 28 -------
.../expected/dark.css} | 0
.../expected/main.css} | 0
.../public/index.html | 12 +++
.../src/dark-theme/_vars.scss | 0
.../src/index.js | 50 ++++++++++++
.../src/light-theme/_vars.scss | 0
.../src/style.scss | 0
.../webpack.config.js | 18 +----
.../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 | 49 ++++++++++++
19 files changed, 237 insertions(+), 91 deletions(-)
delete mode 100644 test/cases/multi-theme-based-on-entries/public/index.html
delete mode 100644 test/cases/multi-theme-based-on-entries/src/index.js
rename test/cases/{multi-theme-based-on-entries/expected/dark-theme.css => multiple-themes-async-loading-with-default-light/expected/dark.css} (100%)
rename test/cases/{multi-theme-based-on-entries/expected/light-theme.css => multiple-themes-async-loading-with-default-light/expected/main.css} (100%)
create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/public/index.html
rename test/cases/{multi-theme-based-on-entries => multiple-themes-async-loading-with-default-light}/src/dark-theme/_vars.scss (100%)
create mode 100644 test/cases/multiple-themes-async-loading-with-default-light/src/index.js
rename test/cases/{multi-theme-based-on-entries => multiple-themes-async-loading-with-default-light}/src/light-theme/_vars.scss (100%)
rename test/cases/{multi-theme-based-on-entries => multiple-themes-async-loading-with-default-light}/src/style.scss (100%)
rename test/cases/{multi-theme-based-on-entries => multiple-themes-async-loading-with-default-light}/webpack.config.js (74%)
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 adca50eb..bfede678 100644
--- a/README.md
+++ b/README.md
@@ -919,20 +919,7 @@ module.exports = {
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
- entry: {
- "light-theme": {
- import: ["./src/index.js", "./src/style.scss"],
- },
- "dark-theme": {
- import: ["./src/index.js", "./src/style.scss?dark"],
- },
- },
- // For better runtime code caching
- optimization: {
- runtimeChunk: {
- name: "runtime",
- },
- },
+ entry: "./src/index.js",
module: {
rules: [
{
@@ -968,8 +955,11 @@ module.exports = {
],
},
plugins: [
- new MiniCssExtractPlugin({
+ new Self({
filename: "[name].css",
+ attributes: {
+ id: "theme",
+ },
}),
],
};
@@ -978,16 +968,16 @@ module.exports = {
**src/index.js**
```js
+import "./style.scss";
+
let theme = "light";
+const themes = {};
-document.onclick = () => {
- console.log("CHANGING THEME...");
+themes[theme] = document.querySelector("#theme");
- if (theme === "light") {
- theme = "dark";
- } else {
- theme = "light";
- }
+async function loadTheme(newTheme) {
+ // eslint-disable-next-line no-console
+ console.log(`CHANGE THEME - ${newTheme}`);
const themeElement = document.querySelector("#theme");
@@ -995,15 +985,36 @@ document.onclick = () => {
themeElement.remove();
}
- const linkElement = document.createElement("link");
+ 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}`);
- linkElement.type = "text/css";
- linkElement.rel = "stylesheet";
- linkElement.href = `${theme}-theme.css`;
+ import(/* webpackChunkName: "dark" */ "./style.scss?dark").then(() => {
+ themes[newTheme] = document.querySelector("#theme");
- document.getElementsByTagName("head")[0].appendChild(linkElement);
+ // eslint-disable-next-line no-console
+ console.log(`LOADED - ${newTheme}`);
+ });
+ }
+}
+
+document.onclick = () => {
+ if (theme === "light") {
+ theme = "dark";
+ } else {
+ theme = "light";
+ }
- console.log("THEME WAS CHANGED");
+ loadTheme(theme);
};
```
@@ -1027,14 +1038,11 @@ $background: white;
-
- Multiple Themes
-
-
+ Document
+
-
-
+