diff --git a/demo/App.tsx b/demo/App.tsx
index e937e817..5d3b97ee 100644
--- a/demo/App.tsx
+++ b/demo/App.tsx
@@ -38,6 +38,7 @@ function App() {
This text is styled by global configured SASS
This text is styled by imported SASS
+ This text is styled by imported SASS using a shared mixin and variable
This text is styled by Tailwind CSS
diff --git a/demo/__tests__/transform.test.tsx b/demo/__tests__/transform.test.tsx
index f0e63ee8..92bf2aeb 100644
--- a/demo/__tests__/transform.test.tsx
+++ b/demo/__tests__/transform.test.tsx
@@ -7,7 +7,7 @@ describe('transform', () => {
render();
// TODO: To refactor this test. It frequently need to be updated.
expect(document.body.outerHTML).toMatchInlineSnapshot(
- `""`,
+ `""`,
);
});
});
diff --git a/demo/assets/_scss/sharedSassResources/color-vars.scss b/demo/assets/_scss/sharedSassResources/color-vars.scss
new file mode 100644
index 00000000..2930a004
--- /dev/null
+++ b/demo/assets/_scss/sharedSassResources/color-vars.scss
@@ -0,0 +1 @@
+$limeGreen: #32cd32;
diff --git a/demo/assets/_scss/sharedSassResources/mixins.scss b/demo/assets/_scss/sharedSassResources/mixins.scss
new file mode 100644
index 00000000..7911fa62
--- /dev/null
+++ b/demo/assets/_scss/sharedSassResources/mixins.scss
@@ -0,0 +1,5 @@
+@mixin desktop {
+ @media only screen and (min-width: 900px) {
+ @content;
+ }
+}
diff --git a/demo/assets/_scss/style.scss b/demo/assets/_scss/style.scss
index 0db3cdaa..83089606 100644
--- a/demo/assets/_scss/style.scss
+++ b/demo/assets/_scss/style.scss
@@ -8,4 +8,12 @@ header {
.imported-sass {
color: pink;
}
+
+ .imported-sass-shared-var {
+ color: purple;
+
+ @include desktop {
+ color: $limeGreen;
+ }
+ }
}
diff --git a/demo/setupTests.js b/demo/setupTests.js
index f1bb8d7e..e243a404 100644
--- a/demo/setupTests.js
+++ b/demo/setupTests.js
@@ -7,6 +7,10 @@ jestPreviewConfigure({
publicFolder: 'demo/public',
autoPreview: true,
sassLoadPaths: ['demo/assets/_scss/loadPathsExample'],
+ sharedSassResources: [
+ 'demo/assets/_scss/sharedSassResources/color-vars.scss',
+ 'demo/assets/_scss/sharedSassResources/mixins.scss',
+ ],
});
window.matchMedia = (query) => ({
diff --git a/examples/angular/src/app/app.component.spec.ts b/examples/angular/src/app/app.component.spec.ts
index a3d563fe..f74cc381 100644
--- a/examples/angular/src/app/app.component.spec.ts
+++ b/examples/angular/src/app/app.component.spec.ts
@@ -7,7 +7,7 @@ styleUrls.forEach((styleUrl) => import(styleUrl));
describe('App', () => {
it('should work as expected', async () => {
const user = userEvent.setup();
- await render(AppComponent);
+ const { detectChanges } = await render(AppComponent);
await user.click(screen.getByTestId('increase'));
await user.click(screen.getByTestId('increase'));
@@ -16,6 +16,8 @@ describe('App', () => {
await user.click(screen.getByTestId('increase'));
await user.click(screen.getByTestId('increase'));
+ detectChanges();
+
// Open http://localhost:3336 to see preview
// Require to run `jest-preview` server before
preview.debug();
diff --git a/examples/angular/src/app/counter/counter.component.spec.ts b/examples/angular/src/app/counter/counter.component.spec.ts
index 7b3acc87..b95b7f85 100644
--- a/examples/angular/src/app/counter/counter.component.spec.ts
+++ b/examples/angular/src/app/counter/counter.component.spec.ts
@@ -1,13 +1,13 @@
import { render, screen } from '@testing-library/angular';
import userEvent from '@testing-library/user-event';
-// import preview from 'jest-preview';
+import preview from 'jest-preview';
import { CounterComponent } from './counter.component';
import './counter.component.css';
describe(CounterComponent.name, () => {
it('should work as expected', async () => {
const user = userEvent.setup();
- await render(CounterComponent);
+ const { detectChanges } = await render(CounterComponent);
await user.click(screen.getByTestId('increase'));
await user.click(screen.getByTestId('increase'));
@@ -16,9 +16,11 @@ describe(CounterComponent.name, () => {
await user.click(screen.getByTestId('increase'));
await user.click(screen.getByTestId('increase'));
+ detectChanges();
+
// Open http://localhost:3336 to see preview
// Require to run `jest-preview` server before
- // preview.debug();
+ preview.debug();
expect(screen.getByTestId('count')).toContainHTML('6');
});
diff --git a/src/configure.ts b/src/configure.ts
index ee89a66b..82088610 100644
--- a/src/configure.ts
+++ b/src/configure.ts
@@ -1,7 +1,7 @@
import path from 'path';
import fs from 'fs';
import chalk from 'chalk';
-import { CACHE_FOLDER, SASS_LOAD_PATHS_CONFIG } from './constants';
+import { CACHE_FOLDER, SASS_LOAD_PATHS_CONFIG, SASS_SHARED_RESOURCES_CONCAT } from './constants';
import { createCacheFolderIfNeeded } from './utils';
import { debug } from './preview';
@@ -13,6 +13,7 @@ interface JestPreviewConfigOptions {
autoPreview?: boolean;
publicFolder?: string;
sassLoadPaths?: string[];
+ sharedSassResources?: string[];
}
export function jestPreviewConfigure(
@@ -21,6 +22,7 @@ export function jestPreviewConfigure(
autoPreview = false,
publicFolder,
sassLoadPaths,
+ sharedSassResources,
}: JestPreviewConfigOptions = {
autoPreview: false,
sassLoadPaths: [],
@@ -72,6 +74,24 @@ export function jestPreviewConfigure(
},
);
}
+
+ if (sharedSassResources && sharedSassResources.length > 0) {
+ createCacheFolderIfNeeded();
+
+ const resourceFileContents = sharedSassResources.map((sassResourceFile) => {
+ const filenameComment = `// ${sassResourceFile}`;
+ const fileContents = fs.readFileSync(sassResourceFile, "utf-8");
+
+ return `${filenameComment}\n${fileContents}`;
+ });
+
+ const resourceFileContentsConcat = resourceFileContents.join('\n\n');
+
+ fs.writeFileSync(
+ path.join(CACHE_FOLDER, SASS_SHARED_RESOURCES_CONCAT),
+ resourceFileContentsConcat,
+ );
+ }
}
// Omit only, skip, todo, concurrent, each. Couldn't use Omit. Just redeclare for simplicity
diff --git a/src/constants.ts b/src/constants.ts
index dae98cb0..558ee81a 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -1,2 +1,4 @@
-export const CACHE_FOLDER = './node_modules/.cache/jest-preview';
+export const CACHE_SUB_FOLDER = '.cache/jest-preview';
+export const CACHE_FOLDER = `./node_modules/${CACHE_SUB_FOLDER}`;
export const SASS_LOAD_PATHS_CONFIG = 'cache-sass-load-paths.config';
+export const SASS_SHARED_RESOURCES_CONCAT = '_sass-resources-concat.scss';
diff --git a/src/transform.ts b/src/transform.ts
index aaecf6dc..9dca4a8b 100644
--- a/src/transform.ts
+++ b/src/transform.ts
@@ -6,7 +6,7 @@ import { pathToFileURL } from 'url';
import camelcase from 'camelcase';
import slash from 'slash';
import { transform } from '@svgr/core';
-import { CACHE_FOLDER, SASS_LOAD_PATHS_CONFIG } from './constants';
+import { CACHE_FOLDER, CACHE_SUB_FOLDER, SASS_LOAD_PATHS_CONFIG, SASS_SHARED_RESOURCES_CONCAT } from './constants';
import { createCacheFolderIfNeeded } from './utils';
// https://github.com/vitejs/vite/blob/c29613013ca1c6d9c77b97e2253ed1f07e40a544/packages/vite/src/node/plugins/css.ts#L97-L98
@@ -397,6 +397,25 @@ function processSass(filename: string): string {
sassLoadPathsConfig = [];
}
+ // Workaround for ?bug? with sass.compileString that the location of the source file is not automatically included in load paths
+ sassLoadPathsConfig.push(path.parse(filename).dir);
+
+ const sharedSassResourcesPath = path.join(CACHE_FOLDER, SASS_SHARED_RESOURCES_CONCAT);
+
+ let sassPrefixedWithSharedResources = '';
+ if (fs.existsSync(sharedSassResourcesPath)) {
+ // Transform the filename for use in "use" statement
+ const sharedResourcesFilenameForUse = SASS_SHARED_RESOURCES_CONCAT.replace(/^_|\.scss$/g, '');
+ // Prepend a "use" statement so shared sass resources are accessible from all source files
+ const useSharedStatement = `@use '~${CACHE_SUB_FOLDER}/${sharedResourcesFilenameForUse}' as *;`;
+ const sassContent = fs.readFileSync(filename, 'utf8');
+ sassPrefixedWithSharedResources = `${useSharedStatement}\n\n${sassContent}`;
+ }
+
+ return buildCssResult(sass, sassLoadPathsConfig, sassPrefixedWithSharedResources, filename);
+}
+
+function buildCssResult(sass: any, sassLoadPathsConfig: string[], sassPrefixedWithSharedResources: string, filename: string): string {
let cssResult;
// An importer that redirects relative URLs starting with "~" to `node_modules`
@@ -412,17 +431,25 @@ function processSass(filename: string): string {
);
};
- if (sass.compile) {
- cssResult = sass.compile(filename, {
- loadPaths: sassLoadPathsConfig,
- importers: [
- {
- findFileUrl(url: string) {
- return tildeImporter(url);
- },
+ if (sassPrefixedWithSharedResources && !sass.compileString) {
+ console.warn("WARNING: Config specifies sharedSassResources, but your version of Sass doesn't support it - consider updating to v1.45.0 or higher.");
+ }
+
+ const compileOptions = {
+ loadPaths: sassLoadPathsConfig,
+ importers: [
+ {
+ findFileUrl(url: string) {
+ return tildeImporter(url);
},
- ],
- }).css;
+ },
+ ],
+ };
+
+ if (sassPrefixedWithSharedResources && sass.compileString) {
+ cssResult = sass.compileString(sassPrefixedWithSharedResources, compileOptions).css;
+ } else if (sass.compile) {
+ cssResult = sass.compile(filename, compileOptions).css;
}
// Because sass.compile is only introduced since sass version 1.45.0
// For older versions, we have to use the legacy API: renderSync
diff --git a/website/docs/api/jestPreviewConfigure.md b/website/docs/api/jestPreviewConfigure.md
index 40bcb106..a4017841 100644
--- a/website/docs/api/jestPreviewConfigure.md
+++ b/website/docs/api/jestPreviewConfigure.md
@@ -36,6 +36,12 @@ jestPreviewConfigure({
});
```
+## sharedSassResources: string[]
+
+Default: `undefined`
+
+Optional list of paths to SASS files that define shared resources (e.g. variables, mixins, etc). The paths are relative to the root of the project. Requires SASS v1.45.0 or higher.
+
## publicFolder: string
Default: `undefined`.