Skip to content

feat: add the :global {} rule support #161

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 10 commits into from
Jun 5, 2020
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
# [3.9.0](https://github.com/kaisermann/svelte-preprocess/compare/v3.7.4...v3.9.0) (2020-06-05)


### Bug Fixes

* 🐛 run globalRule only if postcss is installed ([6294750](https://github.com/kaisermann/svelte-preprocess/commit/62947507064271d1cec796d3e0a7801633b875a8))


### Features

* add implementation option for scss ([e4ca556](https://github.com/kaisermann/svelte-preprocess/commit/e4ca556821785e2b853f1668489912ebab21ee4b))
* add the [@global](https://github.com/global) {} rule support ([46722ba](https://github.com/kaisermann/svelte-preprocess/commit/46722bac993308d8e4f1bb3d0b3086b802013d3d))
* replace the [@global](https://github.com/global) for :global for CSS modules compliance ([3c6a574](https://github.com/kaisermann/svelte-preprocess/commit/3c6a574ac25ea84aea2d1d60e025680d404c30ff))



# [3.8.0](https://github.com/kaisermann/svelte-preprocess/compare/v3.7.4...v3.8.0) (2020-06-05)


Expand Down
36 changes: 33 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ _Note: only for auto preprocessing_

### Global style

Add a `global` attribute to your `style` tag and instead of scoping the css, all of its content will be interpreted as global style.
Add a `global` attribute to your `style` tag and instead of scoping the CSS, all of its content will be interpreted as global style.

```html
<style global>
Expand All @@ -89,10 +89,38 @@ Add a `global` attribute to your `style` tag and instead of scoping the css, all
</style>
```

_Note<sup>1</sup>: needs postcss to be installed_
_Note<sup>1</sup>: needs PostCSS to be installed._

_Note<sup>2</sup>: if you're using it as a standalone processor, it works best if added to the end of the processors array._

_Note<sup>3</sup>: if you need to have some styles be scoped inside a global style tag, use `:local` in the same way you'd use `:global`._

### Global rule

Use a `:global` rule to only expose parts of the stylesheet:

```html
<style lang="scss">
.scoped-style {}

:global {
@import 'global-stylesheet.scss';

.global-style {
.global-child-style {}
}
}
</style>
```

Works best with nesting-enabled CSS preprocessors, but regular CSS selectors like `div :global .global1 .global2` are also supported.

_Note<sup>1</sup>: needs PostCSS to be installed._

_Note<sup>2</sup>: if you're using it as a standalone processor, it works best if added to the end of the processors array._

_Note<sup>3</sup>: wrapping `@keyframes` inside `:global {}` blocks is not supported. Use the [`-global-` name prefix for global keyframes](https://svelte.dev/docs#style)._

### Preprocessors

Current supported out-of-the-box preprocessors are `SCSS`, `Stylus`, `Less`, `Coffeescript`, `TypeScript`, `Pug`, `PostCSS`, `Babel`.
Expand Down Expand Up @@ -135,7 +163,9 @@ Current supported out-of-the-box preprocessors are `SCSS`, `Stylus`, `Less`, `Co
<!-- Or -->

<style type="text/stylus">
$color=reddivcolor: $color;
$color = red
div
color: $color
</style>
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "svelte-preprocess",
"version": "3.8.0",
"version": "3.9.0",
"license": "MIT",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
25 changes: 19 additions & 6 deletions src/autoProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Options,
Processed,
} from './types';
import { hasPostCssInstalled } from './modules/hasPostcssInstalled';

interface Transformers {
typescript?: TransformerOptions<Options.Typescript>;
Expand All @@ -26,9 +27,10 @@ interface Transformers {
postcss?: TransformerOptions<Options.Postcss>;
coffeescript?: TransformerOptions<Options.Coffeescript>;
pug?: TransformerOptions<Options.Pug>;
globalStyle?: TransformerOptions<Options.Typescript>;
globalStyle?: TransformerOptions;
globalRule?: TransformerOptions;
replace?: Options.Replace;
[languageName: string]: TransformerOptions<any>;
[languageName: string]: TransformerOptions;
}

type AutoPreprocessOptions = {
Expand All @@ -55,14 +57,15 @@ type AutoPreprocessOptions = {
coffeescript?: TransformerOptions<Options.Coffeescript>;
pug?: TransformerOptions<Options.Pug>;
globalStyle?: TransformerOptions<Options.Typescript>;
globalRule?: TransformerOptions<Options.Typescript>;
// workaround while we don't have this
// https://github.com/microsoft/TypeScript/issues/17867
[languageName: string]:
| string
| Promise<string>
| [string, string][]
| string[]
| TransformerOptions<any>;
| TransformerOptions;
};

const SVELTE_MAJOR_VERSION = +version[0];
Expand Down Expand Up @@ -259,13 +262,23 @@ export function autoPreprocess(
dependencies = concat(dependencies, transformed.dependencies);
}

if (attributes.global) {
const transformed = await runTransformer('globalStyle', null, {
if (await hasPostCssInstalled()) {
if (attributes.global) {
const transformed = await runTransformer('globalStyle', null, {
content: code,
map,
filename,
});

code = transformed.code;
map = transformed.map;
}

const transformed = await runTransformer('globalRule', null, {
content: code,
map,
filename,
});

code = transformed.code;
map = transformed.map;
}
Expand Down
16 changes: 16 additions & 0 deletions src/modules/globalifySelector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export function globalifySelector(selector: string) {
return selector
.trim()
.split(' ')
.filter(Boolean)
.map((selectorPart) => {
if (selectorPart.startsWith(':local')) {
return selectorPart.replace(/:local\((.+?)\)/g, '$1');
}
if (selectorPart.startsWith(':global')) {
return selectorPart;
}
return `:global(${selectorPart})`;
})
.join(' ');
}
17 changes: 17 additions & 0 deletions src/modules/hasPostcssInstalled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
let cachedResult: boolean;

export async function hasPostCssInstalled() {
if (cachedResult != null) {
return cachedResult;
}

let result = false;
try {
await import('postcss');
result = true;
} catch (e) {
result = false;
}

return (cachedResult = result);
}
11 changes: 11 additions & 0 deletions src/modules/importAny.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export async function importAny(...modules: string[]) {
try {
const mod = await modules.reduce(
(acc, moduleName) => acc.catch(() => import(moduleName)),
Promise.reject(),
);
return mod;
} catch (e) {
throw new Error(`Cannot find any of modules: ${modules}`);
}
}
13 changes: 13 additions & 0 deletions src/processors/globalRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { PreprocessorGroup } from '../types';

export default (): PreprocessorGroup => {
return {
async style({ content, filename }) {
const { default: transformer } = await import(
'../transformers/globalRule'
);

return transformer({ content, filename });
},
};
};
26 changes: 26 additions & 0 deletions src/transformers/globalRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import postcss from 'postcss';

import { Transformer } from '../types';
import { globalifySelector } from '../modules/globalifySelector';

const selectorPattern = /:global(?!\()/;

const globalifyRulePlugin = (root: any) => {
root.walkRules(selectorPattern, (rule: any) => {
const [beginning, ...rest] = rule.selector.split(selectorPattern);
rule.selector = [beginning, ...rest.map(globalifySelector)]
.map((str) => str.trim())
.join(' ')
.trim();
});
};

const transformer: Transformer<never> = async ({ content, filename }) => {
const { css, map: newMap } = await postcss()
.use(globalifyRulePlugin)
.process(content, { from: filename, map: true });

return { code: css, map: newMap };
};

export default transformer;
18 changes: 3 additions & 15 deletions src/transformers/globalStyle.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import postcss from 'postcss';

import { Transformer } from '../types';
import { globalifySelector } from '../modules/globalifySelector';

const globalifyPlugin = (root: any) => {
root.walkAtRules(/keyframes$/, (atrule: any) => {
if (!atrule.params.startsWith('-global-')) {
atrule.params = '-global-' + atrule.params;
atrule.params = `-global-${atrule.params}`;
}
});

Expand All @@ -14,20 +15,7 @@ const globalifyPlugin = (root: any) => {
return;
}

rule.selectors = rule.selectors.map((selector: string) => {
return selector
.split(' ')
.map((selectorPart) => {
if (selectorPart.startsWith(':local')) {
return selectorPart.replace(/:local\((.+?)\)/g, '$1');
}
if (selectorPart.startsWith(':global')) {
return selectorPart;
}
return `:global(${selectorPart})`;
})
.join(' ');
});
rule.selectors = rule.selectors.map(globalifySelector);
});
};

Expand Down
3 changes: 2 additions & 1 deletion src/transformers/scss.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Result } from 'sass';

import { importAny, getIncludePaths } from '../utils';
import { getIncludePaths } from '../utils';
import { Transformer, Processed, Options } from '../types';
import { importAny } from '../modules/importAny';

let sass: Options.Sass['implementation'];

Expand Down
2 changes: 1 addition & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export type Transformer<T> = (
args: TransformerArgs<T>,
) => Processed | Promise<Processed>;

export type TransformerOptions<T> =
export type TransformerOptions<T = any> =
| boolean
| Record<string, any>
| Transformer<T>;
14 changes: 1 addition & 13 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,4 @@ export const runTransformer = async (
`Error transforming '${name}'.\n\nMessage:\n${e.message}\n\nStack:\n${e.stack}`,
);
}
};

export const importAny = async (...modules: string[]) => {
try {
const mod = await modules.reduce(
(acc, moduleName) => acc.catch(() => import(moduleName)),
Promise.reject(),
);
return mod;
} catch (e) {
throw new Error(`Cannot find any of modules: ${modules}`);
}
};
};
Loading