From 46722bac993308d8e4f1bb3d0b3086b802013d3d Mon Sep 17 00:00:00 2001 From: illright Date: Wed, 3 Jun 2020 16:06:11 +0300 Subject: [PATCH 01/10] feat: add the @global {} rule support --- src/autoProcess.ts | 11 ++++++++ src/processors/globalRule.ts | 13 +++++++++ src/transformers/globalRule.ts | 28 +++++++++++++++++++ src/transformers/globalStyle.ts | 2 +- test/transformers/globalRule.test.ts | 42 ++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/processors/globalRule.ts create mode 100644 src/transformers/globalRule.ts create mode 100644 test/transformers/globalRule.test.ts diff --git a/src/autoProcess.ts b/src/autoProcess.ts index 62fcbd6b..2f822f01 100644 --- a/src/autoProcess.ts +++ b/src/autoProcess.ts @@ -27,6 +27,7 @@ interface Transformers { coffeescript?: TransformerOptions; pug?: TransformerOptions; globalStyle?: TransformerOptions; + globalRule?: TransformerOptions; replace?: Options.Replace; [languageName: string]: TransformerOptions; } @@ -55,6 +56,7 @@ type AutoPreprocessOptions = { coffeescript?: TransformerOptions; pug?: TransformerOptions; globalStyle?: TransformerOptions; + globalRule?: TransformerOptions; // workaround while we don't have this // https://github.com/microsoft/TypeScript/issues/17867 [languageName: string]: @@ -270,6 +272,15 @@ export function autoPreprocess( map = transformed.map; } + const transformed = await runTransformer('globalRule', null, { + content: code, + map, + filename, + }); + + code = transformed.code; + map = transformed.map; + return { code, map, dependencies }; }, }; diff --git a/src/processors/globalRule.ts b/src/processors/globalRule.ts new file mode 100644 index 00000000..1a7a5fe7 --- /dev/null +++ b/src/processors/globalRule.ts @@ -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 }); + }, + }; +}; diff --git a/src/transformers/globalRule.ts b/src/transformers/globalRule.ts new file mode 100644 index 00000000..27af4377 --- /dev/null +++ b/src/transformers/globalRule.ts @@ -0,0 +1,28 @@ +import postcss from 'postcss'; + +import { Transformer } from '../types'; +import { globalifyPlugin } from './globalStyle'; + +const globalifyRulePlugin = (root: any) => { + root.walkAtRules(/^global$/, (atrule: any) => { + globalifyPlugin(atrule); + let after = atrule; + + atrule.each(function (child: any) { + after.after(child); + after = child; + }); + + atrule.remove(); + }); +}; + +const transformer: Transformer = 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; diff --git a/src/transformers/globalStyle.ts b/src/transformers/globalStyle.ts index ee01ecf6..9d03aa2b 100644 --- a/src/transformers/globalStyle.ts +++ b/src/transformers/globalStyle.ts @@ -2,7 +2,7 @@ import postcss from 'postcss'; import { Transformer } from '../types'; -const globalifyPlugin = (root: any) => { +export const globalifyPlugin = (root: any) => { root.walkAtRules(/keyframes$/, (atrule: any) => { if (!atrule.params.startsWith('-global-')) { atrule.params = '-global-' + atrule.params; diff --git a/test/transformers/globalRule.test.ts b/test/transformers/globalRule.test.ts new file mode 100644 index 00000000..aa21fe5b --- /dev/null +++ b/test/transformers/globalRule.test.ts @@ -0,0 +1,42 @@ +import autoProcess from '../../src'; +import { preprocess } from '../utils'; + +describe('transformer - globalRule', () => { + it('wraps selector in :global(...) modifier', async () => { + const template = ``; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain( + `:global(div){color:red}:global(.test){}`, + ); + }); + + it('wraps selector in :global(...) modifier only inside the rule', async () => { + const template = ``; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain( + `:global(div){color:red}.test{}`, + ); + }); + + it('wraps selector in :global(...) only if needed', async () => { + const template = ``; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain( + `:global(.test){}:global(.foo){}`, + ); + }); + + it("prefixes @keyframes names with '-global-' only if needed", async () => { + const template = ``; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain( + `@keyframes -global-a {from{} to{}}@keyframes -global-b {from{} to{}}`, + ); + }); +}); From 399482b6015ad69ca5916575a352ff7af6559f8a Mon Sep 17 00:00:00 2001 From: illright Date: Wed, 3 Jun 2020 16:13:25 +0300 Subject: [PATCH 02/10] docs: fix whitespace in the Stylus example --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a465b36a..6b29515a 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,9 @@ Current supported out-of-the-box preprocessors are `SCSS`, `Stylus`, `Less`, `Co ``` From 10511da543cbe41936a64788140eaf6a841d5326 Mon Sep 17 00:00:00 2001 From: illright Date: Wed, 3 Jun 2020 16:16:57 +0300 Subject: [PATCH 03/10] docs: document the addition and add a notice about `:local` --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 6b29515a..55bc16e2 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,30 @@ _Note1: needs postcss to be installed_ _Note2: if you're using it as a standalone processor, it works best if added to the end of the processors array._ +_Note3: 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 + +``` + +_Note1: needs postcss to be installed_ + +_Note2: if you're using it as a standalone processor, it works best if added to the end of the processors array._ + ### Preprocessors Current supported out-of-the-box preprocessors are `SCSS`, `Stylus`, `Less`, `Coffeescript`, `TypeScript`, `Pug`, `PostCSS`, `Babel`. From eeb1f4a2c36cd28871fdfb89fab51634724453f8 Mon Sep 17 00:00:00 2001 From: illright Date: Fri, 5 Jun 2020 11:50:52 +0300 Subject: [PATCH 04/10] test: fix a typo in the test message --- test/transformers/scss.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/transformers/scss.test.ts b/test/transformers/scss.test.ts index dbbac95d..cbc19bd1 100644 --- a/test/transformers/scss.test.ts +++ b/test/transformers/scss.test.ts @@ -30,7 +30,7 @@ const implementation: Options.Sass['implementation'] = { }; describe('transformer - scss', () => { - it('should prepend scss content via `data` option property - via defaul async render', async () => { + it('should prepend scss content via `data` option property - via default async render', async () => { const template = ``; const opts = getAutoPreprocess({ scss: { From 3c6a574ac25ea84aea2d1d60e025680d404c30ff Mon Sep 17 00:00:00 2001 From: illright Date: Fri, 5 Jun 2020 11:52:12 +0300 Subject: [PATCH 05/10] feat: replace the @global for :global for CSS modules compliance --- src/transformers/globalRule.ts | 18 +++----- src/transformers/globalStyle.ts | 33 +++++++------- test/transformers/globalRule.test.ts | 66 ++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 40 deletions(-) diff --git a/src/transformers/globalRule.ts b/src/transformers/globalRule.ts index 27af4377..3a5b689b 100644 --- a/src/transformers/globalRule.ts +++ b/src/transformers/globalRule.ts @@ -1,19 +1,15 @@ import postcss from 'postcss'; import { Transformer } from '../types'; -import { globalifyPlugin } from './globalStyle'; +import { wrapSelectorInGlobal } from './globalStyle'; const globalifyRulePlugin = (root: any) => { - root.walkAtRules(/^global$/, (atrule: any) => { - globalifyPlugin(atrule); - let after = atrule; - - atrule.each(function (child: any) { - after.after(child); - after = child; - }); - - atrule.remove(); + root.walkRules(/:global(?!\()/, (rule: any) => { + const [beginning, ...rest] = rule.selector.split(/:global(?!\()/); + rule.selector = ( + beginning.trim() + ' ' + + rest.filter((x: string) => !!x).map(wrapSelectorInGlobal).join(' ') + ).trim(); }); }; diff --git a/src/transformers/globalStyle.ts b/src/transformers/globalStyle.ts index 9d03aa2b..fce02330 100644 --- a/src/transformers/globalStyle.ts +++ b/src/transformers/globalStyle.ts @@ -2,7 +2,23 @@ import postcss from 'postcss'; import { Transformer } from '../types'; -export const globalifyPlugin = (root: any) => { +export const wrapSelectorInGlobal = (selector: string) => { + return selector + .trim() + .split(' ') + .map((selectorPart) => { + if (selectorPart.startsWith(':local')) { + return selectorPart.replace(/:local\((.+?)\)/g, '$1'); + } + if (selectorPart.startsWith(':global')) { + return selectorPart; + } + return `:global(${selectorPart})`; + }) + .join(' '); +}; + +const globalifyPlugin = (root: any) => { root.walkAtRules(/keyframes$/, (atrule: any) => { if (!atrule.params.startsWith('-global-')) { atrule.params = '-global-' + atrule.params; @@ -14,20 +30,7 @@ export 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(wrapSelectorInGlobal); }); }; diff --git a/test/transformers/globalRule.test.ts b/test/transformers/globalRule.test.ts index aa21fe5b..e0f63ae4 100644 --- a/test/transformers/globalRule.test.ts +++ b/test/transformers/globalRule.test.ts @@ -3,7 +3,7 @@ import { preprocess } from '../utils'; describe('transformer - globalRule', () => { it('wraps selector in :global(...) modifier', async () => { - const template = ``; + const template = ``; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); expect(preprocessed.toString()).toContain( @@ -11,32 +11,70 @@ describe('transformer - globalRule', () => { ); }); - it('wraps selector in :global(...) modifier only inside the rule', async () => { - const template = ``; + it('wraps selector in :global(...) only if needed', async () => { + const template = ``; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); expect(preprocessed.toString()).toContain( - `:global(div){color:red}.test{}`, + `:global(.test){}:global(.foo){}`, ); }); - it('wraps selector in :global(...) only if needed', async () => { - const template = ``; + it('wraps selector in :global(...) on multiple levels', async () => { + const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); - expect(preprocessed.toString()).toContain( - `:global(.test){}:global(.foo){}`, + expect(preprocessed.toString()).toMatch( + // either be :global(div .cls){} + // or :global(div) :global(.cls){} + /(:global\(div .cls\)\{\}|:global\(div\) :global\(\.cls\)\{\})/, ); }); - it("prefixes @keyframes names with '-global-' only if needed", async () => { - const template = ``; + it('wraps selector in :global(...) on multiple levels when in the middle', async () => { + const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); - expect(preprocessed.toString()).toContain( - `@keyframes -global-a {from{} to{}}@keyframes -global-b {from{} to{}}`, + expect(preprocessed.toString()).toMatch( + // either be div :global(span .cls) {} + // or div :global(span) :global(.cls) {} + /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/, + ); + }); + + it('does not break when at the end', async () => { + const template = ''; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain('span{}'); + }); + + it('works with collapsed nesting several times', async () => { + const template = ''; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toMatch( + // either be div :global(span .cls) {} + // or div :global(span) :global(.cls) {} + /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/, + ); + }); + + it('does not interfere with the :global(...) syntax', async () => { + const template = ''; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain('div :global(span){}'); + }); + + it('allows mixing with the :global(...) syntax', async () => { + const template = ''; + const opts = autoProcess(); + const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toMatch( + // either be div :global(span .cls) {} + // or div :global(span) :global(.cls) {} + /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/, ); }); }); From 89515d000eb2507c7d68debe45f0d2342d29973e Mon Sep 17 00:00:00 2001 From: illright Date: Fri, 5 Jun 2020 18:12:14 +0300 Subject: [PATCH 06/10] docs: update docs to reflect the change, fix mistakes --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 55bc16e2..a4148a8e 100644 --- a/README.md +++ b/README.md @@ -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 ``` -_Note1: needs postcss to be installed_ +_Note1: needs PostCSS to be installed._ _Note2: if you're using it as a standalone processor, it works best if added to the end of the processors array._ @@ -97,14 +97,14 @@ _Note3: if you need to have some styles be scoped inside a global sty ### Global rule -Use a `@global` rule to only expose parts of the stylesheet: +Use a `:global` rule to only expose parts of the stylesheet: ```html ``` -_Note1: needs postcss to be installed_ +Works best with nesting-enabled CSS preprocessors, but regular CSS selectors like `div :global .global1 .global2` are also supported. + +_Note1: needs PostCSS to be installed._ _Note2: if you're using it as a standalone processor, it works best if added to the end of the processors array._ +_Note3: 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`. From 6c992406090c245592f03668094adfb19a82cab7 Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Fri, 5 Jun 2020 17:13:35 -0300 Subject: [PATCH 07/10] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20move=20things?= =?UTF-8?q?=20a=20bit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/globalifySelector.ts | 16 ++++++++++++++++ src/transformers/globalRule.ts | 16 +++++++++------- src/transformers/globalStyle.ts | 21 +++------------------ test/transformers/globalRule.test.ts | 16 ++++++++++++---- 4 files changed, 40 insertions(+), 29 deletions(-) create mode 100644 src/modules/globalifySelector.ts diff --git a/src/modules/globalifySelector.ts b/src/modules/globalifySelector.ts new file mode 100644 index 00000000..c3a88c37 --- /dev/null +++ b/src/modules/globalifySelector.ts @@ -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(' '); +} diff --git a/src/transformers/globalRule.ts b/src/transformers/globalRule.ts index 3a5b689b..4145e6fd 100644 --- a/src/transformers/globalRule.ts +++ b/src/transformers/globalRule.ts @@ -1,15 +1,17 @@ import postcss from 'postcss'; import { Transformer } from '../types'; -import { wrapSelectorInGlobal } from './globalStyle'; +import { globalifySelector } from '../modules/globalifySelector'; + +const selectorPattern = /:global(?!\()/; const globalifyRulePlugin = (root: any) => { - root.walkRules(/:global(?!\()/, (rule: any) => { - const [beginning, ...rest] = rule.selector.split(/:global(?!\()/); - rule.selector = ( - beginning.trim() + ' ' - + rest.filter((x: string) => !!x).map(wrapSelectorInGlobal).join(' ') - ).trim(); + root.walkRules(selectorPattern, (rule: any) => { + const [beginning, ...rest] = rule.selector.split(selectorPattern); + rule.selector = [beginning, ...rest.map(globalifySelector)] + .map((str) => str.trim()) + .join(' ') + .trim(); }); }; diff --git a/src/transformers/globalStyle.ts b/src/transformers/globalStyle.ts index fce02330..8468389c 100644 --- a/src/transformers/globalStyle.ts +++ b/src/transformers/globalStyle.ts @@ -1,27 +1,12 @@ import postcss from 'postcss'; import { Transformer } from '../types'; - -export const wrapSelectorInGlobal = (selector: string) => { - return selector - .trim() - .split(' ') - .map((selectorPart) => { - if (selectorPart.startsWith(':local')) { - return selectorPart.replace(/:local\((.+?)\)/g, '$1'); - } - if (selectorPart.startsWith(':global')) { - return selectorPart; - } - return `:global(${selectorPart})`; - }) - .join(' '); -}; +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}`; } }); @@ -30,7 +15,7 @@ const globalifyPlugin = (root: any) => { return; } - rule.selectors = rule.selectors.map(wrapSelectorInGlobal); + rule.selectors = rule.selectors.map(globalifySelector); }); }; diff --git a/test/transformers/globalRule.test.ts b/test/transformers/globalRule.test.ts index e0f63ae4..509148a9 100644 --- a/test/transformers/globalRule.test.ts +++ b/test/transformers/globalRule.test.ts @@ -6,6 +6,7 @@ describe('transformer - globalRule', () => { const template = ``; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain( `:global(div){color:red}:global(.test){}`, ); @@ -15,6 +16,7 @@ describe('transformer - globalRule', () => { const template = ``; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain( `:global(.test){}:global(.foo){}`, ); @@ -24,6 +26,7 @@ describe('transformer - globalRule', () => { const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toMatch( // either be :global(div .cls){} // or :global(div) :global(.cls){} @@ -32,13 +35,14 @@ describe('transformer - globalRule', () => { }); it('wraps selector in :global(...) on multiple levels when in the middle', async () => { - const template = ''; + const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toMatch( - // either be div :global(span .cls) {} - // or div :global(span) :global(.cls) {} - /div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/, + // either be div div :global(span .cls) {} + // or div div :global(span) :global(.cls) {} + /div div (:global\(span .cls\)\{\}|:global\(span\) :global\(\.cls\)\{\})/, ); }); @@ -46,6 +50,7 @@ describe('transformer - globalRule', () => { const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain('span{}'); }); @@ -53,6 +58,7 @@ describe('transformer - globalRule', () => { const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toMatch( // either be div :global(span .cls) {} // or div :global(span) :global(.cls) {} @@ -64,6 +70,7 @@ describe('transformer - globalRule', () => { const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toContain('div :global(span){}'); }); @@ -71,6 +78,7 @@ describe('transformer - globalRule', () => { const template = ''; const opts = autoProcess(); const preprocessed = await preprocess(template, opts); + expect(preprocessed.toString()).toMatch( // either be div :global(span .cls) {} // or div :global(span) :global(.cls) {} From 62947507064271d1cec796d3e0a7801633b875a8 Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Fri, 5 Jun 2020 17:42:29 -0300 Subject: [PATCH 08/10] =?UTF-8?q?fix:=20=F0=9F=90=9B=20run=20globalRule=20?= =?UTF-8?q?only=20if=20postcss=20is=20installed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/autoProcess.ts | 26 ++++++++++++++------------ src/modules/hasPostcssInstalled.ts | 17 +++++++++++++++++ src/modules/importAny.ts | 11 +++++++++++ src/transformers/scss.ts | 3 ++- src/utils.ts | 14 +------------- test/transformers/globalRule.test.ts | 7 +++++++ test/transformers/scss.test.ts | 8 ++++---- test/utils.test.ts | 3 ++- 8 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 src/modules/hasPostcssInstalled.ts create mode 100644 src/modules/importAny.ts diff --git a/src/autoProcess.ts b/src/autoProcess.ts index 2f822f01..794807a1 100644 --- a/src/autoProcess.ts +++ b/src/autoProcess.ts @@ -16,6 +16,7 @@ import { Options, Processed, } from './types'; +import { hasPostCssInstalled } from './modules/hasPostcssInstalled'; interface Transformers { typescript?: TransformerOptions; @@ -261,26 +262,27 @@ 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; } - const transformed = await runTransformer('globalRule', null, { - content: code, - map, - filename, - }); - - code = transformed.code; - map = transformed.map; - return { code, map, dependencies }; }, }; diff --git a/src/modules/hasPostcssInstalled.ts b/src/modules/hasPostcssInstalled.ts new file mode 100644 index 00000000..a8fdc61a --- /dev/null +++ b/src/modules/hasPostcssInstalled.ts @@ -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); +} diff --git a/src/modules/importAny.ts b/src/modules/importAny.ts new file mode 100644 index 00000000..fee66ebf --- /dev/null +++ b/src/modules/importAny.ts @@ -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}`); + } +} diff --git a/src/transformers/scss.ts b/src/transformers/scss.ts index 78456ce0..d72dff13 100644 --- a/src/transformers/scss.ts +++ b/src/transformers/scss.ts @@ -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']; diff --git a/src/utils.ts b/src/utils.ts index 0b7c6ab5..c54a3ce1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -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}`); - } -}; +}; \ No newline at end of file diff --git a/test/transformers/globalRule.test.ts b/test/transformers/globalRule.test.ts index 509148a9..e01b86ec 100644 --- a/test/transformers/globalRule.test.ts +++ b/test/transformers/globalRule.test.ts @@ -2,6 +2,13 @@ import autoProcess from '../../src'; import { preprocess } from '../utils'; describe('transformer - globalRule', () => { + it('does nothing if postcss is not installed', async () => { + const template = ``; + const opts = autoProcess(); + + expect(async () => await preprocess(template, opts)).not.toThrow(); + }); + it('wraps selector in :global(...) modifier', async () => { const template = ``; const opts = autoProcess(); diff --git a/test/transformers/scss.test.ts b/test/transformers/scss.test.ts index cbc19bd1..b04108a2 100644 --- a/test/transformers/scss.test.ts +++ b/test/transformers/scss.test.ts @@ -7,7 +7,7 @@ import { Options } from '../../src/types'; const implementation: Options.Sass['implementation'] = { render(options, callback) { callback(null, { - css: Buffer.from('Foo'), + css: Buffer.from('div#red{color:red}'), stats: { entry: 'data', start: 0, @@ -18,7 +18,7 @@ const implementation: Options.Sass['implementation'] = { }); }, renderSync: () => ({ - css: Buffer.from('Bar'), + css: Buffer.from('div#green{color:green}'), stats: { entry: 'data', start: 0, @@ -58,7 +58,7 @@ describe('transformer - scss', () => { }, }); const preprocessed = await preprocess(template, opts); - expect(preprocessed.toString()).toContain('Foo'); + expect(preprocessed.toString()).toContain('div#red{color:red}'); }); it('should prepend scss content via `data` option property - via renderSync', async () => { @@ -95,6 +95,6 @@ describe('transformer - scss', () => { }, }); const preprocessed = await preprocess(template, opts); - expect(preprocessed.toString()).toContain('Bar'); + expect(preprocessed.toString()).toContain('div#green{color:green}'); }); }); diff --git a/test/utils.test.ts b/test/utils.test.ts index 5ffe23b1..ce1160d6 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,6 +1,7 @@ import { resolve } from 'path'; -import { importAny, getIncludePaths } from '../src/utils'; +import { getIncludePaths } from '../src/utils'; +import { importAny } from '../src/modules/importAny'; describe('utils - importAny', () => { it('should throw error when none exist', () => { From 72393d215a3078271bd307748f30823acbd4522e Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Fri, 5 Jun 2020 17:46:54 -0300 Subject: [PATCH 09/10] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20simplify=20tra?= =?UTF-8?q?nsformerOptions=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/autoProcess.ts | 8 ++++---- src/types/index.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/autoProcess.ts b/src/autoProcess.ts index 794807a1..94d66956 100644 --- a/src/autoProcess.ts +++ b/src/autoProcess.ts @@ -27,10 +27,10 @@ interface Transformers { postcss?: TransformerOptions; coffeescript?: TransformerOptions; pug?: TransformerOptions; - globalStyle?: TransformerOptions; - globalRule?: TransformerOptions; + globalStyle?: TransformerOptions; + globalRule?: TransformerOptions; replace?: Options.Replace; - [languageName: string]: TransformerOptions; + [languageName: string]: TransformerOptions; } type AutoPreprocessOptions = { @@ -65,7 +65,7 @@ type AutoPreprocessOptions = { | Promise | [string, string][] | string[] - | TransformerOptions; + | TransformerOptions; }; const SVELTE_MAJOR_VERSION = +version[0]; diff --git a/src/types/index.ts b/src/types/index.ts index 9fad0b75..8895280c 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -33,7 +33,7 @@ export type Transformer = ( args: TransformerArgs, ) => Processed | Promise; -export type TransformerOptions = +export type TransformerOptions = | boolean | Record | Transformer; From 2ae68a0bbea89da16459b7ef2fa5d102f59d0f3f Mon Sep 17 00:00:00 2001 From: Christian Kaisermann Date: Fri, 5 Jun 2020 17:50:36 -0300 Subject: [PATCH 10/10] chore(release): v3.9.0 :tada: --- CHANGELOG.md | 16 ++++++++++++++++ package.json | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 497e9d31..ecde6c90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/package.json b/package.json index 1f3569ee..67278771 100644 --- a/package.json +++ b/package.json @@ -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",