зеркало из https://github.com/mozilla/kitsune.git
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:
Родитель
3800193c73
Коммит
e8d178c936
|
@ -28,6 +28,7 @@ Part 2: Developer's Guide
|
|||
localization
|
||||
search
|
||||
frontend
|
||||
svelte
|
||||
browser_permissions
|
||||
zendesk
|
||||
notes
|
||||
|
|
|
@ -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",
|
||||
|
|
Загрузка…
Ссылка в новой задаче