Skip to content

Issue 427 #824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a reference to Self. Should it be like this?

Suggested change
Self.loader,
MiniCssExtractPlugin.loader,

(same for next two occurrences)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is for tests

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I saw the tests. But this is the README right?

"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(() => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the chunk name comment required here, or is it optional? If it's required, would there be any way to define it in the webpack config rather than the source?

Just thinking out loud: It might be possible to use a pitching loader to expand a static ./style.scss import to one per theme (i.e. ../style.scss?dark, ./style.scss?light, ./style.scss?n...), and then use matching resource queries.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for tests and examples, for production I recommend to not use comments, because you will have less names for files, so you will send less bytes for client

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thank you. Would it make sense to revise this example to use production best practices?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to send a PR and fix it

Copy link

@benquarmby benquarmby Sep 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can certainly fix the Self references in the README. Stand by for that.

However, I don't actually know how to replace webpackChunkName comments with something more first class (for example, something we'd see in webpack.config.js). This is one of the reasons I've been following this issue so closely.

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Document</title>
<link id="theme" rel="stylesheet" type="text/css" href="./main.css" />
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
```

### 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:
Expand Down
85 changes: 85 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: black;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: white;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Document</title>
<link id="theme" rel="stylesheet" type="text/css" href="./main.css">
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$background: black;
Original file line number Diff line number Diff line change
@@ -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);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
$background: white;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: vars.$background;
}
Loading