ensure (s)css is handled properly by svelte (#5023)

involved some re-jigging of our scss files to ensure that unnecessary
bits of css weren't imported into svelte components when attempting to
import mixins or variables, as well as ensure imports are resolvable
by svelte-preprocess
This commit is contained in:
Leo McArdle 2022-03-14 10:33:34 +00:00 коммит произвёл Tasos Katsoulas
Родитель 3800193c73
Коммит e8d178c936
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 522F81314743785E
53 изменённых файлов: 147 добавлений и 68 удалений

Просмотреть файл

@ -28,6 +28,7 @@ Part 2: Developer's Guide
localization
search
frontend
svelte
browser_permissions
zendesk
notes

48
docs/svelte.md Normal file
Просмотреть файл

@ -0,0 +1,48 @@
# Svelte
## CSS/SASS
Svelte supports writing CSS directly in a component within `<style>` tags,
as well as writing compiled-to-CSS languages like SASS within `<style lang="scss">` tags.
CSS written this way is automatically scoped to the component:
[read more in the Svelte docs](https://svelte.dev/docs#component-format-style).
This SASS to CSS compilation is handled by `svelte-preprocess`,
and the resulting CSS is handed to Wepback for further processing.
Since Webpack isn't involved in SASS compilation within Svelte components,
care must be taken in a few areas:
1. Because Webpack isn't handling `@use` and `@import` resolution,
it's not possible to use its aliases to reference paths to other SASS files.
Instead paths relative to the Svelte component,
or full node module paths,
must be used.
This _doesn't_ include paths not processed by the SASS compiler,
such as paths to images in `url()` functions,
as these are still handled by Webpack.
To illustrate:
```scss
@use "@mozilla-protocol/core/protocol/css/includes/lib" as p;
@use "../../kitsune/sumo/static/sumo/scss/config/typography-mixins";
// ^ here we must use a full or relative path, as svelte-preprocess is resolving this
div {
background: url("protocol/img/icons/reader-mode.svg");
// ^ here we can use a webpack alias, as webpack is resolving this
background-size: p.$spacing-md;
@include typography-mixins.text-display-sm;
}
```
2. As a knock-on effect of the above,
any partials used in both our main CSS bundle,
as well as a Svelte component (like the `typography-mixins` above)
must not use Webpack aliases in their own imports,
otherwise `svelte-preprocess` won't be able to resolve them.
3. Partials should be careful to not accidentally include or import CSS blocks outside of mixin defintions.
This is because neither `svelte-preprocess` nor the Webpack `sass-loader` are able to chunk split `@import`s and `@use`s,
or even de-duplicate their use across Svelte components (due to the scoped nature of the CSS within).
Not doing this will lead to unnecessarily duplicated code.

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.sumo-dl {
display: flex;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Tables

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Typography
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Expanded link utility
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config' as c;
@use '../../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Button Wrap element
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config' as c;
@use '../../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Buttons
//
@ -238,7 +238,7 @@ input[type=submit]:focus {
background: transparent;
font: 0/0 a;
color: transparent;
background-image: url('#{p.$image-path}/icons/more-vertical.svg');
background-image: url('protocol/img/icons/more-vertical.svg');
background-size: p.$spacing-lg p.$spacing-lg;
background-position: center center;
background-repeat: no-repeat;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config'as c;
@use '../../protocol'as p;
@use '../../config' as c;
@use 'protocol/css/includes/lib' as p;
:root {
--field-border-color-default: var(--color-marketing-gray-05);

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config' as c;
@use '../../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Checkboxes
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config' as c;
@use '../../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Range inputs
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config' as c;
@use '../../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.simple-search-form {
position: relative;
@ -45,7 +45,7 @@
height: p.$spacing-xl;
border: none;
border-radius: p.$spacing-xs;
background-image: url('#{p.$image-path}/icons/search.svg');
background-image: url('protocol/img/icons/search.svg');
background-color: transparent;
background-position: center center;
background-repeat: no-repeat;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../../config' as c;
@use '../../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Toggles
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.avatar-group {
@include c.grid-row();

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Banners
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Breadcrumbs
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Card Grid
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Cards
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
div.editor-tools {
&:not(:empty) {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.has-icon,
.is-details .mzp-c-menu-list-item a.has-icon {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.message-list {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// This component should be replaced with Protocol's modal system, because
// it doesn't make sense to include two of them. However, this plugin is doing

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.mzp-c-modal-inner {
@ -11,7 +11,7 @@
}
.mzp-c-modal-close .mzp-c-modal-button-close {
background: transparent url("#{p.$image-path}/icons/close.svg") center center no-repeat;
background: transparent url("protocol/img/icons/close.svg") center center no-repeat;
}

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// This is a container for Protocol notifications. See
// https://protocol.mozilla.org/patterns/molecules/notification-bar.html

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Pagination
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.is-details.mzp-c-menu-list.featured-dropdown,
.is-details.mzp-c-menu-list.subheading-dropdown, {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Progress Bar
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Sidebar navigation
//
@ -62,7 +62,7 @@
.related-document,
.related-question {
@include c.text-body-md;
background-image: url("#{p.$image-path}/icons/blog.svg");
background-image: url("protocol/img/icons/blog.svg");
background-repeat: no-repeat;
background-position: 0px 6px;
background-size: p.$spacing-md p.$spacing-md;
@ -70,7 +70,7 @@
}
.related-document {
background-image: url("#{p.$image-path}/icons/reader-mode.svg");
background-image: url("protocol/img/icons/reader-mode.svg");
}
li.selected > :link,

Просмотреть файл

@ -11,7 +11,7 @@
// Style guide: tabs
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
%link-styles {
appearance: none;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// .editable .edit-mode {
// display: none;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// These styles were pulled directly from the less files.
@ -412,23 +412,23 @@ article {
.delete {
a {
background-image: url("#{p.$image-path}/icons/delete.svg");
background-image: url("protocol/img/icons/delete.svg");
}
}
.l10n {
a {
&.yes {
background-image: url("#{p.$image-path}/icons/check.svg");
background-image: url("protocol/img/icons/check.svg");
}
&.markasready,
&.no {
background-image: url("#{p.$image-path}/icons/close.svg");
background-image: url("protocol/img/icons/close.svg");
}
&.markasready:hover {
background-image: url("#{p.$image-path}/icons/check.svg");
background-image: url("protocol/img/icons/check.svg");
cursor: pointer;
}
}

Просмотреть файл

@ -1,4 +1,4 @@
@use '../protocol' as p;
@use '@mozilla-protocol/core/protocol/css/includes/lib' as p;
@use './variables' as c;

Просмотреть файл

@ -1,5 +1,5 @@
@use './color-swatches';
@use '../protocol' as p;
@use '@mozilla-protocol/core/protocol/css/includes/lib' as p;
@use 'sass:map';
// Think in pixels, but use rems. Takes a whole number.

Просмотреть файл

@ -1,5 +1,5 @@
@use './mixins' as c;
@use '../protocol' as p;
@use '@mozilla-protocol/core/protocol/css/includes/lib' as p;
@use './color-swatches' as swatches;
:root {

Просмотреть файл

@ -1,4 +1,4 @@
@use '../protocol' as p;
@use '@mozilla-protocol/core/protocol/css/includes/lib' as p;
@use './mixins' as c;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.aaq {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.sumo-auth {

Просмотреть файл

@ -1,4 +1,4 @@
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
@use '../config' as c;
.results-user {
@ -56,7 +56,7 @@
height: p.$spacing-md;
border: none;
border-radius: p.$spacing-xs;
background-image: url('#{p.$image-path}/icons/check.svg');
background-image: url('protocol/img/icons/check.svg');
background-color: transparent;
background-position: center center;
background-repeat: no-repeat;

Просмотреть файл

@ -1,4 +1,4 @@
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
@use '../config' as c;
// Containers

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.contributor-list {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.document {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Footer
//

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.forum {
&--question-item {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// Navigation
//
@ -191,7 +191,7 @@
height: p.$spacing-xl;
border: none;
border-radius: p.$spacing-xs;
background-image: url('#{p.$image-path}/icons/menu.svg');
background-image: url('protocol/img/icons/menu.svg');
background-color: transparent;
background-position: center center;
background-repeat: no-repeat;
@ -215,7 +215,7 @@
(margin-left, auto, 0),
(margin-right, 0, auto),
));
background-image: url('#{p.$image-path}/icons/search.svg');
background-image: url('protocol/img/icons/search.svg');
}
.simple-search-form {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.sumo-page-subheader {

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config'as c;
@use '../protocol'as p;
@use '../config' as c;
@use 'protocol/css/includes/lib' as p;
.badges-list {
display: flex;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
// this class is added to the body when the instant search is active. It should

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.topic-article {
display: flex;

Просмотреть файл

@ -1,5 +1,5 @@
@use '../config' as c;
@use '../protocol' as p;
@use 'protocol/css/includes/lib' as p;
.sumo-l-two-col {
@include c.grid-row();

Просмотреть файл

@ -90,6 +90,7 @@
"stylelint-order": "^5.0.0",
"stylelint-scss": "^4.1.0",
"svelte-loader": "^3.1.2",
"svelte-preprocess": "^4.10.2",
"webpack": "^5.65.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2",

Просмотреть файл

@ -31,3 +31,11 @@
</Route>
</Router>
</div>
<style lang="scss">
@use "../../kitsune/sumo/static/sumo/scss/config/typography-mixins";
h1 {
@include typography-mixins.text-display-sm;
}
</style>

Просмотреть файл

@ -7,3 +7,17 @@
<li>
<Link {to}><slot /></Link>
</li>
<style lang="scss">
@use "@mozilla-protocol/core/protocol/css/includes/lib" as p;
li {
&::before {
content: "";
background: url("protocol/img/icons/reader-mode.svg");
background-repeat: no-repeat;
background-size: p.$spacing-md p.$spacing-md;
padding-left: p.$spacing-lg;
}
}
</style>

Просмотреть файл

@ -1,6 +1,7 @@
const webpack = require("webpack");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const sveltePreprocess = require("svelte-preprocess");
module.exports = {
mode: "development",
@ -10,10 +11,10 @@ module.exports = {
sumo: path.resolve(__dirname, "kitsune/sumo/static/sumo"),
community: path.resolve(__dirname, "kitsune/community/static/community"),
kpi: path.resolve(__dirname, "kitsune/kpi/static/kpi"),
svelte: path.resolve('node_modules', 'svelte')
svelte: path.resolve("node_modules", "svelte"),
},
extensions: ['.mjs', '.js', '.svelte'],
mainFields: ['svelte', 'browser', 'module', 'main']
extensions: [".mjs", ".js", ".svelte"],
mainFields: ["svelte", "browser", "module", "main"],
},
module: {
rules: [
@ -43,17 +44,23 @@ module.exports = {
},
{
test: /\.svelte$/,
use: "svelte-loader",
use: {
loader: "svelte-loader",
options: {
emitCss: true,
preprocess: sveltePreprocess(),
},
},
},
{
// required to prevent errors from Svelte on Webpack 5+
test: /node_modules\/svelte\/.*\.mjs$/,
resolve: {
fullySpecified: false
}
fullySpecified: false,
},
},
{
test: /\.scss$/,
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",